Skip to content

Commit cb378f5

Browse files
Merge branch '2.4-develop' into ACQE-6392
2 parents 41c0b4c + 49cc612 commit cb378f5

File tree

10 files changed

+1387
-58
lines changed

10 files changed

+1387
-58
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Bundle\Model\Product;
20+
21+
use Magento\Catalog\Model\Product;
22+
use Magento\Framework\Serialize\Serializer\Json;
23+
24+
/**
25+
* Get original price for bundle products
26+
*/
27+
class OriginalPrice
28+
{
29+
/**
30+
* @param Json $serializer
31+
*/
32+
public function __construct(private readonly Json $serializer)
33+
{
34+
}
35+
36+
/**
37+
* Get Original Total price for Bundle items
38+
*
39+
* @param Product $product
40+
* @return float
41+
*/
42+
public function getTotalBundleItemsOriginalPrice(Product $product): float
43+
{
44+
$price = 0.0;
45+
46+
if (!$product->hasCustomOptions()) {
47+
return $price;
48+
}
49+
50+
$selectionIds = $this->getBundleSelectionIds($product);
51+
52+
if (empty($selectionIds)) {
53+
return $price;
54+
}
55+
56+
$selections = $product->getTypeInstance()->getSelectionsByIds($selectionIds, $product);
57+
foreach ($selections->getItems() as $selection) {
58+
if (!$selection->isSalable()) {
59+
continue;
60+
}
61+
62+
$selectionQty = $product->getCustomOption('selection_qty_' . $selection->getSelectionId());
63+
if ($selectionQty) {
64+
$price += $this->getSelectionOriginalTotalPrice(
65+
$product,
66+
$selection,
67+
(float) $selectionQty->getValue()
68+
);
69+
}
70+
}
71+
72+
return $price;
73+
}
74+
75+
/**
76+
* Calculate total original price of selection
77+
*
78+
* @param Product $bundleProduct
79+
* @param Product $selectionProduct
80+
* @param float $selectionQty
81+
*
82+
* @return float
83+
*/
84+
private function getSelectionOriginalTotalPrice(
85+
Product $bundleProduct,
86+
Product $selectionProduct,
87+
float $selectionQty
88+
): float {
89+
$price = $this->getSelectionOriginalPrice($bundleProduct, $selectionProduct);
90+
91+
return $price * $selectionQty;
92+
}
93+
94+
/**
95+
* Calculate the original price of selection
96+
*
97+
* @param Product $bundleProduct
98+
* @param Product $selectionProduct
99+
*
100+
* @return float
101+
*/
102+
public function getSelectionOriginalPrice(Product $bundleProduct, Product $selectionProduct): float
103+
{
104+
if ($bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC) {
105+
return (float) $selectionProduct->getPrice();
106+
}
107+
if ($selectionProduct->getSelectionPriceType()) {
108+
// percent
109+
return $bundleProduct->getPrice() * ($selectionProduct->getSelectionPriceValue() / 100);
110+
}
111+
112+
// fixed
113+
return (float) $selectionProduct->getSelectionPriceValue();
114+
}
115+
116+
/**
117+
* Retrieve array of bundle selection IDs
118+
*
119+
* @param Product $product
120+
* @return array
121+
*/
122+
private function getBundleSelectionIds(Product $product): array
123+
{
124+
$customOption = $product->getCustomOption('bundle_selection_ids');
125+
if ($customOption) {
126+
$selectionIds = $this->serializer->unserialize($customOption->getValue());
127+
if (is_array($selectionIds)) {
128+
return $selectionIds;
129+
}
130+
}
131+
return [];
132+
}
133+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Bundle\Plugin\Quote;
20+
21+
use Magento\Bundle\Model\Product\OriginalPrice;
22+
use Magento\Bundle\Model\Product\Type;
23+
use Magento\Quote\Model\Quote;
24+
use Magento\Quote\Model\Quote\Address\Total\Subtotal;
25+
use Magento\Quote\Api\Data\ShippingAssignmentInterface;
26+
use Magento\Quote\Model\Quote\Address\Total;
27+
28+
/**
29+
* Update bundle base original price
30+
*/
31+
class UpdateBundleQuoteItemBaseOriginalPrice
32+
{
33+
/**
34+
* @param OriginalPrice $price
35+
*/
36+
public function __construct(
37+
private readonly OriginalPrice $price
38+
) {
39+
}
40+
41+
/**
42+
* Update bundle base original price
43+
*
44+
* @param Subtotal $subject
45+
* @param Subtotal $result
46+
* @param Quote $quote
47+
* @param ShippingAssignmentInterface $shippingAssignment
48+
* @param Total $total
49+
*
50+
* @return Subtotal
51+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
52+
*/
53+
public function afterCollect(
54+
Subtotal $subject,
55+
Subtotal $result,
56+
Quote $quote,
57+
ShippingAssignmentInterface $shippingAssignment,
58+
Total $total
59+
): Subtotal {
60+
foreach ($quote->getAllVisibleItems() as $quoteItem) {
61+
if ($quoteItem->getProductType() === Type::TYPE_CODE) {
62+
$price = $quoteItem->getProduct()->getPrice();
63+
$price += $this->price->getTotalBundleItemsOriginalPrice($quoteItem->getProduct());
64+
$quoteItem->setBaseOriginalPrice($price);
65+
}
66+
}
67+
return $result;
68+
}
69+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,9 @@
284284
</argument>
285285
</arguments>
286286
</type>
287+
<type name="Magento\Quote\Model\Quote\Address\Total\Subtotal">
288+
<plugin name="update_bundle_quote_item_base_original_price"
289+
type="Magento\Bundle\Plugin\Quote\UpdateBundleQuoteItemBaseOriginalPrice"
290+
sortOrder="10"/>
291+
</type>
287292
</config>

app/code/Magento/BundleGraphQl/Model/Resolver/BundlePriceDetails.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
2828

2929
$price = $product->getPrice();
3030
$finalPrice = $product->getFinalPrice();
31-
$discountPercentage = 100 - (($finalPrice * 100) / $price);
31+
$discountPercentage = ($price) ? (100 - (($finalPrice * 100) / $price)) : 0;
3232
return [
3333
'main_price' => $price,
3434
'main_final_price' => $finalPrice,

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
*

0 commit comments

Comments
 (0)