Skip to content

Commit 78d98c3

Browse files
committed
ACP2E-924: MSI - Inventory Compensation command is not working properly for partial shipment of the Configurable products
1 parent 1a7f152 commit 78d98c3

File tree

8 files changed

+354
-22
lines changed

8 files changed

+354
-22
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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\Test\Fixture;
9+
10+
use Magento\Bundle\Model\Product\Type;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Framework\DataObject;
13+
use Magento\Framework\DataObjectFactory;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
16+
class AddProductToCart extends \Magento\Quote\Test\Fixture\AddProductToCart
17+
{
18+
/**
19+
* @var ProductRepositoryInterface
20+
*/
21+
private ProductRepositoryInterface $productRepository;
22+
23+
/**
24+
* @var Type
25+
*/
26+
private Type $productType;
27+
28+
/**
29+
* @param CartRepositoryInterface $cartRepository
30+
* @param ProductRepositoryInterface $productRepository
31+
* @param DataObjectFactory $dataObjectFactory
32+
* @param Type $productType
33+
*/
34+
public function __construct(
35+
CartRepositoryInterface $cartRepository,
36+
ProductRepositoryInterface $productRepository,
37+
DataObjectFactory $dataObjectFactory,
38+
Type $productType
39+
) {
40+
parent::__construct($cartRepository, $productRepository, $dataObjectFactory);
41+
$this->productRepository = $productRepository;
42+
$this->productType = $productType;
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
* @param array $data Parameters
48+
* <pre>
49+
* $data = [
50+
* 'cart_id' => (int) Cart ID. Required.
51+
* 'product_id' => (int) Product ID. Required.
52+
* 'selections' => (array) array of options selections. Required.
53+
* 'qty' => (int) Quantity. Optional. Default: 1.
54+
* ]
55+
* </pre>
56+
* $data['selections'] can be supplied in following formats:
57+
* - [["$product1.id$"], ["$product2.id$"]]
58+
* - [[{"product_id":"$product1.id$","qty":1}], [{"product_id":"$product2.id$","qty":1}]]
59+
* - To skip an option, pass empty array [["$product1.id$"], [], ["$product2.id$"]]
60+
*/
61+
public function apply(array $data = []): ?DataObject
62+
{
63+
$bundleProduct = $this->productRepository->getById($data['product_id']);
64+
$buyRequest = [
65+
'bundle_option' => [],
66+
'bundle_option_qty' => [],
67+
'qty' => $data['qty'] ?? 1,
68+
];
69+
$options = $this->productType->getOptionsCollection($bundleProduct);
70+
$selections = $this->productType->getSelectionsCollection([], $bundleProduct);
71+
$options->appendSelections($selections, true);
72+
$optionsList = array_values($options->getItems());
73+
foreach ($data['selections'] as $index => $selections) {
74+
if (!empty($selections)) {
75+
$option = $optionsList[$index];
76+
foreach ($selections as $item) {
77+
if (is_array($item)) {
78+
$productId = (int) $item['product_id'];
79+
$qty = $item['qty'] ?? 1;
80+
} else {
81+
$productId = (int) $item;
82+
$qty = 1;
83+
}
84+
foreach ($option->getSelections() as $selection) {
85+
if (((int) $selection->getProductId()) === $productId) {
86+
$buyRequest['bundle_option'][$option->getId()][] = $selection->getSelectionId();
87+
$buyRequest['bundle_option_qty'][$option->getId()][$selection->getSelectionId()] = $qty;
88+
break;
89+
}
90+
}
91+
}
92+
}
93+
}
94+
return parent::apply(
95+
[
96+
'cart_id' => $data['cart_id'],
97+
'product_id' => $data['product_id'],
98+
'buy_request' => $buyRequest
99+
]
100+
);
101+
}
102+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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\ConfigurableProduct\Test\Fixture;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
12+
use Magento\Framework\DataObject;
13+
use Magento\Framework\DataObjectFactory;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
16+
class AddProductToCart extends \Magento\Quote\Test\Fixture\AddProductToCart
17+
{
18+
/**
19+
* @var ProductRepositoryInterface
20+
*/
21+
private ProductRepositoryInterface $productRepository;
22+
23+
/**
24+
* @var Configurable
25+
*/
26+
private Configurable $productType;
27+
28+
/**
29+
* @param CartRepositoryInterface $cartRepository
30+
* @param ProductRepositoryInterface $productRepository
31+
* @param DataObjectFactory $dataObjectFactory
32+
* @param Configurable $productType
33+
*/
34+
public function __construct(
35+
CartRepositoryInterface $cartRepository,
36+
ProductRepositoryInterface $productRepository,
37+
DataObjectFactory $dataObjectFactory,
38+
Configurable $productType
39+
) {
40+
parent::__construct($cartRepository, $productRepository, $dataObjectFactory);
41+
$this->productRepository = $productRepository;
42+
$this->productType = $productType;
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
* @param array $data Parameters
48+
* <pre>
49+
* $data = [
50+
* 'cart_id' => (int) Cart ID. Required.
51+
* 'product_id' => (int) Product ID. Required.
52+
* 'child_product_id' => (int) Product ID. Required.
53+
* 'qty' => (int) Quantity. Optional. Default: 1.
54+
* ]
55+
* </pre>
56+
*/
57+
public function apply(array $data = []): ?DataObject
58+
{
59+
$configurableProduct = $this->productRepository->getById($data['product_id']);
60+
$childProduct = $this->productRepository->getById($data['child_product_id']);
61+
$buyRequest = [
62+
'super_attribute' => [],
63+
'qty' => $data['qty'] ?? 1,
64+
];
65+
foreach ($this->productType->getUsedProductAttributes($configurableProduct) as $attribute) {
66+
$buyRequest['super_attribute'][$attribute->getId()] = $childProduct->getData($attribute->getAttributeCode());
67+
}
68+
return parent::apply(
69+
[
70+
'cart_id' => $data['cart_id'],
71+
'product_id' => $data['product_id'],
72+
'buy_request' => $buyRequest
73+
]
74+
);
75+
}
76+
}

app/code/Magento/ConfigurableProduct/Test/Fixture/Attribute.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Attribute extends \Magento\Catalog\Test\Fixture\Attribute
2323
'sort_order' => 1,
2424
]
2525
],
26+
'scope' => 'global',
2627
];
2728

