-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7313 from magento-l3/L3_PR_21-12-10
L3_PR_21-12-10
- Loading branch information
Showing
80 changed files
with
3,235 additions
and
524 deletions.
There are no files selected for viewing
160 changes: 160 additions & 0 deletions
160
app/code/Magento/Bundle/Model/Inventory/ChangeParentStockStatus.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Bundle\Model\Inventory; | ||
|
||
use Magento\Bundle\Model\Product\Type; | ||
use Magento\CatalogInventory\Api\Data\StockItemInterface; | ||
use Magento\CatalogInventory\Api\StockConfigurationInterface; | ||
use Magento\CatalogInventory\Api\StockItemCriteriaInterfaceFactory; | ||
use Magento\CatalogInventory\Api\StockItemRepositoryInterface; | ||
|
||
/*** | ||
* Update stock status of bundle products based on children products stock status | ||
*/ | ||
class ChangeParentStockStatus | ||
{ | ||
/** | ||
* @var Type | ||
*/ | ||
private $bundleType; | ||
|
||
/** | ||
* @var StockItemCriteriaInterfaceFactory | ||
*/ | ||
private $criteriaInterfaceFactory; | ||
|
||
/** | ||
* @var StockItemRepositoryInterface | ||
*/ | ||
private $stockItemRepository; | ||
|
||
/** | ||
* @var StockConfigurationInterface | ||
*/ | ||
private $stockConfiguration; | ||
|
||
/** | ||
* @param StockItemCriteriaInterfaceFactory $criteriaInterfaceFactory | ||
* @param StockItemRepositoryInterface $stockItemRepository | ||
* @param StockConfigurationInterface $stockConfiguration | ||
* @param Type $bundleType | ||
*/ | ||
public function __construct( | ||
StockItemCriteriaInterfaceFactory $criteriaInterfaceFactory, | ||
StockItemRepositoryInterface $stockItemRepository, | ||
StockConfigurationInterface $stockConfiguration, | ||
Type $bundleType | ||
) { | ||
$this->bundleType = $bundleType; | ||
$this->criteriaInterfaceFactory = $criteriaInterfaceFactory; | ||
$this->stockItemRepository = $stockItemRepository; | ||
$this->stockConfiguration = $stockConfiguration; | ||
} | ||
|
||
/** | ||
* Update stock status of bundle products based on children products stock status | ||
* | ||
* @param array $childrenIds | ||
* @return void | ||
*/ | ||
public function execute(array $childrenIds): void | ||
{ | ||
$parentIds = $this->bundleType->getParentIdsByChild($childrenIds); | ||
foreach (array_unique($parentIds) as $productId) { | ||
$this->processStockForParent((int)$productId); | ||
} | ||
} | ||
|
||
/** | ||
* Update stock status of bundle product based on children products stock status | ||
* | ||
* @param int $productId | ||
* @return void | ||
*/ | ||
private function processStockForParent(int $productId): void | ||
{ | ||
$stockItems = $this->getStockItems([$productId]); | ||
$parentStockItem = $stockItems[$productId] ?? null; | ||
if ($parentStockItem) { | ||
$childrenIsInStock = $this->isChildrenInStock($productId); | ||
if ($this->isNeedToUpdateParent($parentStockItem, $childrenIsInStock)) { | ||
$parentStockItem->setIsInStock($childrenIsInStock); | ||
$parentStockItem->setStockStatusChangedAuto(1); | ||
$this->stockItemRepository->save($parentStockItem); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Returns stock status of bundle product based on children stock status | ||
* | ||
* Returns TRUE if any of the following conditions is true: | ||
* - At least one product is in-stock in each required option | ||
* - Any product is in-stock (if all options are optional) | ||
* | ||
* @param int $productId | ||
* @return bool | ||
*/ | ||
private function isChildrenInStock(int $productId) : bool | ||
{ | ||
$childrenIsInStock = false; | ||
$childrenIds = $this->bundleType->getChildrenIds($productId, true); | ||
$stockItems = $this->getStockItems(array_merge(...array_values($childrenIds))); | ||
foreach ($childrenIds as $childrenIdsPerOption) { | ||
$childrenIsInStock = false; | ||
foreach ($childrenIdsPerOption as $id) { | ||
$stockItem = $stockItems[$id] ?? null; | ||
if ($stockItem && $stockItem->getIsInStock()) { | ||
$childrenIsInStock = true; | ||
break; | ||
} | ||
} | ||
if (!$childrenIsInStock) { | ||
break; | ||
} | ||
} | ||
|
||
return $childrenIsInStock; | ||
} | ||
|
||
/** | ||
* Check if parent item should be updated | ||
* | ||
* @param StockItemInterface $parentStockItem | ||
* @param bool $childrenIsInStock | ||
* @return bool | ||
*/ | ||
private function isNeedToUpdateParent( | ||
StockItemInterface $parentStockItem, | ||
bool $childrenIsInStock | ||
): bool { | ||
return $parentStockItem->getIsInStock() !== $childrenIsInStock && | ||
($childrenIsInStock === false || $parentStockItem->getStockStatusChangedAuto()); | ||
} | ||
|
||
/** | ||
* Get stock items for provided product IDs | ||
* | ||
* @param array $productIds | ||
* @return StockItemInterface[] | ||
*/ | ||
private function getStockItems(array $productIds): array | ||
{ | ||
$criteria = $this->criteriaInterfaceFactory->create(); | ||
$criteria->setScopeFilter($this->stockConfiguration->getDefaultScopeId()); | ||
$criteria->setProductsFilter(array_unique($productIds)); | ||
$stockItemCollection = $this->stockItemRepository->getList($criteria); | ||
|
||
$stockItems = []; | ||
foreach ($stockItemCollection->getItems() as $stockItem) { | ||
$stockItems[$stockItem->getProductId()] = $stockItem; | ||
} | ||
|
||
return $stockItems; | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
app/code/Magento/Bundle/Model/Inventory/ParentItemProcessor.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\Bundle\Model\Inventory; | ||
|
||
use Magento\Catalog\Api\Data\ProductInterface as Product; | ||
use Magento\CatalogInventory\Observer\ParentItemProcessorInterface; | ||
|
||
/** | ||
* Bundle product stock item processor | ||
*/ | ||
class ParentItemProcessor implements ParentItemProcessorInterface | ||
{ | ||
/** | ||
* @var ChangeParentStockStatus | ||
*/ | ||
private $changeParentStockStatus; | ||
|
||
/** | ||
* @param ChangeParentStockStatus $changeParentStockStatus | ||
*/ | ||
public function __construct( | ||
ChangeParentStockStatus $changeParentStockStatus | ||
) { | ||
$this->changeParentStockStatus = $changeParentStockStatus; | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function process(Product $product) | ||
{ | ||
$this->changeParentStockStatus->execute([$product->getId()]); | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
...st/Mftf/ActionGroup/AdminAssertSpecialPriceAttributeValueOnProductGridPageActionGroup.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
--> | ||
|
||
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> | ||
<actionGroup name="AdminAssertSpecialPriceAttributeValueOnProductGridPageActionGroup"> | ||
<annotations> | ||
<description>Assert special price attribute value from the catalog product grid page</description> | ||
</annotations> | ||
<arguments> | ||
<argument name="specialPriceColumn" type="string" defaultValue="Special Price"/> | ||
<argument name="expectedValue" type="string" defaultValue=""/> | ||
</arguments> | ||
<!-- Check the special price column are present in catalog product grid --> | ||
<seeElement selector="{{AdminProductGridSection.columnHeader(specialPriceColumn)}}" stepKey="seeSpecialPriceColumn"/> | ||
<!-- Grab the special price value from the catalog product grid --> | ||
<grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', specialPriceColumn)}}" stepKey="getSpecialPrice"/> | ||
<assertStringContainsString stepKey="assertSpecialPricePercentageSymbol"> | ||
<expectedResult type="string">{{expectedValue}}</expectedResult> | ||
<actualResult type="variable">$getSpecialPrice</actualResult> | ||
</assertStringContainsString> | ||
</actionGroup> | ||
</actionGroups> |
86 changes: 86 additions & 0 deletions
86
app/code/Magento/Bundle/Test/Mftf/Test/AdminBundleProductPriceSymbolValidationInGridTest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
--> | ||
|
||
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> | ||
<test name="AdminBundleProductPriceSymbolValidationInGridTest"> | ||
<annotations> | ||
<features value="Bundle"/> | ||
<stories value="Bundle Products Special Price Column in admin Grid should have % sign not currency sign"/> | ||
<title value="Admin to validate the bundle products special price column in grid should display percentage symbol instead of currency sign"/> | ||
<description value="Admin to validate the bundle products special price column in grid should display percentage symbol instead of currency sign"/> | ||
<severity value="AVERAGE"/> | ||
<testCaseId value="AC-1378"/> | ||
<useCaseId value="ACP2E-64"/> | ||
<group value="Bundle"/> | ||
</annotations> | ||
<before> | ||
<!-- Create a simple product --> | ||
<createData entity="SimpleProduct2" stepKey="simpleProduct1"/> | ||
<!-- Admin login --> | ||
<actionGroup ref="AdminLoginActionGroup" stepKey="loginToAdminPanel"/> | ||
<!-- Navigate to catalog product grid page --> | ||
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPage"/> | ||
<!-- Open the column dropdown to add the special price from the catalog product grid --> | ||
<actionGroup ref="ToggleAdminProductGridColumnsDropdownActionGroup" stepKey="openColumnsDropdownSpecialPrice"/> | ||
<actionGroup ref="CheckAdminProductGridColumnOptionActionGroup" stepKey="checkSpecialPriceOption"> | ||
<argument name="optionName" value="Special Price"/> | ||
</actionGroup> | ||
<actionGroup ref="ToggleAdminProductGridColumnsDropdownActionGroup" stepKey="closeColumnsDropdownSpecialPrice"/> | ||
<!-- It takes a few seconds for column update to be saved --> | ||
<!-- waitForPageLoad won't work here since saving is happening with a short delay --> | ||
<wait time="5" stepKey="waitForColumnUpdateToSave"/> | ||
</before> | ||
<after> | ||
<!-- Navigate to catalog product grid page --> | ||
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPage"/> | ||
<!-- Clean applied product filters before delete --> | ||
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="clearAppliedFilters"/> | ||
<!-- Delete all the products from the catalog product grid --> | ||
<actionGroup ref="DeleteProductsIfTheyExistActionGroup" stepKey="deleteAllProducts"/> | ||
<!-- Set product grid to default columns --> | ||
<actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="setProductGridToDefaultColumns"/> | ||
<!-- Logging out --> | ||
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> | ||
</after> | ||
<!-- Go to bundle product creation page --> | ||
<actionGroup ref="AdminOpenNewProductFormPageActionGroup" stepKey="openNewBundleProductPage"> | ||
<argument name="productType" value="{{BundleProduct.type}}"/> | ||
<argument name="attributeSetId" value="{{BundleProduct.set}}"/> | ||
</actionGroup> | ||
<!-- Sets the provided Special Price on the Admin Product creation/edit page. --> | ||
<actionGroup ref="AddSpecialPriceToProductActionGroup" stepKey="addSpecialPrice"> | ||
<argument name="price" value="{{SimpleProductWithSpecialPrice.special_price}}"/> | ||
</actionGroup> | ||
<!-- Fill up the new product form with data --> | ||
<actionGroup ref="CreateBasicBundleProductActionGroup" stepKey="createBundledProduct"> | ||
<argument name="bundleProduct" value="BundleProduct"/> | ||
</actionGroup> | ||
<!-- Add the bundle option to the product --> | ||
<actionGroup ref="AddBundleOptionWithOneProductActionGroup" stepKey="addBundleOption"> | ||
<argument name="x" value="0"/> | ||
<argument name="n" value="1"/> | ||
<argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> | ||
<argument name="prodTwoSku" value=""/> | ||
<argument name="optionTitle" value="{{BundleProduct.optionTitle1}}"/> | ||
<argument name="inputType" value="{{BundleProduct.optionInputType1}}"/> | ||
</actionGroup> | ||
<!-- Save the bundle product --> | ||
<actionGroup ref="SaveProductFormActionGroup" stepKey="saveProductForm"/> | ||
<!-- Navigate to catalog product grid page --> | ||
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPageAfterProdSave"/> | ||
<!-- Search the created bundle product with sku --> | ||
<actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterBundleProductGridBySku"> | ||
<argument name="sku" value="{{BundleProduct.sku}}"/> | ||
</actionGroup> | ||
<!-- Asserting with the special price value contains the percentage value --> | ||
<actionGroup ref="AdminAssertSpecialPriceAttributeValueOnProductGridPageActionGroup" stepKey="assertSpecialPricePercentageSymbol"> | ||
<argument name="expectedValue" value="90.00%"/> | ||
</actionGroup> | ||
</test> | ||
</tests> |
Oops, something went wrong.