Skip to content

Commit 02fb27c

Browse files
author
Yevhen Miroshnychenko
committed
Merge branch '2.2-develop' into MAGETWO-93758
2 parents 0b1ccac + c8c2791 commit 02fb27c

File tree

89 files changed

+2366
-383
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2366
-383
lines changed

app/code/Magento/Bundle/Test/Mftf/ActionGroup/BundleProductsOnAdminActionGroup.xml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<actionGroup name="CreateBundleProductForTwoSimpleProducts">
1212
<arguments>
1313
<argument name="bundleProduct"/>
14+
<argument name="simpleProductFirst"/>
15+
<argument name="simpleProductSecond"/>
1416
</arguments>
1517
<fillField userInput="{{bundleProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillProductSku"/>
1618
<fillField userInput="{{bundleProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillProductName"/>
@@ -19,7 +21,22 @@
1921
<click selector="{{AdminProductFormBundleSection.AddOption}}" stepKey="clickAddOptionButton"/>
2022
<fillField userInput="{{bundleProduct.option_title}}" selector="{{AdminProductFormBundleSection.OptionTitle}}" stepKey="fillOptionTitle"/>
2123
<click selector="{{AdminProductFormBundleSection.AddProductsToOption}}" stepKey="clickAddProductsToOption"/>
22-
<click selector="{{AdminProductFormBundleSection.selectAll}}" stepKey="tickSelectAllCheckbox"/>
24+
25+
<!-- Select First Simple -->
26+
<click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickOnFiltersButton"/>
27+
<conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.clearAll}}" visible="true" stepKey="clearFilters"/>
28+
<fillField selector="{{AdminProductGridFilterSection.name}}" userInput="{{simpleProductFirst.name}}" stepKey="fillNameFilter"/>
29+
<click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="applyFilters"/>
30+
<click selector="{{AdminProductFormBundleSection.firstRowCheckbox}}" stepKey="selectFirstSimple"/>
31+
32+
<!-- Select Second Simple -->
33+
<click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickOnFiltersButton2"/>
34+
<conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.clearAll}}" visible="true" stepKey="clearFilters2"/>
35+
<fillField selector="{{AdminProductGridFilterSection.name}}" userInput="{{simpleProductSecond.name}}" stepKey="fillNameFilter2"/>
36+
<click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="applyFilters2"/>
37+
<click selector="{{AdminProductFormBundleSection.firstRowCheckbox}}" stepKey="selectSecondSimple"/>
38+
39+
<!-- Add Selected Simples To Bundle -->
2340
<click selector="{{AdminProductFormBundleSection.AddSelectedProducts}}" stepKey="clickAddSelectedProductsButton"/>
2441
<fillField userInput="{{bundleProduct.default_quantity1}}" selector="{{AdminProductFormBundleSection.DefaultQuantity1}}" stepKey="fillDefaultQuantityForFirstProduct"/>
2542
<fillField userInput="{{bundleProduct.default_quantity2}}" selector="{{AdminProductFormBundleSection.DefaultQuantity2}}" stepKey="fillDefaultQuantityForSecondProduct"/>

app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormSection.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
<!--Add Products to Option-->
2121
<element name="selectAll" type="input" selector="//label[@data-bind='attr: {for: ko.uid}']"/>
2222
<element name="AddSelectedProducts" type="button" selector="//span[contains(text(),'Add Selected Products')]/ancestor::button" timeout="30"/>
23+
<element name="firstRowCheckbox" type="checkbox" selector="tr.data-row:nth-of-type(1) input.admin__control-checkbox[data-action='select-row']"/>
2324
</section>
2425
</sections>

app/code/Magento/Bundle/Test/Mftf/Test/AdminCreateBundleProductTest.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
<before>
2222
<createData entity="_defaultCategory" stepKey="createPreReqCategory"/>
2323
<createData entity="SimpleProduct" stepKey="createPreReqSimpleProduct1">
24-
<requiredEntity createDataKey="createPreReqCategory"/>
24+
<requiredEntity createDataKey="createPreReqCategory"/>
2525
</createData>
2626
<createData entity="SimpleProduct2" stepKey="createPreReqSimpleProduct2">
27-
<requiredEntity createDataKey="createPreReqCategory"/>
27+
<requiredEntity createDataKey="createPreReqCategory"/>
2828
</createData>
2929
</before>
3030
<after>
@@ -45,6 +45,8 @@
4545
<!--Step4. Fill in all data according to data set-->
4646
<actionGroup ref="CreateBundleProductForTwoSimpleProducts" stepKey="CreateBundleProductForTwoSimpleProducts">
4747
<argument name="bundleProduct" value="BundleProduct"/>
48+
<argument name="simpleProductFirst" value="$$createPreReqSimpleProduct1$$"/>
49+
<argument name="simpleProductSecond" value="$$createPreReqSimpleProduct2$$"/>
4850
</actionGroup>
4951

5052
<!--Step5. Save product-->

