Skip to content

Commit 4885d16

Browse files
authored
Merge pull request #4262 from magento-tsg-csl3/2.2-develop-pr30
[TSG-CSL3] For 2.2 (pr30)
2 parents 8a9639e + 334b1a9 commit 4885d16

File tree

16 files changed

+299
-174
lines changed

16 files changed

+299
-174
lines changed

app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd">
1111
<actionGroup name="LoginAsAdmin">
1212
<arguments>
13-
<argument name="adminUser" defaultValue="_ENV"/>
13+
<argument name="adminUser" defaultValue="DefaultAdminUser"/>
1414
</arguments>
1515
<amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin"/>
16-
<fillField selector="{{AdminLoginFormSection.username}}" userInput="{{adminUser.MAGENTO_ADMIN_USERNAME}}" stepKey="fillUsername"/>
17-
<fillField selector="{{AdminLoginFormSection.password}}" userInput="{{adminUser.MAGENTO_ADMIN_PASSWORD}}" stepKey="fillPassword"/>
16+
<fillField selector="{{AdminLoginFormSection.username}}" userInput="{{adminUser.username}}" stepKey="fillUsername"/>
17+
<fillField selector="{{AdminLoginFormSection.password}}" userInput="{{adminUser.password}}" stepKey="fillPassword"/>
1818
<click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/>
1919
<closeAdminNotification stepKey="closeAdminNotification"/>
2020
</actionGroup>

app/code/Magento/Catalog/Model/ResourceModel/Product/Option.php

Lines changed: 116 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
namespace Magento\Catalog\Model\ResourceModel\Product;
77

88
use Magento\Catalog\Api\Data\ProductInterface;
9-
use Magento\Store\Model\ScopeInterface;
9+
use Magento\Framework\DataObject;
10+
use Magento\Framework\Model\AbstractModel;
11+
use Magento\Store\Model\Store;
1012

