Skip to content

Commit beb7f44

Browse files
authored
LYNX-399: Placeholder thumbnail returns when a simple product added to cart within a grouped product
1 parent 4681ce9 commit beb7f44

File tree

2 files changed

+261
-20
lines changed

2 files changed

+261
-20
lines changed

app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<?php
22
/**
3-
* Grouped product type implementation
4-
*
53
* Copyright © Magento, Inc. All rights reserved.
64
* See COPYING.txt for license details.
75
*/
86
namespace Magento\GroupedProduct\Model\Product\Type;
97

108
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Catalog\Model\Product;
10+
use Magento\Framework\DataObject;
1111
use Magento\Framework\File\UploaderFactory;
1212

1313
/**
@@ -19,7 +19,7 @@
1919
*/
2020
class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
2121
{
22-
const TYPE_CODE = 'grouped';
22+
public const TYPE_CODE = 'grouped';
2323

2424
/**
2525
* Cache key for Associated Products
@@ -57,15 +57,11 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
5757
protected $_canConfigure = true;
5858

5959
/**
60-
* Catalog product status
61-
*
6260
* @var \Magento\Catalog\Model\Product\Attribute\Source\Status
6361
*/
6462
protected $_catalogProductStatus;
6563

6664
/**
67-
* Store manager
68-
*
6965
* @var \Magento\Store\Model\StoreManagerInterface
7066
*/
7167
protected $_storeManager;
@@ -201,7 +197,7 @@ public function getParentIdsByChild($childId)
201197
/**
202198
* Retrieve array of associated products
203199
*
204-
* @param \Magento\Catalog\Model\Product $product
200+
* @param Product $product
205201
* @return array
206202
*/
207203
public function getAssociatedProducts($product)
@@ -214,7 +210,16 @@ public function getAssociatedProducts($product)
214210
$collection = $this->getAssociatedProductCollection(
215211
$product
216212
)->addAttributeToSelect(
217-
['name', 'price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id', 'image']
213+
[
214+
'name',
215+
'price',
216+
'special_price',
217+
'special_from_date',
218+
'special_to_date',
219+
'tax_class_id',
220+
'image',
221+
'thumbnail'
222+
]
218223
)->addFilterByRequiredOptions()->setPositionOrder()->addStoreFilter(
219224
$this->getStoreFilter($product)
220225
)->addAttributeToFilter(
@@ -347,22 +352,34 @@ protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $pr
347352
return __('Please specify the quantity of product(s).')->render();
348353
}
349354
foreach ($associatedProducts as $subProduct) {
350-
if (!isset($productsInfo[$subProduct->getId()])) {
351-
if ($isStrictProcessMode && !$subProduct->getQty() && $subProduct->isSalable()) {
352-
return __('Please specify the quantity of product(s).')->render();
353-
}
354-
if (isset($buyRequest['qty']) && !isset($buyRequest['super_group'])) {
355-
$subProductQty = (float)$subProduct->getQty() * (float)$buyRequest['qty'];
356-
$productsInfo[$subProduct->getId()] = $subProduct->isSalable() ? $subProductQty : 0;
357-
} else {
358-
$productsInfo[$subProduct->getId()] = $subProduct->isSalable() ? (float)$subProduct->getQty() : 0;
359-
}
355+
if (isset($productsInfo[$subProduct->getId()])) {
356+
continue;
357+
}
358+
if ($isStrictProcessMode && !$subProduct->getQty() && $subProduct->isSalable()) {
359+
return __('Please specify the quantity of product(s).')->render();
360360
}
361+
$productsInfo[$subProduct->getId()] = $this->getSubProductQtyInfo($buyRequest, $subProduct);
361362
}
362-
363363
return $productsInfo;
364364
}
365365

366+
/**
367+
* Gets qty info for sub product in group
368+
*
369+
* @param DataObject $buyRequest
370+
* @param Product $subProduct
371+
* @return float
372+
*/
373+
private function getSubProductQtyInfo(
374+
DataObject $buyRequest,
375+
Product $subProduct,
376+
): float {
377+
if (isset($buyRequest['qty']) && !isset($buyRequest['super_group'])) {
378+
return $subProduct->isSalable() ? $subProduct->getQty() * (float)$buyRequest['qty'] : 0.0;
379+
}
380+
return $subProduct->isSalable() ? $subProduct->getQty() : 0.0;
381+
}
382+
366383
/**
367384
* Prepare product and its configuration to be added to some products list.
368385
*
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained from
13+
* Adobe.
14+
*/
15+
declare(strict_types=1);
16+
17+
namespace Magento\GraphQl\Quote;
18+
19+
use Magento\TestFramework\Fixture\Config as ConfigFixture;
20+
use Magento\Catalog\Test\Fixture\Category as CategoryFixture;
21+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
22+
use Magento\GroupedProduct\Test\Fixture\Product as GroupedProductFixture;
23+
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
24+
use Magento\Quote\Test\Fixture\QuoteIdMask as QuoteMaskFixture;
25+
use Magento\TestFramework\Fixture\DataFixture;
26+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
27+
use Magento\TestFramework\TestCase\GraphQlAbstract;
28+
29+
/**
30+
* Test adding grouped products returns default thumbnail/product image thumbnail
31+
*/
32+
class AddGroupedProductToCartThumbnailTest extends GraphQlAbstract
33+
{
34+
private const DEFAULT_THUMBNAIL_PATH = 'Magento_Catalog/images/product/placeholder/thumbnail.jpg';
35+
36+
#[
37+
DataFixture(CategoryFixture::class, ['name' => 'Category'], 'category'),
38+
DataFixture(
39+
ProductFixture::class,
40+
[
41+
'name' => 'Product 1',
42+
'sku' => 'product-1',
43+
'category_ids' => ['$category.id$'],
44+
'price' => 10
45+
],
46+
'product1'
47+
),
48+
DataFixture(
49+
ProductFixture::class,
50+
[
51+
'name' => 'Product 2',
52+
'sku' => 'product-2',
53+
'category_ids' => ['$category.id$'],
54+
'price' => 15
55+
],
56+
'product2'
57+
),
58+
DataFixture(
59+
GroupedProductFixture::class,
60+
[
61+
'sku' => 'grouped-product',
62+
'category_ids' => ['$category.id$'],
63+
'product_links' => [
64+
['sku' => '$product1.sku$', 'qty' => 1],
65+
['sku' => '$product2.sku$', 'qty' => 1]
66+
]
67+
],
68+
'grouped-product'
69+
),
70+
DataFixture(GuestCartFixture::class, as: 'cart'),
71+
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
72+
]
73+
public function testAddGroupedProductToCartWithoutImageShouldUseThumbnail()
74+
{
75+
$cartId = DataFixtureStorageManager::getStorage()->get('quoteIdMask')->getMaskedId();
76+
$groupedProductId = DataFixtureStorageManager::getStorage()->get('grouped-product')->getSku();
77+
$response = $this->graphQlMutation($this->getMutation($cartId, $groupedProductId));
78+
79+
$this->assertArrayHasKey('addProductsToCart', $response);
80+
$this->assertEquals(2, count($response['addProductsToCart']['cart']['itemsV2']['items']));
81+
$this->assertStringContainsString(
82+
self::DEFAULT_THUMBNAIL_PATH,
83+
$response['addProductsToCart']['cart']['itemsV2']['items'][0]['product']['thumbnail']['url']
84+
);
85+
$this->assertStringContainsString(
86+
self::DEFAULT_THUMBNAIL_PATH,
87+
$response['addProductsToCart']['cart']['itemsV2']['items'][1]['product']['thumbnail']['url']
88+
);
89+
}
90+
91+
#[
92+
ConfigFixture('checkout/cart/grouped_product_image', 'itself'),
93+
DataFixture(CategoryFixture::class, ['name' => 'Category'], 'category'),
94+
DataFixture(
95+
ProductFixture::class,
96+
[
97+
'name' => 'Product 1',
98+
'sku' => 'product-1',
99+
'category_ids' => ['$category.id$'],
100+
'price' => 10,
101+
'media_gallery_entries' => [
102+
[
103+
'label' => 'image',
104+
'media_type' => 'image',
105+
'position' => 1,
106+
'disabled' => false,
107+
'types' => [
108+
'image',
109+
'small_image',
110+
'thumbnail'
111+
],
112+
'file' => '/m/product1.jpg',
113+
],
114+
],
115+
],
116+
'product1'
117+
),
118+
DataFixture(
119+
ProductFixture::class,
120+
[
121+
'name' => 'Product 2',
122+
'sku' => 'product-2',
123+
'category_ids' => ['$category.id$'],
124+
'price' => 15,
125+
'media_gallery_entries' => [
126+
[
127+
'label' => 'image',
128+
'media_type' => 'image',
129+
'position' => 1,
130+
'disabled' => false,
131+
'types' => [
132+
'image',
133+
'small_image',
134+
'thumbnail'
135+
],
136+
'file' => '/m/product2.jpg',
137+
],
138+
],
139+
],
140+
'product2'
141+
),
142+
DataFixture(
143+
GroupedProductFixture::class,
144+
[
145+
'sku' => 'grouped-product',
146+
'category_ids' => ['$category.id$'],
147+
'product_links' => [
148+
['sku' => '$product1.sku$', 'qty' => 1],
149+
['sku' => '$product2.sku$', 'qty' => 1]
150+
]
151+
],
152+
'grouped-product'
153+
),
154+
DataFixture(GuestCartFixture::class, as: 'cart'),
155+
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
156+
]
157+
public function testAddGroupedProductToCartWithImageShouldUseProductImageAsThumbnail()
158+
{
159+
$cartId = DataFixtureStorageManager::getStorage()->get('quoteIdMask')->getMaskedId();
160+
$groupedProductId = DataFixtureStorageManager::getStorage()->get('grouped-product')->getSku();
161+
$product1 = DataFixtureStorageManager::getStorage()->get('product1');
162+
$product2 = DataFixtureStorageManager::getStorage()->get('product2');
163+
164+
$response = $this->graphQlMutation($this->getMutation($cartId, $groupedProductId));
165+
166+
$this->assertArrayHasKey('addProductsToCart', $response);
167+
$this->assertEquals(2, count($response['addProductsToCart']['cart']['itemsV2']['items']));
168+
$this->assertStringContainsString(
169+
$product1->getCustomAttribute('thumbnail')->getValue(),
170+
$response['addProductsToCart']['cart']['itemsV2']['items'][0]['product']['thumbnail']['url']
171+
);
172+
$this->assertStringContainsString(
173+
$product2->getCustomAttribute('thumbnail')->getValue(),
174+
$response['addProductsToCart']['cart']['itemsV2']['items'][1]['product']['thumbnail']['url']
175+
);
176+
}
177+
178+
/**
179+
* Get addProductsToCart mutation based on passed parameters
180+
*
181+
* @param string $cartId
182+
* @param string $sku
183+
* @return string
184+
*/
185+
private function getMutation(
186+
string $cartId,
187+
string $sku
188+
): string {
189+
return <<<MUTATION
190+
mutation {
191+
addProductsToCart(
192+
cartId: "$cartId"
193+
cartItems: [
194+
{
195+
quantity: 1
196+
sku: "$sku"
197+
}
198+
]
199+
) {
200+
cart {
201+
itemsV2(
202+
pageSize: 20
203+
currentPage: 1
204+
sort: { field: CREATED_AT, order: ASC }
205+
) {
206+
total_count
207+
items {
208+
product {
209+
thumbnail {
210+
url
211+
}
212+
}
213+
}
214+
}
215+
}
216+
user_errors {
217+
code
218+
message
219+
}
220+
}
221+
}
222+
MUTATION;
223+
}
224+
}

0 commit comments

Comments
 (0)