Skip to content

Commit 3cf05c6

Browse files
committed
Merge remote-tracking branch 'origin/AC-15054' into spartans_pr_21082025_AC-15054
2 parents 3026734 + 2f851aa commit 3cf05c6

File tree

5 files changed

+1019
-17
lines changed

5 files changed

+1019
-17
lines changed
Lines changed: 126 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,160 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
55
*/
66

77
declare(strict_types=1);
88

99
namespace Magento\Quote\Plugin;
1010

11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Framework\Exception\NoSuchEntityException;
1114
use Magento\Framework\Webapi\Rest\Request as RestRequest;
15+
use Magento\Quote\Api\CartRepositoryInterface;
1216
use Magento\Quote\Api\Data\CartItemInterface;
1317
use Magento\Quote\Api\GuestCartItemRepositoryInterface;
18+
use Magento\Quote\Model\QuoteIdMaskFactory;
19+
use Magento\Store\Model\StoreManagerInterface;
1420

1521
/**
16-
* Update cart id from request param
22+
* Plugin to update cart ID from request and validate product website assignment
1723
*/
1824
class UpdateCartId
1925
{
20-
/**
21-
* @var RestRequest $request
22-
*/
23-
private $request;
24-
2526
/**
2627
* @param RestRequest $request
28+
* @param ProductRepositoryInterface $productRepository
29+
* @param StoreManagerInterface $storeManager
30+
* @param QuoteIdMaskFactory $quoteIdMaskFactory
31+
* @param CartRepositoryInterface $cartRepository
2732
*/
28-
public function __construct(RestRequest $request)
29-
{
30-
$this->request = $request;
33+
public function __construct(
34+
private readonly RestRequest $request,
35+
private readonly ProductRepositoryInterface $productRepository,
36+
private readonly StoreManagerInterface $storeManager,
37+
private readonly QuoteIdMaskFactory $quoteIdMaskFactory,
38+
private readonly CartRepositoryInterface $cartRepository
39+
) {
3140
}
3241

3342
/**
34-
* Update id from request if param cartId exist
43+
* Before saving a guest cart item, set quote ID from request and validate website assignment
3544
*
36-
* @param GuestCartItemRepositoryInterface $guestCartItemRepository
45+
* @param GuestCartItemRepositoryInterface $subject
3746
* @param CartItemInterface $cartItem
3847
* @return void
48+
* @throws LocalizedException
49+
*
3950
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
4051
*/
4152
public function beforeSave(
42-
GuestCartItemRepositoryInterface $guestCartItemRepository,
53+
GuestCartItemRepositoryInterface $subject,
4354
CartItemInterface $cartItem
4455
): void {
45-
$cartId = $this->request->getParam('cartId');
46-
47-
if ($cartId) {
56+
if ($cartId = $this->request->getParam('cartId')) {
4857
$cartItem->setQuoteId($cartId);
4958
}
59+
60+
$this->validateProductWebsiteAssignment($cartItem);
61+
}
62+
63+
/**
64+
* Validate product's website assignment for guest cart item
65+
*
66+
* @param CartItemInterface $cartItem
67+
* @return void
68+
* @throws LocalizedException
69+
*/
70+
private function validateProductWebsiteAssignment(CartItemInterface $cartItem): void
71+
{
72+
$sku = $cartItem->getSku();
73+
if (!$sku) {
74+
return;
75+
}
76+
77+
$maskedQuoteId = $cartItem->getQuoteId();
78+
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($maskedQuoteId, 'masked_id');
79+
$quoteId = $quoteIdMask->getQuoteId();
80+
81+
if (!$quoteId) {
82+
return;
83+
}
84+
85+
try {
86+
$quote = $this->cartRepository->get($quoteId);
87+
$storeId = $quote->getStoreId();
88+
89+
foreach ($quote->getAllItems() as $item) {
90+
if ($sku === $item->getSku()) {
91+
$this->validateWebsiteAssignment($item->getProductId(), $storeId);
92+
return;
93+
}
94+
}
95+
96+
// Product not in quote yet
97+
$this->validateWebsiteAssignmentBySku($sku, $storeId);
98+
99+
} catch (NoSuchEntityException) {
100+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
101+
}
102+
}
103+
104+
/**
105+
* Validate by SKU for new items
106+
*
107+
* @param string $sku
108+
* @param int $storeId
109+
* @return void
110+
* @throws LocalizedException
111+
*/
112+
private function validateWebsiteAssignmentBySku(string $sku, int $storeId): void
113+
{
114+
try {
115+
$product = $this->productRepository->get($sku, false, $storeId);
116+
$this->checkProductInWebsite($product->getWebsiteIds(), $storeId);
117+
} catch (NoSuchEntityException) {
118+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
119+
}
120+
}
121+
122+
/**
123+
* Validate by product ID for existing items
124+
*
125+
* @param int $productId
126+
* @param int $storeId
127+
* @return void
128+
* @throws LocalizedException
129+
*/
130+
private function validateWebsiteAssignment(int $productId, int $storeId): void
131+
{
132+
try {
133+
$product = $this->productRepository->getById($productId, false, $storeId);
134+
if (empty($product->getWebsiteIds())) {
135+
return;
136+
}
137+
$this->checkProductInWebsite($product->getWebsiteIds(), $storeId);
138+
} catch (NoSuchEntityException) {
139+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
140+
}
141+
}
142+
143+
/**
144+
* Validate by product ID for existing items
145+
*
146+
* @param array|null $websiteIds
147+
* @param int $storeId
148+
* @return void
149+
* @throws LocalizedException
150+
* @throws NoSuchEntityException
151+
*/
152+
private function checkProductInWebsite(?array $websiteIds, int $storeId): void
153+
{
154+
$websiteId = $this->storeManager->getStore($storeId)->getWebsiteId();
155+
156+
if (empty($websiteIds) || !in_array($websiteId, $websiteIds, true)) {
157+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
158+
}
50159
}
51160
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Quote\Plugin\Webapi;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\Quote\Api\CartItemRepositoryInterface;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
use Magento\Quote\Api\Data\CartItemInterface;
16+
use Magento\Store\Model\StoreManagerInterface;
17+
18+
/**
19+
* Plugin to validate product website assignment for REST API cart operations
20+
*/
21+
class ValidateProductWebsiteAssignment
22+
{
23+
/**
24+
* @param ProductRepositoryInterface $productRepository
25+
* @param StoreManagerInterface $storeManager
26+
* @param CartRepositoryInterface $cartRepository
27+
*/
28+
public function __construct(
29+
private readonly ProductRepositoryInterface $productRepository,
30+
private readonly StoreManagerInterface $storeManager,
31+
private readonly CartRepositoryInterface $cartRepository
32+
) {
33+
}
34+
35+
/**
36+
* Validate product website assignment before saving cart item
37+
*
38+
* @param CartItemRepositoryInterface $subject
39+
* @param CartItemInterface $cartItem
40+
* @return void
41+
* @throws LocalizedException
42+
*
43+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
44+
*/
45+
public function beforeSave(
46+
CartItemRepositoryInterface $subject,
47+
CartItemInterface $cartItem
48+
): void {
49+
$sku = $cartItem->getSku();
50+
if (!$sku) {
51+
return;
52+
}
53+
54+
try {
55+
$quote = $this->cartRepository->getActive($cartItem->getQuoteId());
56+
57+
foreach ($quote->getAllItems() as $item) {
58+
if ($sku === $item->getSku()) {
59+
$this->checkProductWebsiteAssignment($item->getProductId(), $item->getStoreId());
60+
return;
61+
}
62+
}
63+
64+
// Fallback: product not in quote items yet
65+
$this->checkProductWebsiteAssignmentBySku($sku, $quote->getStoreId());
66+
67+
} catch (NoSuchEntityException $e) {
68+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
69+
}
70+
}
71+
72+
/**
73+
* Check product website assignment by SKU
74+
*
75+
* @param string $sku
76+
* @param int $storeId
77+
* @throws LocalizedException
78+
*/
79+
private function checkProductWebsiteAssignmentBySku(string $sku, int $storeId): void
80+
{
81+
try {
82+
$product = $this->productRepository->get($sku, false, $storeId);
83+
$this->validateWebsiteAssignment($product->getWebsiteIds(), $storeId);
84+
} catch (NoSuchEntityException $e) {
85+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
86+
}
87+
}
88+
89+
/**
90+
* Check product website assignment by product ID
91+
*
92+
* @param int $productId
93+
* @param int|null $storeId
94+
* @throws LocalizedException
95+
*/
96+
private function checkProductWebsiteAssignment($productId, $storeId): void
97+
{
98+
try {
99+
$product = $this->productRepository->getById($productId, false, $storeId);
100+
if (empty($product->getWebsiteIds())) {
101+
return;
102+
}
103+
$this->validateWebsiteAssignment($product->getWebsiteIds(), $storeId);
104+
} catch (NoSuchEntityException $e) {
105+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
106+
}
107+
}
108+
109+
/**
110+
* Validate product website assignment
111+
*
112+
* @param array|null $websiteIds
113+
* @param int $storeId
114+
* @throws LocalizedException
115+
*/
116+
private function validateWebsiteAssignment(?array $websiteIds, int $storeId): void
117+
{
118+
$websiteId = $this->storeManager->getStore($storeId)->getWebsiteId();
119+
if (empty($websiteIds) || !in_array($websiteId, $websiteIds, true)) {
120+
throw new LocalizedException(__('Product that you are trying to add is not available.'));
121+
}
122+
}
123+
}

0 commit comments

Comments
 (0)