Skip to content

Commit 068168f

Browse files
committed
Merge remote-tracking branch 'l3/ACP2E-666' into PR_L3_05_04_2022
2 parents 9fa9af8 + f8a319e commit 068168f

File tree

3 files changed

+301
-0
lines changed

3 files changed

+301
-0
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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\ConfigurableProductGraphQl\Plugin\Quote;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
12+
use Magento\ConfigurableProductGraphQl\Model\Cart\BuyRequest\SuperAttributeDataProvider;
13+
use Magento\Framework\DataObject;
14+
use Magento\Framework\Exception\LocalizedException;
15+
use Magento\Framework\Exception\NoSuchEntityException;
16+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
17+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
18+
use Magento\Quote\Model\Quote;
19+
20+
/**
21+
* Intercepts data before update cart and check customized options available
22+
* and update super attribute data for configurable product
23+
*/
24+
class UpdateCustomizedOptions
25+
{
26+
/**
27+
* @var ProductRepositoryInterface
28+
*/
29+
private $productRepository;
30+
31+
/**
32+
* @var SuperAttributeDataProvider
33+
*/
34+
private $superAttributeDataProvider;
35+
36+
/**
37+
* @param ProductRepositoryInterface $productRepository
38+
* @param SuperAttributeDataProvider $superAttributeDataProvider
39+
*/
40+
public function __construct(
41+
ProductRepositoryInterface $productRepository,
42+
SuperAttributeDataProvider $superAttributeDataProvider
43+
) {
44+
$this->productRepository = $productRepository;
45+
$this->superAttributeDataProvider = $superAttributeDataProvider;
46+
}
47+
48+
/**
49+
* Parses the product data after update cart event and checking customized options super attribute
50+
*
51+
* @param Quote $subject
52+
* @param int $itemId
53+
* @param DataObject $buyRequest
54+
* @param null|array|DataObject $params
55+
* @return void
56+
* @throws LocalizedException
57+
* @throws NoSuchEntityException
58+
* @throws GraphQlInputException
59+
* @throws GraphQlNoSuchEntityException
60+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
61+
*/
62+
public function beforeUpdateItem(
63+
Quote $subject,
64+
int $itemId,
65+
DataObject $buyRequest,
66+
DataObject $params = null
67+
): void {
68+
$item = $subject->getItemById($itemId);
69+
if ($item) {
70+
$productId = $item->getProduct()->getId();
71+
$product = clone $this->productRepository->getById($productId, false, $subject->getStore()->getId());
72+
if ($item->getProductType() === Configurable::TYPE_CODE && count($product->getOptions()) > 0) {
73+
$cartItemData = [];
74+
$cartItemData['model'] = $subject;
75+
if (count($item->getChildren()) > 0) {
76+
$currentItem = current($item->getChildren());
77+
$cartItemData['data']['sku'] = $currentItem->getSku();
78+
} else {
79+
$cartItemData['data']['sku'] = $item->getSku();
80+
}
81+
$cartItemData['data']['quantity'] = $buyRequest->getQty();
82+
$cartItemData['parent_sku'] = $product->getSku();
83+
$superAttributeDetails = $this->superAttributeDataProvider->execute($cartItemData);
84+
$buyRequest->addData($superAttributeDetails);
85+
}
86+
}
87+
}
88+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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\ConfigurableProductGraphQl\Test\Unit\Plugin\Quote;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Catalog\Model\Product\Type;
13+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
14+
use Magento\ConfigurableProductGraphQl\Model\Cart\BuyRequest\SuperAttributeDataProvider;
15+
use Magento\Framework\DataObject;
16+
use Magento\Framework\Exception\LocalizedException;
17+
use Magento\Framework\Exception\NoSuchEntityException;
18+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
19+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
20+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
21+
use Magento\ConfigurableProductGraphQl\Plugin\Quote\UpdateCustomizedOptions;
22+
use Magento\Quote\Model\Quote as Quote;
23+
use Magento\Quote\Model\Quote\Item as QuoteItem;
24+
use Magento\Store\Model\Store;
25+
use PHPUnit\Framework\MockObject\MockObject;
26+
use PHPUnit\Framework\TestCase;
27+
28+
/**
29+
* Test cases for data before update cart and check customized options available
30+
* and update super attribute data for configurable product
31+
*
32+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
33+
*/
34+
class UpdateCustomizedOptionsTest extends TestCase
35+
{
36+
/** @var UpdateCustomizedOptions */
37+
private $model;
38+
39+
/** @var QuoteItem|MockObject */
40+
private $quoteItem;
41+
42+
/** @var Quote|MockObject */
43+
private $quote;
44+
45+
/** @var Product|MockObject */
46+
private $productMock;
47+
48+
/** @var ObjectManagerHelper */
49+
private $objectManagerHelper;
50+
51+
/**
52+
* @var ProductRepositoryInterface|MockObject
53+
*/
54+
private $productRepositoryMock;
55+
56+
/**
57+
* @var Store|MockObject
58+
*/
59+
private $storeMock;
60+
61+
/**
62+
* @var SuperAttributeDataProvider|MockObject
63+
*/
64+
private $superAttributeDataProviderMock;
65+
66+
protected function setUp(): void
67+
{
68+
$this->productRepositoryMock = $this->getMockBuilder(ProductRepositoryInterface::class)
69+
->disableOriginalConstructor()
70+
->getMock();
71+
72+
$this->productMock = $this->getMockBuilder(Product::class)
73+
->disableOriginalConstructor()
74+
->getMock();
75+
76+
$this->storeMock = $this->getMockBuilder(Store::class)
77+
->disableOriginalConstructor()
78+
->getMock();
79+
80+
$this->superAttributeDataProviderMock = $this->getMockBuilder(SuperAttributeDataProvider::class)
81+
->disableOriginalConstructor()
82+
->getMock();
83+
84+
$this->quote = $this->getMockBuilder(Quote::class)
85+
->disableOriginalConstructor()
86+
->setMethods(['getStore', 'getItemById'])
87+
->getMock();
88+
89+
$this->quoteItem = $this->getMockBuilder(QuoteItem::class)
90+
->disableOriginalConstructor()
91+
->onlyMethods(['getProduct', 'getProductType', 'getChildren'])
92+
->setMethods(['getQty', 'getSku'])
93+
->getMock();
94+
$this->objectManagerHelper = new ObjectManagerHelper($this);
95+
$this->model = $this->objectManagerHelper->getObject(
96+
UpdateCustomizedOptions::class,
97+
[
98+
'productRepository' => $this->productRepositoryMock,
99+
'superAttributeDataProvider' => $this->superAttributeDataProviderMock
100+
]
101+
);
102+
}
103+
104+
/**
105+
* Test buyRequest object for customized options before update
106+
*
107+
* @param array $superAttributeDetails
108+
* @param DataObject $buyRequest
109+
* @param array $itemDetails
110+
* @param string $productType
111+
* @param array $productOptions
112+
* @param DataObject $productChildren
113+
* @param bool $quoteHasItem
114+
* @param int|null $productId
115+
* @throws GraphQlInputException
116+
* @throws GraphQlNoSuchEntityException
117+
* @throws LocalizedException
118+
* @throws NoSuchEntityException
119+
* @dataProvider updateCustomizedOptionsDataProvider
120+
*/
121+
public function testBeforeUpdateItem(
122+
array $superAttributeDetails,
123+
DataObject $buyRequest,
124+
array $itemDetails,
125+
string $productType,
126+
array $productOptions,
127+
DataObject $productChildren,
128+
bool $quoteHasItem = true,
129+
?int $productId = null
130+
) {
131+
$params = new DataObject([]);
132+
$this->productMock->expects($this->any())
133+
->method('getId')
134+
->willReturn($productId);
135+
$this->productMock->expects($this->any())
136+
->method('getSku')
137+
->willReturn($itemDetails['parent_sku']);
138+
$this->quoteItem->expects($this->any())
139+
->method('getProduct')
140+
->willReturn($this->productMock);
141+
142+
$this->quote->expects($this->any())
143+
->method('getStore')
144+
->willReturn($this->storeMock);
145+
146+
$this->storeMock->expects($this->any())
147+
->method('getId')
148+
->willReturn($itemDetails['store_id']);
149+
150+
$this->quote->expects($this->once())
151+
->method('getItemById')
152+
->willReturn($quoteHasItem ? $this->quoteItem : false);
153+
154+
$this->productRepositoryMock->expects($this->any())
155+
->method('getById')
156+
->with($productId)
157+
->willReturn($this->productMock);
158+
159+
$this->productMock->expects($this->any())
160+
->method('getOptions')
161+
->willReturn([$productOptions]);
162+
163+
$this->quoteItem->expects($this->any())
164+
->method('getProductType')
165+
->willReturn($productType);
166+
167+
$this->quoteItem->expects($this->any())
168+
->method('getChildren')
169+
->willReturn([$productChildren]);
170+
171+
$this->quoteItem->expects($this->any())
172+
->method('getSku')
173+
->willReturn($itemDetails['sku']);
174+
175+
$this->superAttributeDataProviderMock->expects($this->any())
176+
->method('execute')
177+
->willReturn($superAttributeDetails);
178+
179+
$this->model->beforeUpdateItem($this->quote, $itemDetails['item_id'], $buyRequest, $params);
180+
}
181+
182+
/**
183+
* @return array
184+
*/
185+
public function updateCustomizedOptionsDataProvider()
186+
{
187+
return [
188+
'test customized options for simple product' => [
189+
[],
190+
new DataObject(['sku' => 'simple', 'quantity' => 1]),
191+
['item_id' => 1, 'store_id' => 1, 'parent_sku' => null, 'sku' => 'simple'] ,
192+
Type::TYPE_SIMPLE,
193+
[],
194+
new DataObject([]),
195+
false,
196+
5
197+
],
198+
'test customized options for configurable product' => [
199+
['1' => 14, '5' => 10],
200+
new DataObject(['sku' => 'configurable', 'quantity' => 10]),
201+
['item_id' => 2, 'store_id' => 1, 'parent_sku' => 'configurable', 'sku' => 'configurable-child'] ,
202+
Configurable::TYPE_CODE,
203+
['option1'],
204+
new DataObject(['sku' => 'child1']),
205+
true,
206+
7
207+
]
208+
];
209+
}
210+
}

app/code/Magento/ConfigurableProductGraphQl/etc/graphql/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,7 @@
8282
<type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection">
8383
<plugin name="add_stock_information" type="Magento\ConfigurableProductGraphQl\Plugin\AddStockStatusToCollection" />
8484
</type>
85+
<type name="Magento\Quote\Model\Quote">
86+
<plugin name="update_customized_options" type="Magento\ConfigurableProductGraphQl\Plugin\Quote\UpdateCustomizedOptions"/>
87+
</type>
8588
</config>

0 commit comments

Comments
 (0)