Skip to content

Commit 0f3d7e4

Browse files
committed
Merge branch 'L3_PR_21-12-13' into L3_PR_21-12-10
2 parents 8003bd7 + 2cb48c9 commit 0f3d7e4

File tree

44 files changed

+1828
-316
lines changed

Some content is hidden

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

44 files changed

+1828
-316
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="AdminAssertSpecialPriceAttributeValueOnProductGridPageActionGroup">
12+
<annotations>
13+
<description>Assert special price attribute value from the catalog product grid page</description>
14+
</annotations>
15+
<arguments>
16+
<argument name="specialPriceColumn" type="string" defaultValue="Special Price"/>
17+
<argument name="expectedValue" type="string" defaultValue=""/>
18+
</arguments>
19+
<!-- Check the special price column are present in catalog product grid -->
20+
<seeElement selector="{{AdminProductGridSection.columnHeader(specialPriceColumn)}}" stepKey="seeSpecialPriceColumn"/>
21+
<!-- Grab the special price value from the catalog product grid -->
22+
<grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', specialPriceColumn)}}" stepKey="getSpecialPrice"/>
23+
<assertStringContainsString stepKey="assertSpecialPricePercentageSymbol">
24+
<expectedResult type="string">{{expectedValue}}</expectedResult>
25+
<actualResult type="variable">$getSpecialPrice</actualResult>
26+
</assertStringContainsString>
27+
</actionGroup>
28+
</actionGroups>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="AdminBundleProductPriceSymbolValidationInGridTest">
12+
<annotations>
13+
<features value="Bundle"/>
14+
<stories value="Bundle Products Special Price Column in admin Grid should have % sign not currency sign"/>
15+
<title value="Admin to validate the bundle products special price column in grid should display percentage symbol instead of currency sign"/>
16+
<description value="Admin to validate the bundle products special price column in grid should display percentage symbol instead of currency sign"/>
17+
<severity value="AVERAGE"/>
18+
<testCaseId value="AC-1378"/>
19+
<useCaseId value="ACP2E-64"/>
20+
<group value="Bundle"/>
21+
</annotations>
22+
<before>
23+
<!-- Create a simple product -->
24+
<createData entity="SimpleProduct2" stepKey="simpleProduct1"/>
25+
<!-- Admin login -->
26+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginToAdminPanel"/>
27+
<!-- Navigate to catalog product grid page -->
28+
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPage"/>
29+
<!-- Open the column dropdown to add the special price from the catalog product grid -->
30+
<actionGroup ref="ToggleAdminProductGridColumnsDropdownActionGroup" stepKey="openColumnsDropdownSpecialPrice"/>
31+
<actionGroup ref="CheckAdminProductGridColumnOptionActionGroup" stepKey="checkSpecialPriceOption">
32+
<argument name="optionName" value="Special Price"/>
33+
</actionGroup>
34+
<actionGroup ref="ToggleAdminProductGridColumnsDropdownActionGroup" stepKey="closeColumnsDropdownSpecialPrice"/>
35+
<!-- It takes a few seconds for column update to be saved -->
36+
<!-- waitForPageLoad won't work here since saving is happening with a short delay -->
37+
<wait time="5" stepKey="waitForColumnUpdateToSave"/>
38+
</before>
39+
<after>
40+
<!-- Navigate to catalog product grid page -->
41+
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPage"/>
42+
<!-- Clean applied product filters before delete -->
43+
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="clearAppliedFilters"/>
44+
<!-- Delete all the products from the catalog product grid -->
45+
<actionGroup ref="DeleteProductsIfTheyExistActionGroup" stepKey="deleteAllProducts"/>
46+
<!-- Set product grid to default columns -->
47+
<actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="setProductGridToDefaultColumns"/>
48+
<!-- Logging out -->
49+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
50+
</after>
51+
<!-- Go to bundle product creation page -->
52+
<actionGroup ref="AdminOpenNewProductFormPageActionGroup" stepKey="openNewBundleProductPage">
53+
<argument name="productType" value="{{BundleProduct.type}}"/>
54+
<argument name="attributeSetId" value="{{BundleProduct.set}}"/>
55+
</actionGroup>
56+
<!-- Sets the provided Special Price on the Admin Product creation/edit page. -->
57+
<actionGroup ref="AddSpecialPriceToProductActionGroup" stepKey="addSpecialPrice">
58+
<argument name="price" value="{{SimpleProductWithSpecialPrice.special_price}}"/>
59+
</actionGroup>
60+
<!-- Fill up the new product form with data -->
61+
<actionGroup ref="CreateBasicBundleProductActionGroup" stepKey="createBundledProduct">
62+
<argument name="bundleProduct" value="BundleProduct"/>
63+
</actionGroup>
64+
<!-- Add the bundle option to the product -->
65+
<actionGroup ref="AddBundleOptionWithOneProductActionGroup" stepKey="addBundleOption">
66+
<argument name="x" value="0"/>
67+
<argument name="n" value="1"/>
68+
<argument name="prodOneSku" value="$$simpleProduct1.sku$$"/>
69+
<argument name="prodTwoSku" value=""/>
70+
<argument name="optionTitle" value="{{BundleProduct.optionTitle1}}"/>
71+
<argument name="inputType" value="{{BundleProduct.optionInputType1}}"/>
72+
</actionGroup>
73+
<!-- Save the bundle product -->
74+
<actionGroup ref="SaveProductFormActionGroup" stepKey="saveProductForm"/>
75+
<!-- Navigate to catalog product grid page -->
76+
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndexPageAfterProdSave"/>
77+
<!-- Search the created bundle product with sku -->
78+
<actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterBundleProductGridBySku">
79+
<argument name="sku" value="{{BundleProduct.sku}}"/>
80+
</actionGroup>
81+
<!-- Asserting with the special price value contains the percentage value -->
82+
<actionGroup ref="AdminAssertSpecialPriceAttributeValueOnProductGridPageActionGroup" stepKey="assertSpecialPricePercentageSymbol">
83+
<argument name="expectedValue" value="90.00%"/>
84+
</actionGroup>
85+
</test>
86+
</tests>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Bundle\Ui\DataProvider\Product\Modifier;
9+
10+
use Magento\Bundle\Model\Product\Type;
11+
use Magento\Directory\Model\Currency as DirectoryCurrency;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\Framework\Locale\ResolverInterface;
14+
use Magento\Ui\DataProvider\Modifier\ModifierInterface;
15+
use NumberFormatter;
16+
use Zend_Currency;
17+
use Zend_Currency_Exception;
18+
19+
/**
20+
* Modify product listing special price attributes
21+
*/
22+
class SpecialPriceAttributes implements ModifierInterface
23+
{
24+
/**
25+
* @var ResolverInterface
26+
*/
27+
private $localeResolver;
28+
29+
/**
30+
* @var array
31+
*/
32+
private $priceAttributeList;
33+
34+
/**
35+
* @var DirectoryCurrency
36+
*/
37+
private $directoryCurrency;
38+
39+
/**
40+
* PriceAttributes constructor.
41+
*
42+
* @param DirectoryCurrency $directoryCurrency
43+
* @param ResolverInterface $localeResolver
44+
* @param array $priceAttributeList
45+
*/
46+
public function __construct(
47+
DirectoryCurrency $directoryCurrency,
48+
ResolverInterface $localeResolver,
49+
array $priceAttributeList = []
50+
) {
51+
$this->directoryCurrency = $directoryCurrency;
52+
$this->localeResolver = $localeResolver;
53+
$this->priceAttributeList = $priceAttributeList;
54+
}
55+
56+
/**
57+
* @inheritdoc
58+
* @throws NoSuchEntityException
59+
* @throws Zend_Currency_Exception
60+
*/
61+
public function modifyData(array $data): array
62+
{
63+
if (empty($data) || empty($this->priceAttributeList)) {
64+
return $data;
65+
}
66+
$numberFormatter = new NumberFormatter(
67+
$this->localeResolver->getLocale(),
68+
NumberFormatter::PERCENT
69+
);
70+
$numberFormatter->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, 2);
71+
foreach ($data['items'] as &$item) {
72+
foreach ($this->priceAttributeList as $priceAttribute) {
73+
if (isset($item[$priceAttribute]) && $item['type_id'] == Type::TYPE_CODE) {
74+
$item[$priceAttribute] =
75+
$this->directoryCurrency->format(
76+
$item[$priceAttribute],
77+
['display' => Zend_Currency::NO_SYMBOL],
78+
false
79+
);
80+
$item[$priceAttribute] = $numberFormatter->format($item[$priceAttribute] / 100);
81+
}
82+
}
83+
}
84+
return $data;
85+
}
86+
87+
/**
88+
* @inheritdoc
89+
*/
90+
public function modifyMeta(array $meta): array
91+
{
92+
return $meta;
93+
}
94+
}