1113
/**
1214
* Catalog product custom option resource model
@@ -77,10 +79,10 @@ protected function _construct()
7779
/**
7880
* Save options store data
7981
*
80-
* @param \Magento\Framework\Model\AbstractModel $object
82+
* @param AbstractModel $object
8183
* @return \Magento\Framework\Model\ResourceModel\Db\AbstractDb
8284
*/
83-
protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
85+
protected function _afterSave(AbstractModel $object)
8486
{
8587
$this->_saveValuePrices($object);
8688
$this->_saveValueTitles($object);
@@ -91,140 +93,38 @@ protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
9193
/**
9294
* Save value prices
9395
*
94-
* @param \Magento\Framework\Model\AbstractModel $object
96+
* @param AbstractModel $object
9597
* @return $this
96-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
97-
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
9898
*/
99-
protected function _saveValuePrices(\Magento\Framework\Model\AbstractModel $object)
99+
protected function _saveValuePrices(AbstractModel $object)
100100
{
101-
$priceTable = $this->getTable('catalog_product_option_price');
102-
$connection = $this->getConnection();
103-
104101
/*
105102
* Better to check param 'price' and 'price_type' for saving.
106103
* If there is not price skip saving price
107104
*/
108-
109105
if (in_array($object->getType(), $this->getPriceTypes())) {
110-
//save for store_id = 0
106+
// save for store_id = 0
111107
if (!$object->getData('scope', 'price')) {
112-
$statement = $connection->select()->from(
113-
$priceTable,
114-
'option_id'
115-
)->where(
116-
'option_id = ?',
117-
$object->getId()
118-
)->where(
119-
'store_id = ?',
120-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
121-
);
122-
$optionId = $connection->fetchOne($statement);
123-
124-
if ($optionId) {
125-
$data = $this->_prepareDataForTable(
126-
new \Magento\Framework\DataObject(
127-
['price' => $object->getPrice(), 'price_type' => $object->getPriceType()]
128-
),
129-
$priceTable
130-
);
131-
132-
$connection->update(
133-
$priceTable,
134-
$data,
135-
[
136-
'option_id = ?' => $object->getId(),
137-
'store_id = ?' => \Magento\Store\Model\Store::DEFAULT_STORE_ID
138-
]
139-
);
140-
} else {
141-
$data = $this->_prepareDataForTable(
142-
new \Magento\Framework\DataObject(
143-
[
144-
'option_id' => $object->getId(),
145-
'store_id' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
146-
'price' => $object->getPrice(),
147-
'price_type' => $object->getPriceType(),
148-
]
149-
),
150-
$priceTable
151-
);
152-
$connection->insert($priceTable, $data);
153-
}
108+
$this->savePriceByStore($object, Store::DEFAULT_STORE_ID);
154109
}
155110

156111
$scope = (int)$this->_config->getValue(
157-
\Magento\Store\Model\Store::XML_PATH_PRICE_SCOPE,
158-
ScopeInterface::SCOPE_STORE
112+
Store::XML_PATH_PRICE_SCOPE,
113+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
159114
);
160115

161-
if ($object->getStoreId() != '0' && $scope == \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE) {
162-
$website = $this->_storeManager->getStore($object->getStoreId())->getWebsite();
163-
164-
$websiteBaseCurrency = $this->_config->getValue(
165-
\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
166-
ScopeInterface::SCOPE_WEBSITE,
167-
$website
168-
);
169-
170-
$storeIds = $website->getStoreIds();
171-
if (is_array($storeIds)) {
172-
foreach ($storeIds as $storeId) {
173-
if ($object->getPriceType() == 'fixed') {
174-
$storeCurrency = $this->_storeManager->getStore($storeId)->getBaseCurrencyCode();
175-
$rate = $this->_currencyFactory->create()->load($websiteBaseCurrency)
176-
->getRate($storeCurrency);
177-
if (!$rate) {
178-
$rate = 1;
179-
}
180-
$newPrice = $object->getPrice() * $rate;
181-
} else {
182-
$newPrice = $object->getPrice();
183-
}
184-
185-
$statement = $connection->select()->from(
186-
$priceTable
187-
)->where(
188-
'option_id = ?',
189-
$object->getId()
190-
)->where(
191-
'store_id = ?',
192-
$storeId
193-
);
194-
195-
if ($connection->fetchOne($statement)) {
196-
$data = $this->_prepareDataForTable(
197-
new \Magento\Framework\DataObject(
198-
['price' => $newPrice, 'price_type' => $object->getPriceType()]
199-
),
200-
$priceTable
201-
);
202-
203-
$connection->update(
204-
$priceTable,
205-
$data,
206-
['option_id = ?' => $object->getId(), 'store_id = ?' => $storeId]
207-
);
208-
} else {
209-
$data = $this->_prepareDataForTable(
210-
new \Magento\Framework\DataObject(
211-
[
212-
'option_id' => $object->getId(),
213-
'store_id' => $storeId,
214-
'price' => $newPrice,
215-
'price_type' => $object->getPriceType(),
216-
]
217-
),
218-
$priceTable
219-
);
220-
$connection->insert($priceTable, $data);
221-
}
222-
}
116+
if ((int)$object->getStoreId() !== Store::DEFAULT_STORE_ID && $scope === Store::PRICE_SCOPE_WEBSITE) {
117+
$storeIds = $this->_storeManager->getStore($object->getStoreId())->getWebsite()->getStoreIds();
118+
if (empty($storeIds)) {
119+
return $this;
120+
}
121+
foreach ($storeIds as $storeId) {
122+
$newPrice = $this->calculateStorePrice($object, $storeId);
123+
$this->savePriceByStore($object, (int)$storeId, $newPrice);
223124
}
224-
} elseif ($scope == \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE && $object->getData('scope', 'price')
225-
) {
226-
$connection->delete(
227-
$priceTable,
125+
} elseif ($scope === Store::PRICE_SCOPE_WEBSITE && $object->getData('scope', 'price')) {
126+
$this->getConnection()->delete(
127+
$this->getTable('catalog_product_option_price'),
228128
['option_id = ?' => $object->getId(), 'store_id = ?' => $object->getStoreId()]
229129
);
230130
}
@@ -233,31 +133,112 @@ protected function _saveValuePrices(\Magento\Framework\Model\AbstractModel $obje
233133
return $this;
234134
}
235135

136+
/**
137+
* Save option price by store
138+
*
139+
* @param AbstractModel $object
140+
* @param int $storeId
141+
* @param float|null $newPrice
142+
*/
143+
private function savePriceByStore(AbstractModel $object, int $storeId, float $newPrice = null)
144+
{
145+
$priceTable = $this->getTable('catalog_product_option_price');
146+
$connection = $this->getConnection();
147+
$price = $newPrice ?? $object->getPrice();
148+
149+
$statement = $connection->select()->from($priceTable, 'option_id')
150+
->where('option_id = ?', $object->getId())
151+
->where('store_id = ?', $storeId);
152+
$optionId = $connection->fetchOne($statement);
153+
154+
if (!$optionId) {
155+
$data = $this->_prepareDataForTable(
156+
new DataObject(
157+
[
158+
'option_id' => $object->getId(),
159+
'store_id' => $storeId,
160+
'price' => $price,
161+
'price_type' => $object->getPriceType(),
162+
]
163+
),
164+
$priceTable
165+
);
166+
$connection->insert($priceTable, $data);
167+
} else {
168+
// skip to update the default price when the price is saving on other store
169+
if ($storeId === Store::DEFAULT_STORE_ID && (int)$object->getStoreId() !== $storeId) {
170+
return;
171+
}
172+
173+
$data = $this->_prepareDataForTable(
174+
new DataObject(
175+
[
176+
'price' => $price,
177+
'price_type' => $object->getPriceType()
178+
]
179+
),
180+
$priceTable
181+
);
182+
183+
$connection->update(
184+
$priceTable,
185+
$data,
186+
[
187+
'option_id = ?' => $object->getId(),
188+
'store_id = ?' => $storeId
189+
]
190+
);
191+
}
192+
}
193+
194+
/**
195+
* Calculate price by store
196+
*
197+
* @param AbstractModel $object
198+
* @param int $storeId
199+
* @return float
200+
*/
201+
private function calculateStorePrice(AbstractModel $object, int $storeId): float
202+
{
203+
$price = $object->getPrice();
204+
if ($object->getPriceType() === 'fixed') {
205+
$baseCurrency = $this->_config->getValue(
206+
\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
207+
'default'
208+
);
209+
$storeCurrency = $this->_storeManager->getStore($storeId)->getBaseCurrencyCode();
210+
$rate = $this->_currencyFactory->create()->load($baseCurrency)->getRate($storeCurrency);
211+
$price = $object->getPrice() * ($rate ?: 1);
212+
}
213+
214+
return (float)$price;
215+
}
216+
236217
/**
237218
* Save titles
238219
*
239-
* @param \Magento\Framework\Model\AbstractModel $object
220+
* @param AbstractModel $object
240221
* @return void
241222
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
242223
*/
243-
protected function _saveValueTitles(\Magento\Framework\Model\AbstractModel $object)
224+
protected function _saveValueTitles(AbstractModel $object)
244225
{
245226
$connection = $this->getConnection();
246227
$titleTableName = $this->getTable('catalog_product_option_title');
247-
foreach ([\Magento\Store\Model\Store::DEFAULT_STORE_ID, $object->getStoreId()] as $storeId) {
228+
foreach ([Store::DEFAULT_STORE_ID, $object->getStoreId()] as $storeId) {
248229
$existInCurrentStore = $this->getColFromOptionTable($titleTableName, (int)$object->getId(), (int)$storeId);
249-
$existInDefaultStore = (int)$storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID ?
230+
$existInDefaultStore = (int)$storeId === Store::DEFAULT_STORE_ID ?
250231
$existInCurrentStore :
251232
$this->getColFromOptionTable(
252233
$titleTableName,
253234
(int)$object->getId(),
254-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
235+
Store::DEFAULT_STORE_ID
255236
);
256237

257238
if ($object->getTitle()) {
258239
$isDeleteStoreTitle = (bool)$object->getData('is_delete_store_title');
259240
if ($existInCurrentStore) {
260-
if ($isDeleteStoreTitle && (int)$storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID) {
241+
if ($isDeleteStoreTitle && (int)$storeId !== Store::DEFAULT_STORE_ID) {
261242
$connection->delete($titleTableName, ['option_title_id = ?' => $existInCurrentStore]);
262243
} elseif ($object->getStoreId() == $storeId) {
263244
$data = $this->_prepareDataForTable(
@@ -275,9 +256,9 @@ protected function _saveValueTitles(\Magento\Framework\Model\AbstractModel $obje
275256
}
276257
} else {
277258
// we should insert record into not default store only of if it does not exist in default store
278-
if (($storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID && !$existInDefaultStore) ||
259+
if (($storeId == Store::DEFAULT_STORE_ID && !$existInDefaultStore) ||
279260
(
280-
$storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID &&
261+
$storeId != Store::DEFAULT_STORE_ID &&
281262
!$existInCurrentStore &&
282263
!$isDeleteStoreTitle
283264
)
@@ -296,7 +277,7 @@ protected function _saveValueTitles(\Magento\Framework\Model\AbstractModel $obje
296277
}
297278
}
298279
} else {
299-
if ($object->getId() && $object->getStoreId() > \Magento\Store\Model\Store::DEFAULT_STORE_ID
280+
if ($object->getId() && $object->getStoreId() > Store::DEFAULT_STORE_ID
300281
&& $storeId
301282
) {
302283
$connection->delete(
@@ -475,7 +456,7 @@ public function getSearchableData($productId, $storeId)
475456
'option_title_default.option_id=product_option.option_id',
476457
$connection->quoteInto(
477458
'option_title_default.store_id = ?',
478-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
459+
Store::DEFAULT_STORE_ID
479460
)
480461
]
481462
);
@@ -522,7 +503,7 @@ public function getSearchableData($productId, $storeId)
522503
'option_title_default.option_type_id=option_type.option_type_id',
523504
$connection->quoteInto(
524505
'option_title_default.store_id = ?',
525-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
506+
Store::DEFAULT_STORE_ID
526507
)
527508
]
528509
);
@@ -587,6 +568,8 @@ public function getPriceTypes()
587568
}
588569

589570
/**
571+
* Get Metadata Pool
572+
*
590573
* @return \Magento\Framework\EntityManager\MetadataPool
591574
*/
592575
private function getMetadataPool()

app/code/Magento/Catalog/Test/Mftf/Page/AdminProductUpdateAttributesPage.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
<page name="AdminProductUpdateAttributesPage" url="catalog/product_action_attribute/edit/" area="admin" module="Magento_Catalog">
1111
<section name="AdminUpdateAttributesHeaderSection"/>
1212
<section name="AdminUpdateAttributesWebsiteSection"/>
13+
<section name="AdminUpdateAttributesAttributesSection"/>
1314
</page>
1415
</pages>

app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@
1414
<element name="website" type="button" selector="#attributes_update_tabs_websites"/>
1515
<element name="addProductToWebsite" type="checkbox" selector="#add-products-to-website-content .website-checkbox"/>
1616
</section>
17+
<section name="AdminUpdateAttributesAttributesSection">
18+
<element name="formByStoreId" type="block" selector="//form[contains(@action,'store/{{store_id}}')]" parameterized="true"/>
19+
</section>
1720
</sections>

app/code/Magento/Catalog/etc/acl.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
<resource id="Magento_Backend::admin">
1212
<resource id="Magento_Catalog::catalog" title="Catalog" translate="title" sortOrder="30">
1313
<resource id="Magento_Catalog::catalog_inventory" title="Inventory" translate="title" sortOrder="10">
14-
<resource id="Magento_Catalog::products" title="Products" translate="title" sortOrder="10" />
14+
<resource id="Magento_Catalog::products" title="Products" translate="title" sortOrder="10">
15+
<resource id="Magento_Catalog::update_attributes" title="Update Attributes" translate="title" />
16+
</resource>
1517
<resource id="Magento_Catalog::categories" title="Categories" translate="title" sortOrder="20" />
1618
</resource>
1719
</resource>
@@ -23,7 +25,6 @@
2325
</resource>
2426
<resource id="Magento_Backend::stores_attributes">
2527
<resource id="Magento_Catalog::attributes_attributes" title="Product" translate="title" sortOrder="30" />
26-
<resource id="Magento_Catalog::update_attributes" title="Update Attributes" translate="title" sortOrder="35" />
2728
<resource id="Magento_Catalog::sets" title="Attribute Set" translate="title" sortOrder="40"/>
2829
</resource>
2930
</resource>

0 commit comments

Comments
 (0)