2829
/**
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\GroupedProduct\Test\Fixture;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Framework\DataObject;
12+
use Magento\Framework\DataObjectFactory;
13+
use Magento\GroupedProduct\Model\Product\Type\Grouped;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
16+
class AddProductToCart extends \Magento\Quote\Test\Fixture\AddProductToCart
17+
{
18+
/**
19+
* @var ProductRepositoryInterface
20+
*/
21+
private ProductRepositoryInterface $productRepository;
22+
23+
/**
24+
* @var Grouped
25+
*/
26+
private Grouped $productType;
27+
28+
/**
29+
* @param CartRepositoryInterface $cartRepository
30+
* @param ProductRepositoryInterface $productRepository
31+
* @param DataObjectFactory $dataObjectFactory
32+
* @param Grouped $productType
33+
*/
34+
public function __construct(
35+
CartRepositoryInterface $cartRepository,
36+
ProductRepositoryInterface $productRepository,
37+
DataObjectFactory $dataObjectFactory,
38+
Grouped $productType
39+
) {
40+
parent::__construct($cartRepository, $productRepository, $dataObjectFactory);
41+
$this->productRepository = $productRepository;
42+
$this->productType = $productType;
43+
}
44+
45+
46+
/**
47+
* {@inheritdoc}
48+
* @param array $data Parameters
49+
* <pre>
50+
* $data = [
51+
* 'cart_id' => (int) Cart ID. Required.
52+
* 'product_id' => (int) Product ID. Required.
53+
* 'child_products' => (array) array of associated products configuration. Required.
54+
* 'qty' => (int) Quantity. Optional. Default: 1.
55+
* ]
56+
* </pre>
57+
* $data['selections'] can be supplied in following formats:
58+
* - ["$product1.id$", "$product2.id$"]
59+
* - [{"product_id":"$product1.id$","qty":1}, {"product_id":"$product2.id$","qty":1}]
60+
*/
61+
public function apply(array $data = []): ?DataObject
62+
{
63+
$buyRequest = [
64+
'super_group' => [],
65+
'qty' => $data['qty'] ?? 1,
66+
];
67+
$bundleProduct = $this->productRepository->getById($data['product_id']);
68+
$default = [];
69+
foreach ($this->productType->getAssociatedProducts($bundleProduct) as $childProduct) {
70+
$default[$childProduct->getId()] = $childProduct->getQty();
71+
}
72+
foreach ($data['child_products'] as $item) {
73+
if (is_array($item)) {
74+
$productId = (int) $item['product_id'];
75+
$qty = $item['qty'] ?? null;
76+
} else {
77+
$productId = (int) $item;
78+
$qty = null;
79+
}
80+
$qty ??= $default[$productId];
81+
$buyRequest['super_group'][$productId] = $qty;
82+
}
83+
$buyRequest['super_group'] = empty($data['child_products'])
84+
? $default
85+
: array_intersect_key($buyRequest['super_group'], $default);
86+
return parent::apply(
87+
[
88+
'cart_id' => $data['cart_id'],
89+
'product_id' => $data['product_id'],
90+
'buy_request' => $buyRequest
91+
]
92+
);
93+
}
94+
}