app/code/Magento/Bundle/Test/Mftf/Test/StorefrontEditBundleProductTest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
</annotations>
2121
<before>
2222
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
23+
<createData entity="DefaultTaxConfig" stepKey="defaultTaxConfiguration"/>
24+
<createData entity="WeeeConfigDisable" stepKey="disableFPT"/>
2325
<createData entity="SimpleProduct3" stepKey="simpleProduct1"/>
2426
<createData entity="SimpleProduct3" stepKey="simpleProduct2"/>
2527
</before>

app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -375,118 +375,10 @@ protected function modifyPriceData($object, $data)
375375
*
376376
* @param \Magento\Catalog\Model\Product $object
377377
* @return $this
378-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
379-
* @SuppressWarnings(PHPMD.NPathComplexity)
380-
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
378+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
381379
*/
382380
public function afterSave($object)
383381
{
384-
$websiteId = $this->_storeManager->getStore($object->getStoreId())->getWebsiteId();
385-
$isGlobal = $this->getAttribute()->isScopeGlobal() || $websiteId == 0;
386-
387-
$priceRows = $object->getData($this->getAttribute()->getName());
388-
if (null === $priceRows) {
389-
return $this;
390-
}
391-
392-
$priceRows = array_filter((array)$priceRows);
393-
394-
$old = [];
395-
$new = [];
396-
397-
// prepare original data for compare
398-
$origPrices = $object->getOrigData($this->getAttribute()->getName());
399-
if (!is_array($origPrices)) {
400-
$origPrices = [];
401-
}
402-
foreach ($origPrices as $data) {
403-
if ($data['website_id'] > 0 || $data['website_id'] == '0' && $isGlobal) {
404-
$key = implode(
405-
'-',
406-
array_merge(
407-
[$data['website_id'], $data['cust_group']],
408-
$this->_getAdditionalUniqueFields($data)
409-
)
410-
);
411-
$old[$key] = $data;
412-
}
413-
}
414-
415-
// prepare data for save
416-
foreach ($priceRows as $data) {
417-
$hasEmptyData = false;
418-
foreach ($this->_getAdditionalUniqueFields($data) as $field) {
419-
if (empty($field)) {
420-
$hasEmptyData = true;
421-
break;
422-
}
423-
}
424-
425-
if ($hasEmptyData || !isset($data['cust_group']) || !empty($data['delete'])) {
426-
continue;
427-
}
428-
if ($this->getAttribute()->isScopeGlobal() && $data['website_id'] > 0) {
429-
continue;
430-
}
431-
if (!$isGlobal && (int)$data['website_id'] == 0) {
432-
continue;
433-
}
434-
435-
$key = implode(
436-
'-',
437-
array_merge([$data['website_id'], $data['cust_group']], $this->_getAdditionalUniqueFields($data))
438-
);
439-
440-
$useForAllGroups = $data['cust_group'] == $this->_groupManagement->getAllCustomersGroup()->getId();
441-
$customerGroupId = !$useForAllGroups ? $data['cust_group'] : 0;
442-
$new[$key] = array_merge(
443-
$this->getAdditionalFields($data),
444-
[
445-
'website_id' => $data['website_id'],
446-
'all_groups' => $useForAllGroups ? 1 : 0,
447-
'customer_group_id' => $customerGroupId,
448-
'value' => isset($data['price']) ? $data['price'] : null,
449-
],
450-
$this->_getAdditionalUniqueFields($data)
451-
);
452-
}
453-
454-
$delete = array_diff_key($old, $new);
455-
$insert = array_diff_key($new, $old);
456-
$update = array_intersect_key($new, $old);
457-
458-
$isChanged = false;
459-
$productId = $object->getData($this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField());
460-
461-
if (!empty($delete)) {
462-
foreach ($delete as $data) {
463-
$this->_getResource()->deletePriceData($productId, null, $data['price_id']);
464-
$isChanged = true;
465-
}
466-
}
467-
468-
if (!empty($insert)) {
469-
foreach ($insert as $data) {
470-
$price = new \Magento\Framework\DataObject($data);
471-
$price->setData(
472-
$this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(),
473-
$productId
474-
);
475-
$this->_getResource()->savePriceData($price);
476-
477-
$isChanged = true;
478-
}
479-
}
480-
481-
if (!empty($update)) {
482-
$isChanged |= $this->updateValues($update, $old);
483-
}
484-
485-
if ($isChanged) {
486-
$valueChangedKey = $this->getAttribute()->getName() . '_changed';
487-
$object->setData($valueChangedKey, 1);
488-
}
489-
490382
return $this;
491383
}
492384

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Model\Product\Attribute\Backend\TierPrice;
7+
8+
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
9+
use Magento\Store\Model\StoreManagerInterface;
10+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
11+
use Magento\Catalog\Api\Data\ProductInterface;
12+
use Magento\Customer\Api\GroupManagementInterface;
13+
use Magento\Framework\EntityManager\MetadataPool;
14+
use Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice;
15+
16+
/**
17+
* Process tier price data for handled new product
18+
*/
19+
class SaveHandler implements ExtensionInterface
20+
{
21+
/**
22+
* @var \Magento\Store\Model\StoreManagerInterface
23+
*/
24+
private $storeManager;
25+
26+
/**
27+
* @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
28+
*/
29+
private $attributeRepository;
30+
31+
/**
32+
* @var \Magento\Customer\Api\GroupManagementInterface
33+
*/
34+
private $groupManagement;
35+
36+
/**
37+
* @var \Magento\Framework\EntityManager\MetadataPool
38+
*/
39+
private $metadataPoll;
40+
41+
/**
42+
* @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice
43+
*/
44+
private $tierPriceResource;
45+
46+
/**
47+
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
48+
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
49+
* @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
50+
* @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
51+
* @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice $tierPriceResource
52+
*/
53+
public function __construct(
54+
StoreManagerInterface $storeManager,
55+
ProductAttributeRepositoryInterface $attributeRepository,
56+
GroupManagementInterface $groupManagement,
57+
MetadataPool $metadataPool,
58+
Tierprice $tierPriceResource
59+
) {
60+
$this->storeManager = $storeManager;
61+
$this->attributeRepository = $attributeRepository;
62+
$this->groupManagement = $groupManagement;
63+
$this->metadataPoll = $metadataPool;
64+
$this->tierPriceResource = $tierPriceResource;
65+
}
66+
67+
/**
68+
* Set tier price data for product entity
69+
*
70+
* @param \Magento\Catalog\Api\Data\ProductInterface|object $entity
71+
* @param array $arguments
72+
* @return \Magento\Catalog\Api\Data\ProductInterface|object
73+
* @throws \Magento\Framework\Exception\NoSuchEntityException
74+
* @throws \Magento\Framework\Exception\LocalizedException
75+
* @throws \Magento\Framework\Exception\InputException
76+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
77+
*/
78+
public function execute($entity, $arguments = [])
79+
{
80+
$attribute = $this->attributeRepository->get('tier_price');
81+
$priceRows = $entity->getData($attribute->getName());
82+
if (null !== $priceRows) {
83+
if (!is_array($priceRows)) {
84+
throw new \Magento\Framework\Exception\InputException(
85+
__('Tier prices data should be array, but actually other type is received')
86+
);
87+
}
88+
$websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId();
89+
$isGlobal = $attribute->isScopeGlobal() || $websiteId === 0;
90+
$identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
91+
$priceRows = array_filter($priceRows);
92+
$productId = $entity->getData($identifierField);
93+
94+
// prepare and save data
95+
foreach ($priceRows as $data) {
96+
$isPriceWebsiteGlobal = (int)$data['website_id'] === 0;
97+
if ($isGlobal === $isPriceWebsiteGlobal
98+
|| !empty($data['price_qty'])
99+
|| isset($data['cust_group'])
100+
) {
101+
$tierPrice = $this->prepareTierPrice($data);
102+
$price = new \Magento\Framework\DataObject($tierPrice);
103+
$price->setData(
104+
$identifierField,
105+
$productId
106+
);
107+
$this->tierPriceResource->savePriceData($price);
108+
$valueChangedKey = $attribute->getName() . '_changed';
109+
$entity->setData($valueChangedKey, 1);
110+
}
111+
}
112+
}
113+
114+
return $entity;
115+
}
116+
117+
/**
118+
* Get additional tier price fields
119+
*
120+
* @return array
121+
*/
122+
private function getAdditionalFields(array $objectArray): array
123+
{
124+
$percentageValue = $this->getPercentage($objectArray);
125+
return [
126+
'value' => $percentageValue ? null : $objectArray['price'],
127+
'percentage_value' => $percentageValue ?: null,
128+
];
129+
}
130+
131+
/**
132+
* Check whether price has percentage value.
133+
*
134+
* @param array $priceRow
135+
* @return integer|null
136+
*/
137+
private function getPercentage(array $priceRow)
138+
{
139+
return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
140+
? (int)$priceRow['percentage_value']
141+
: null;
142+
}
143+
144+
/**
145+
* Prepare tier price data by provided price row data
146+
*
147+
* @param array $data
148+
* @return array
149+
* @throws \Magento\Framework\Exception\LocalizedException
150+
*/
151+
private function prepareTierPrice(array $data): array
152+
{
153+
$useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId();
154+
$customerGroupId = $useForAllGroups ? 0 : $data['cust_group'];
155+
$tierPrice = array_merge(
156+
$this->getAdditionalFields($data),
157+
[
158+
'website_id' => $data['website_id'],
159+
'all_groups' => (int)$useForAllGroups,
160+
'customer_group_id' => $customerGroupId,
161+
'value' => $data['price'] ?? null,
162+
'qty' => (int)$data['price_qty']
163+
]
164+
);
165+
166+
return $tierPrice;
167+
}
168+
}

0 commit comments

Comments
 (0)