Skip to content

Commit 103dbaf

Browse files
committed
PWA-1299: [Graphql] Unable to update the items of a bundle-product in a wishlist
* Updated bundle option response to include uid * Updated API test to obtain bundle option uids from GraphQL query * Fixed issue where selected_options were removed when omitted from input
1 parent 0e1ebf2 commit 103dbaf

File tree

4 files changed

+109
-76
lines changed

4 files changed

+109
-76
lines changed

app/code/Magento/Bundle/Model/Product/BundleOptionDataProvider.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\Bundle\Model\Option;
1212
use Magento\Catalog\Model\Product;
1313
use Magento\Catalog\Model\Product\Configuration\Item\ItemInterface;
14+
use Magento\Framework\GraphQl\Query\Uid;
1415
use Magento\Framework\Pricing\Helper\Data;
1516
use Magento\Framework\Serialize\SerializerInterface;
1617

@@ -19,6 +20,11 @@
1920
*/
2021
class BundleOptionDataProvider
2122
{
23+
/**
24+
* Option type name
25+
*/
26+
private const OPTION_TYPE = 'bundle';
27+
2228
/**
2329
* @var Data
2430
*/
@@ -34,19 +40,27 @@ class BundleOptionDataProvider
3440
*/
3541
private $configuration;
3642

43+
/**
44+
* @var Uid
45+
*/
46+
private $uidEncoder;
47+
3748
/**
3849
* @param Data $pricingHelper
3950
* @param SerializerInterface $serializer
4051
* @param Configuration $configuration
52+
* @param Uid $uidEncoder
4153
*/
4254
public function __construct(
4355
Data $pricingHelper,
4456
SerializerInterface $serializer,
45-
Configuration $configuration
57+
Configuration $configuration,
58+
Uid $uidEncoder
4659
) {
4760
$this->pricingHelper = $pricingHelper;
4861
$this->serializer = $serializer;
4962
$this->configuration = $configuration;
63+
$this->uidEncoder = $uidEncoder;
5064
}
5165

5266
/**
@@ -100,8 +114,15 @@ private function buildBundleOptions(array $bundleOptions, ItemInterface $item):
100114
continue;
101115
}
102116

117+
$optionDetails = [
118+
self::OPTION_TYPE,
119+
$bundleOption->getOptionId()
120+
];
121+
$uidString = implode('/', $optionDetails);
122+
103123
$options[] = [
104124
'id' => $bundleOption->getId(),
125+
'uid' => $this->uidEncoder->encode($uidString),
105126
'label' => $bundleOption->getTitle(),
106127
'type' => $bundleOption->getType(),
107128
'values' => $this->buildBundleOptionValues($bundleOption->getSelections(), $item),
@@ -130,10 +151,19 @@ private function buildBundleOptionValues(array $selections, ItemInterface $item)
130151
continue;
131152
}
132153

154+
$optionValueDetails = [
155+
self::OPTION_TYPE,
156+
$selection->getOptionId(),
157+
$selection->getSelectionId(),
158+
(int) $selection->getSelectionQty()
159+
];
160+
$uidString = implode('/', $optionValueDetails);
161+
133162
$selectionPrice = $this->configuration->getSelectionFinalPrice($item, $selection);
134163
$values[] = [
135-
'label' => $selection->getName(),
136164
'id' => $selection->getSelectionId(),
165+
'uid' => $this->uidEncoder->encode($uidString),
166+
'label' => $selection->getName(),
137167
'quantity' => $qty,
138168
'price' => $this->pricingHelper->currency($selectionPrice, false, false),
139169
];

app/code/Magento/WishlistGraphQl/Model/Resolver/UpdateProductsInWishlist.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,3 @@ private function getWishlist(?int $wishlistId, ?int $customerId): Wishlist
170170
return $wishlist;
171171
}
172172
}
173-

app/code/Magento/WishlistGraphQl/Model/UpdateWishlistItem.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,11 @@ private function getUpdatedOptions(WishlistItemData $wishlistItemData, Item $wis
105105
);
106106
}
107107

108-
// Create a buy request with the updated wishlist item data
109-
$updatedBuyRequest = $this->buyRequestBuilder
108+
// Update the buy request using the wishlist item data. Use existing values for unspecified options.
109+
$newBuyRequest = $this->buyRequestBuilder
110110
->build($wishlistItemData)
111111
->setData('action', 'updateItem');
112+
$updatedBuyRequest = $wishlistItemToUpdate->getBuyRequest()->addData($newBuyRequest->toArray());
112113

113114
// Get potential products to add to the cart for the product type using the updated buy request
114115
$wishlistItemProduct->setWishlistStoreId($wishlistItemToUpdate->getStoreId());
@@ -170,4 +171,3 @@ public function prepareOutput(Wishlist $wishlist): WishlistOutput
170171
return $output;
171172
}
172173
}
173-

dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/UpdateBundleProductsFromWishlistTest.php

Lines changed: 74 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@
88
namespace Magento\GraphQl\Wishlist;
99

1010
use Exception;
11-
use Magento\Bundle\Model\Selection;
1211
use Magento\Framework\Exception\AuthenticationException;
1312
use Magento\Integration\Api\CustomerTokenServiceInterface;
1413
use Magento\TestFramework\Helper\Bootstrap;
1514
use Magento\TestFramework\TestCase\GraphQlAbstract;
1615
use Magento\Wishlist\Model\WishlistFactory;
17-
use Magento\Bundle\Model\Option;
18-
use Magento\Bundle\Model\Product\Type;
1916
use Magento\Catalog\Api\ProductRepositoryInterface;
20-
use Magento\Catalog\Model\Product;
2117
use Magento\Ui\Component\Form\Element\Select;
2218

2319
/**
@@ -59,7 +55,6 @@ protected function setUp(): void
5955
* @magentoConfigFixture default_store wishlist/general/active 1
6056
* @magentoApiDataFixture Magento/Customer/_files/customer.php
6157
* @magentoApiDataFixture Magento/Bundle/_files/bundle_product_dropdown_options.php
62-
*
6358
* @throws Exception
6459
*/
6560
public function testUpdateBundleProductWithOptions(): void
@@ -73,10 +68,8 @@ public function testUpdateBundleProductWithOptions(): void
7368
// Set the new values to update the wishlist item with
7469
$newQuantity = 5;
7570
$newDescription = 'This is a test.';
76-
$newBundleOptionUid = $this->generateBundleOptionUid(
77-
'bundle-product-dropdown-options',
78-
false
79-
);
71+
$bundleProductOptions = $this->getBundleProductOptions('bundle-product-dropdown-options');
72+
$newBundleOptionUid = $bundleProductOptions[1]["uid"];
8073

8174
// Update the newly added wishlist item as the fixture customer
8275
$query = $this->getUpdateQuery(
@@ -110,28 +103,12 @@ public function testUpdateBundleProductWithOptions(): void
110103
// Assert that the selected value for this bundle option is updated
111104
self::assertNotEmpty($responseBundleOption['values']);
112105
$responseOptionSelection = $responseBundleOption['values'][0];
106+
self::assertEquals($newBundleOptionUid, $responseOptionSelection['uid']);
113107
self::assertEquals('Simple Product2', $responseOptionSelection['label']);
114108
self::assertEquals(1, $responseOptionSelection['quantity']);
115109
self::assertEquals(10, $responseOptionSelection['price']);
116110
}
117111

118-
/**
119-
* Authentication header map
120-
*
121-
* @param string $username
122-
* @param string $password
123-
*
124-
* @return array
125-
*
126-
* @throws AuthenticationException
127-
*/
128-
private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array
129-
{
130-
$customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password);
131-
132-
return ['Authorization' => 'Bearer ' . $customerToken];
133-
}
134-
135112
/**
136113
* Returns GraphQl mutation string
137114
*
@@ -140,7 +117,6 @@ private function getHeaderMap(string $username = 'customer@example.com', string
140117
* @param string $description
141118
* @param string $bundleOptions
142119
* @param int $wishlistId
143-
*
144120
* @return string
145121
*/
146122
private function getUpdateQuery(
@@ -182,10 +158,12 @@ private function getUpdateQuery(
182158
... on BundleWishlistItem {
183159
bundle_options {
184160
id
161+
uid
185162
label
186163
type
187164
values {
188165
id
166+
uid
189167
label
190168
quantity
191169
price
@@ -201,66 +179,29 @@ private function getUpdateQuery(
201179
}
202180

203181
/**
204-
* Generate the uid for the specified bundle option selection.
182+
* Add a product to the to the wishlist.
205183
*
206-
* @param string $bundleProductSku
207-
* @param bool $useFirstSelection
208-
* @return string
209-
*/
210-
private function generateBundleOptionUid(string $bundleProductSku, bool $useFirstSelection): string
211-
{
212-
$product = $this->productRepository->get($bundleProductSku);
213-
214-
/** @var Type $typeInstance */
215-
$typeInstance = $product->getTypeInstance();
216-
$typeInstance->setStoreFilter($product->getStoreId(), $product);
217-
218-
/** @var Option $option */
219-
$option = $typeInstance->getOptionsCollection($product)->getLastItem();
220-
$optionId = (int) $option->getId();
221-
222-
/** @var Selection $selection */
223-
$selections = $typeInstance->getSelectionsCollection([$option->getId()], $product);
224-
if ($useFirstSelection) {
225-
$selection = $selections->getFirstItem();
226-
} else {
227-
$selection = $selections->getLastItem();
228-
}
229-
230-
$selectionId = (int) $selection->getSelectionId();
231-
232-
return base64_encode("bundle/$optionId/$selectionId/1");
233-
}
234-
235-
/**
236-
* @magentoConfigFixture default_store wishlist/general/active 1
237-
* @magentoApiDataFixture Magento/Customer/_files/customer.php
238-
* @magentoApiDataFixture Magento/Bundle/_files/product_1.php
239-
*
240-
* @throws Exception
241-
* return array
184+
* @return array
185+
* @throws AuthenticationException
242186
*/
243187
private function addProductToWishlist(): array
244188
{
245189
$bundleProductSku = 'bundle-product-dropdown-options';
190+
$bundleProductOptions = $this->getBundleProductOptions($bundleProductSku);
191+
$initialBundleOptionUid = $bundleProductOptions[0]["uid"];
246192
$initialQuantity = 2;
247-
$initialBundleOptionUid = $this->generateBundleOptionUid(
248-
$bundleProductSku,
249-
true
250-
);
251193

252194
$query = $this->getAddQuery($bundleProductSku, $initialQuantity, $initialBundleOptionUid);
253195
return $this->graphQlMutation($query, [], '', $this->getHeaderMap());
254196
}
255197

256198
/**
257-
* Returns GraphQl add mutation string
199+
* Returns the GraphQl mutation for adding an item to the wishlist.
258200
*
259201
* @param string $sku
260202
* @param int $qty
261203
* @param string $bundleOptions
262204
* @param int $wishlistId
263-
*
264205
* @return string
265206
*/
266207
private function getAddQuery(
@@ -317,5 +258,68 @@ private function getAddQuery(
317258
}
318259
MUTATION;
319260
}
261+
262+
/**
263+
* Get the available options for the specified bundle product.
264+
*
265+
* @param string $bundleProductSku
266+
* @return array
267+
*/
268+
private function getBundleProductOptions(string $bundleProductSku)
269+
{
270+
$query = $this->getBundleProductSearchQuery($bundleProductSku);
271+
$response = $this->graphQlQuery($query);
272+
273+
$bundleProduct = $response["products"]["items"][0];
274+
$bundleProductOptions = $bundleProduct["items"][0]["options"];
275+
276+
return $bundleProductOptions;
277+
}
278+
279+
/**
280+
* Returns the GraphQl product search query for a bundle product.
281+
*
282+
* @param string $bundleProductSku
283+
* @return string
284+
*/
285+
private function getBundleProductSearchQuery(string $bundleProductSku): string
286+
{
287+
return <<<QUERY
288+
query {
289+
products(search: "{$bundleProductSku}"){
290+
items {
291+
uid
292+
sku
293+
name
294+
... on BundleProduct {
295+
items {
296+
uid
297+
title
298+
type
299+
options {
300+
id
301+
uid
302+
}
303+
}
304+
}
305+
}
306+
}
320307
}
308+
QUERY;
309+
}
321310

311+
/**
312+
* Authentication header map
313+
*
314+
* @param string $username
315+
* @param string $password
316+
* @return array
317+
* @throws AuthenticationException
318+
*/
319+
private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array
320+
{
321+
$customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password);
322+
323+
return ['Authorization' => 'Bearer ' . $customerToken];
324+
}
325+
}

0 commit comments

Comments
 (0)