app/code/Magento/Bundle/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"magento/module-sales": "*",
2222
"magento/module-store": "*",
2323
"magento/module-tax": "*",
24-
"magento/module-ui": "*"
24+
"magento/module-ui": "*",
25+
"magento/module-directory": "*"
2526
},
2627
"suggest": {
2728
"magento/module-webapi": "*",

app/code/Magento/Bundle/etc/adminhtml/di.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,21 @@
4949
</argument>
5050
</arguments>
5151
</type>
52+
<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Listing\Modifier\Pool">
53+
<arguments>
54+
<argument name="modifiers" xsi:type="array">
55+
<item name="specialPriceAttributes" xsi:type="array">
56+
<item name="class" xsi:type="string">Magento\Bundle\Ui\DataProvider\Product\Modifier\SpecialPriceAttributes</item>
57+
<item name="sortOrder" xsi:type="number">20</item>
58+
</item>
59+
</argument>
60+
</arguments>
61+
</virtualType>
62+
<type name="Magento\Bundle\Ui\DataProvider\Product\Modifier\SpecialPriceAttributes">
63+
<arguments>
64+
<argument name="priceAttributeList" xsi:type="array">
65+
<item name="special_price" xsi:type="string">special_price</item>
66+
</argument>
67+
</arguments>
68+
</type>
5269
</config>

app/code/Magento/BundleGraphQl/Model/Resolver/Links/Collection.php

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
use Magento\Bundle\Model\ResourceModel\Selection\CollectionFactory;
1212
use Magento\Bundle\Model\ResourceModel\Selection\Collection as LinkCollection;
1313
use Magento\Framework\App\ObjectManager;
14+
use Magento\Framework\Exception\NoSuchEntityException;
15+
use Magento\Framework\Exception\RuntimeException;
1416
use Magento\Framework\GraphQl\Query\EnumLookup;
1517
use Magento\Framework\GraphQl\Query\Uid;
18+
use Magento\Catalog\Api\ProductRepositoryInterface;
19+
use Zend_Db_Select_Exception;
1620

1721
/**
1822
* Collection to fetch link data at resolution time.
@@ -47,20 +51,29 @@ class Collection
4751
/** @var Uid */
4852
private $uidEncoder;
4953

54+
/**
55+
* @var ProductRepositoryInterface
56+
*/
57+
private $productRepository;
58+
5059
/**
5160
* @param CollectionFactory $linkCollectionFactory
5261
* @param EnumLookup $enumLookup
5362
* @param Uid|null $uidEncoder
63+
* @param ProductRepositoryInterface|null $productRepository
5464
*/
5565
public function __construct(
5666
CollectionFactory $linkCollectionFactory,
5767
EnumLookup $enumLookup,
58-
Uid $uidEncoder = null
68+
Uid $uidEncoder = null,
69+
?ProductRepositoryInterface $productRepository = null
5970
) {
6071
$this->linkCollectionFactory = $linkCollectionFactory;
6172
$this->enumLookup = $enumLookup;
6273
$this->uidEncoder = $uidEncoder ?: ObjectManager::getInstance()
6374
->get(Uid::class);
75+
$this->productRepository = $productRepository ?: ObjectManager::getInstance()
76+
->get(ProductRepositoryInterface::class);
6477
}
6578

6679
/**
@@ -85,6 +98,9 @@ public function addIdFilters(int $optionId, int $parentId) : void
8598
*
8699
* @param int $optionId
87100
* @return array
101+
* @throws NoSuchEntityException
102+
* @throws RuntimeException
103+
* @throws Zend_Db_Select_Exception
88104
*/
89105
public function getLinksForOptionId(int $optionId) : array
90106
{
@@ -101,6 +117,10 @@ public function getLinksForOptionId(int $optionId) : array
101117
* Fetch link data and return in array format. Keys for links will be their option Ids.
102118
*
103119
* @return array
120+
* @throws NoSuchEntityException
121+
* @throws RuntimeException
122+
* @throws Zend_Db_Select_Exception
123+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
104124
*/
105125
private function fetch() : array
106126
{
@@ -123,26 +143,33 @@ private function fetch() : array
123143

124144
/** @var Selection $link */
125145
foreach ($linkCollection as $link) {
146+
$productDetails = [];
126147
$data = $link->getData();
127-
$formattedLink = [
128-
'price' => $link->getSelectionPriceValue(),
129-
'position' => $link->getPosition(),
130-
'id' => $link->getSelectionId(),
131-
'uid' => $this->uidEncoder->encode((string) $link->getSelectionId()),
132-
'qty' => (float)$link->getSelectionQty(),
133-
'quantity' => (float)$link->getSelectionQty(),
134-
'is_default' => (bool)$link->getIsDefault(),
135-
'price_type' => $this->enumLookup->getEnumValueFromField(
136-
'PriceTypeEnum',
137-
(string)$link->getSelectionPriceType()
138-
) ?: 'DYNAMIC',
139-
'can_change_quantity' => $link->getSelectionCanChangeQty(),
140-
];
141-
$data = array_replace($data, $formattedLink);
142-
if (!isset($this->links[$link->getOptionId()])) {
143-
$this->links[$link->getOptionId()] = [];
148+
if (isset($data['product_id'])) {
149+
$productDetails = $this->productRepository->getById($data['product_id']);
150+
}
151+
152+
if ($productDetails && $productDetails->getIsSalable()) {
153+
$formattedLink = [
154+
'price' => $link->getSelectionPriceValue(),
155+
'position' => $link->getPosition(),
156+
'id' => $link->getSelectionId(),
157+
'uid' => $this->uidEncoder->encode((string)$link->getSelectionId()),
158+
'qty' => (float)$link->getSelectionQty(),
159+
'quantity' => (float)$link->getSelectionQty(),
160+
'is_default' => (bool)$link->getIsDefault(),
161+
'price_type' => $this->enumLookup->getEnumValueFromField(
162+
'PriceTypeEnum',
163+
(string)$link->getSelectionPriceType()
164+
) ?: 'DYNAMIC',
165+
'can_change_quantity' => $link->getSelectionCanChangeQty(),
166+
];
167+
$data = array_replace($data, $formattedLink);
168+
if (!isset($this->links[$link->getOptionId()])) {
169+
$this->links[$link->getOptionId()] = [];
170+
}
171+
$this->links[$link->getOptionId()][] = $data;
144172
}
145-
$this->links[$link->getOptionId()][] = $data;
146173
}
147174

148175
return $this->links;

app/code/Magento/Catalog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ProductCategoryCondition.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionInterface;
1111
use Magento\Catalog\Model\ResourceModel\Product\Collection;
1212
use Magento\Framework\Api\Filter;
13-
use Magento\Framework\Data\Collection\AbstractDb;
1413
use Magento\Framework\Exception\NoSuchEntityException as CategoryDoesNotExistException;
1514

1615
/**
@@ -63,12 +62,12 @@ public function build(Filter $filter): string
6362
)->where(
6463
$this->resourceConnection->getConnection()->prepareSqlCondition(
6564
'cat.category_id',
66-
[$this->mapConditionType($filter->getConditionType()) => $this->getCategoryIds($filter)]
65+
['in' => $this->getCategoryIds($filter)]
6766
)
6867
);
6968

7069
$selectCondition = [
71-
'in' => $categorySelect
70+
$this->mapConditionType($filter->getConditionType()) => $categorySelect
7271
];
7372

7473
return $this->resourceConnection->getConnection()
@@ -116,12 +115,7 @@ private function getCategoryIds(Filter $filter): array
116115
*/
117116
private function mapConditionType(string $conditionType): string
118117
{
119-
$conditionsMap = [
120-
'eq' => 'in',
121-
'neq' => 'nin',
122-
'like' => 'in',
123-
'nlike' => 'nin',
124-
];
125-
return $conditionsMap[$conditionType] ?? $conditionType;
118+
$ninConditions = ['nin', 'neq', 'nlike'];
119+
return in_array($conditionType, $ninConditions, true) ? 'nin' : 'in';
126120
}
127121
}

0 commit comments

Comments
 (0)