app/code/Magento/Quote/Test/Fixture/AddProductToCart.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
use Magento\Catalog\Api\ProductRepositoryInterface;
1111
use Magento\Framework\DataObject;
12+
use Magento\Framework\DataObjectFactory;
13+
use Magento\Framework\Exception\LocalizedException;
1214
use Magento\Quote\Api\CartRepositoryInterface;
1315
use Magento\TestFramework\Fixture\DataFixtureInterface;
1416

@@ -17,23 +19,31 @@ class AddProductToCart implements DataFixtureInterface
1719
/**
1820
* @var CartRepositoryInterface
1921
*/
20-
private $cartRepository;
22+
private CartRepositoryInterface $cartRepository;
2123

2224
/**
2325
* @var ProductRepositoryInterface
2426
*/
25-
private $productRepository;
27+
private ProductRepositoryInterface $productRepository;
28+
29+
/**
30+
* @var DataObjectFactory
31+
*/
32+
private DataObjectFactory $dataObjectFactory;
2633

2734
/**
2835
* @param CartRepositoryInterface $cartRepository
2936
* @param ProductRepositoryInterface $productRepository
37+
* @param DataObjectFactory $dataObjectFactory
3038
*/
3139
public function __construct(
3240
CartRepositoryInterface $cartRepository,
33-
ProductRepositoryInterface $productRepository
41+
ProductRepositoryInterface $productRepository,
42+
DataObjectFactory $dataObjectFactory,
3443
) {
3544
$this->cartRepository = $cartRepository;
3645
$this->productRepository = $productRepository;
46+
$this->dataObjectFactory = $dataObjectFactory;
3747
}
3848

3949
/**
@@ -44,15 +54,25 @@ public function __construct(
4454
* 'cart_id' => (int) Cart ID. Required.
4555
* 'product_id' => (int) Product ID. Required.
4656
* 'qty' => (int) Quantity. Optional. Default: 1.
57+
* 'buy_request'=> (array|DataObject) advanced product configuration
4758
* ]
4859
* </pre>
4960
*/
5061
public function apply(array $data = []): ?DataObject
5162
{
5263
$cart = $this->cartRepository->get($data['cart_id']);
5364
$product = $this->productRepository->getById($data['product_id']);
54-
$catItem = $cart->addProduct($product, $data['qty'] ?? 1);
65+
$qty = $data['qty'] ?? 1;
66+
if (isset($data['buy_request'])) {
67+
$buyRequest = $data['buy_request'] instanceof DataObject
68+
? $data['buy_request']
69+
: $this->dataObjectFactory->create(['data' => $data['buy_request']]);
70+
}
71+
$catItem = $cart->addProduct($product, $buyRequest ?? $qty);
5572
$this->cartRepository->save($cart);
73+
if (is_string($catItem)) {
74+
throw new LocalizedException(__($catItem));
75+
}
5676
return $catItem;
5777
}
5878
}

0 commit comments

Comments
 (0)