Skip to content

Commit 10d5b1d

Browse files
[Magento Community Engineering] Community Contributions - 2.4-develop-prs
- merged with '2.4-develop-expedited-prs' branch
2 parents 3bd544c + 73f5ddf commit 10d5b1d

File tree

8 files changed

+569
-7
lines changed

8 files changed

+569
-7
lines changed

app/code/Magento/Catalog/Model/Product/Url.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ class Url extends \Magento\Framework\DataObject
3030
protected $filter;
3131

3232
/**
33-
* Store manager
34-
*
3533
* @var \Magento\Store\Model\StoreManagerInterface
3634
*/
3735
protected $storeManager;
@@ -151,6 +149,7 @@ public function getUrl(\Magento\Catalog\Model\Product $product, $params = [])
151149
UrlRewrite::ENTITY_ID => $product->getId(),
152150
UrlRewrite::ENTITY_TYPE => \Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator::ENTITY_TYPE,
153151
UrlRewrite::STORE_ID => $storeId,
152+
UrlRewrite::REDIRECT_TYPE => 0
154153
];
155154
$useCategories = $this->scopeConfig->getValue(
156155
\Magento\Catalog\Helper\Product::XML_PATH_PRODUCT_URL_USE_CATEGORY,

app/code/Magento/ConfigurableProductGraphQl/Model/Options/Collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function getAttributesByProductId(int $productId): array
111111
*/
112112
private function fetch(): array
113113
{
114-
if (empty($this->productIds) || !empty($this->attributeMap)) {
114+
if (empty($this->productIds) || array_key_exists(end($this->productIds), $this->attributeMap)) {
115115
return $this->attributeMap;
116116
}
117117

app/code/Magento/Elasticsearch/Model/Indexer/Fulltext/Plugin/Category/Product/Action/Rows.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,16 @@ public function afterExecute(
7777
): ActionRows {
7878
$indexer = $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID);
7979
if (!empty($entityIds) && $indexer->isScheduled()) {
80+
$productIds = [];
81+
8082
foreach ($this->storeManager->getStores() as $store) {
8183
$indexTable = $this->getIndexTable((int) $store->getId(), $useTempTable);
82-
$productIds = $this->getProductIdsFromIndex($indexTable, $entityIds);
83-
if (!empty($productIds)) {
84-
$indexer->reindexList($productIds);
85-
}
84+
$productIds[] = $this->getProductIdsFromIndex($indexTable, $entityIds);
85+
}
86+
87+
$productIds = array_merge([], ...$productIds);
88+
if (!empty($productIds)) {
89+
$indexer->reindexList(array_unique($productIds));
8690
}
8791
}
8892

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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\QuoteGraphQl\Model\Resolver;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\Exception\NoSuchEntityException;
12+
use Magento\Framework\Exception\StateException;
13+
use Magento\Framework\GraphQl\Config\Element\Field;
14+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
15+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
16+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
17+
use Magento\Framework\GraphQl\Query\ResolverInterface;
18+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
19+
use Magento\GraphQl\Model\Query\ContextInterface;
20+
use Magento\Quote\Api\GuestCartManagementInterface;
21+
use Magento\Quote\Model\Cart\CustomerCartResolver;
22+
use Magento\QuoteGraphQl\Model\Cart\GetCartForUser;
23+
24+
/**
25+
* Assign the customer to the guest cart resolver
26+
*
27+
* @SuppressWarnings(PHPMD.LongVariable)
28+
*/
29+
class AssignCustomerToGuestCart implements ResolverInterface
30+
{
31+
/**
32+
* @var GetCartForUser
33+
*/
34+
private $getCartForUser;
35+
36+
/**
37+
* @var CustomerCartResolver
38+
*/
39+
private $customerCartResolver;
40+
41+
/**
42+
* @var GuestCartManagementInterface
43+
*/
44+
private $guestCartManagementInterface;
45+
46+
/**
47+
* @param GetCartForUser $getCartForUser
48+
* @param GuestCartManagementInterface $guestCartManagementInterface
49+
* @param CustomerCartResolver $customerCartResolver
50+
*/
51+
public function __construct(
52+
GetCartForUser $getCartForUser,
53+
GuestCartManagementInterface $guestCartManagementInterface,
54+
CustomerCartResolver $customerCartResolver
55+
) {
56+
$this->getCartForUser = $getCartForUser;
57+
$this->guestCartManagementInterface = $guestCartManagementInterface;
58+
$this->customerCartResolver = $customerCartResolver;
59+
}
60+
61+
/**
62+
* @inheritdoc
63+
*/
64+
public function resolve(
65+
Field $field,
66+
$context,
67+
ResolveInfo $info,
68+
array $value = null,
69+
array $args = null
70+
) {
71+
/** @var ContextInterface $context */
72+
if (false === $context->getExtensionAttributes()->getIsCustomer()) {
73+
throw new GraphQlAuthorizationException(__(
74+
'The current customer isn\'t authorized.'
75+
));
76+
}
77+
78+
$currentUserId = $context->getUserId();
79+
$guestMaskedCartId = $args['cart_id'];
80+
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
81+
82+
$this->getCartForUser->execute($guestMaskedCartId, null, $storeId);
83+
84+
try {
85+
$this->guestCartManagementInterface->assignCustomer($guestMaskedCartId, $currentUserId, $storeId);
86+
} catch (NoSuchEntityException $e) {
87+
throw new GraphQlNoSuchEntityException(
88+
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $guestMaskedCartId]),
89+
$e
90+
);
91+
} catch (StateException $e) {
92+
throw new GraphQlInputException(__($e->getMessage()), $e);
93+
} catch (LocalizedException $e) {
94+
throw new GraphQlInputException(
95+
__('Unable to assign the customer to the guest cart: %message', ['message' => $e->getMessage()]),
96+
$e
97+
);
98+
}
99+
100+
try {
101+
$customerCart = $this->customerCartResolver->resolve($currentUserId);
102+
} catch (\Exception $e) {
103+
$customerCart = null;
104+
}
105+
return [
106+
'model' => $customerCart,
107+
];
108+
}
109+
}

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# See COPYING.txt for license details.
33

44
type Query {
5+
"""phpcs:ignore Magento2.GraphQL.ValidArgumentName"""
56
cart(cart_id: String!): Cart @resolver (class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart") @doc(description:"Returns information about shopping cart") @cache(cacheable: false)
67
customerCart: Cart! @resolver (class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CustomerCart") @doc(description:"Returns information about the customer shopping cart") @cache(cacheable: false)
78
}
@@ -18,8 +19,13 @@ type Mutation {
1819
setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetBillingAddressOnCart")
1920
setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingMethodsOnCart")
2021
setPaymentMethodOnCart(input: SetPaymentMethodOnCartInput): SetPaymentMethodOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentMethodOnCart")
22+
"""phpcs:ignore Magento2.GraphQL.ValidArgumentName"""
2123
setGuestEmailOnCart(input: SetGuestEmailOnCartInput): SetGuestEmailOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetGuestEmailOnCart")
24+
"""phpcs:ignore Magento2.GraphQL.ValidArgumentName"""
2225
setPaymentMethodAndPlaceOrder(input: SetPaymentMethodAndPlaceOrderInput): PlaceOrderOutput @deprecated(reason: "Should use setPaymentMethodOnCart and placeOrder mutations in single request.") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentAndPlaceOrder")
26+
"""phpcs:ignore Magento2.GraphQL.ValidArgumentName"""
27+
assignCustomerToGuestCart(cart_id: String!): Cart! @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AssignCustomerToGuestCart") @doc(description:"Assign a logged in customer to the specified guest shopping cart.")
28+
"""phpcs:ignore Magento2.GraphQL.ValidArgumentName"""
2329
mergeCarts(source_cart_id: String!, destination_cart_id: String): Cart! @doc(description:"Merges the source cart into the destination cart") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\MergeCarts")
2430
placeOrder(input: PlaceOrderInput): PlaceOrderOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\PlaceOrder")
2531
addProductsToCart(cartId: String!, cartItems: [CartItemInput!]!): AddProductsToCartOutput @doc(description:"Add any type of product to the cart") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddProductsToCart")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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\GraphQl\ConfigurableProduct;
9+
10+
use Exception;
11+
use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\TestCase\GraphQlAbstract;
14+
15+
/**
16+
* Add configurable product to cart testcases
17+
*/
18+
class AddConfigurableProductsWithDifferentParentsToCartTest extends GraphQlAbstract
19+
{
20+
/**
21+
* @var GetMaskedQuoteIdByReservedOrderId
22+
*/
23+
private $getMaskedQuoteIdByReservedOrderId;
24+
25+
/**
26+
* @inheritdoc
27+
*/
28+
protected function setUp(): void
29+
{
30+
$objectManager = Bootstrap::getObjectManager();
31+
$this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
32+
}
33+
34+
/**
35+
* @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_products.php
36+
* @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
37+
*/
38+
public function testAddMultipleConfigurableProductsWithDifferentParentsToCart()
39+
{
40+
$searchResponse = $this->graphQlQuery($this->getFetchProductQuery('configurable'));
41+
$productOne = current($searchResponse['products']['items']);
42+
$searchResponse = $this->graphQlQuery($this->getFetchProductQuery('configurable_12345'));
43+
$productTwo = current($searchResponse['products']['items']);
44+
45+
$quantityOne = 1;
46+
$quantityTwo = 2;
47+
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
48+
$parentSkuOne = $productOne['sku'];
49+
$parentSkuTwo = $productTwo['sku'];
50+
$skuOne = 'simple_10';
51+
$skuTwo = 'simple_30';
52+
53+
$query = <<<QUERY
54+
mutation {
55+
addConfigurableProductsToCart(input:{
56+
cart_id:"{$maskedQuoteId}"
57+
cart_items:[
58+
{
59+
parent_sku:"{$parentSkuOne}"
60+
data:{
61+
sku:"{$skuOne}"
62+
quantity:{$quantityOne}
63+
}
64+
}
65+
{
66+
parent_sku:"{$parentSkuTwo}"
67+
data:{
68+
sku:"{$skuTwo}"
69+
quantity:{$quantityTwo}
70+
}
71+
}
72+
]
73+
}) {
74+
cart {
75+
items {
76+
id
77+
quantity
78+
product {
79+
sku
80+
}
81+
... on ConfigurableCartItem {
82+
configurable_options {
83+
option_label
84+
value_label
85+
value_id
86+
}
87+
configured_variant {
88+
sku
89+
varchar_attribute
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}
96+
QUERY;
97+
98+
$response = $this->graphQlMutation($query);
99+
100+
$cartItems = $response['addConfigurableProductsToCart']['cart']['items'];
101+
self::assertCount(2, $cartItems);
102+
$firstCartItem = $cartItems[0];
103+
self::assertEquals($quantityOne, $firstCartItem['quantity']);
104+
$secondCartItem = $cartItems[1];
105+
self::assertEquals($quantityTwo, $secondCartItem['quantity']);
106+
}
107+
108+
private function getFetchProductQuery(string $sku): string
109+
{
110+
return <<<QUERY
111+
{
112+
products(
113+
filter: {sku: {eq: "$sku"}}
114+
pageSize:1
115+
) {
116+
items {
117+
sku
118+
... on ConfigurableProduct {
119+
configurable_options {
120+
attribute_id
121+
attribute_code
122+
id
123+
label
124+
position
125+
product_id
126+
use_default
127+
values {
128+
default_label
129+
label
130+
store_label
131+
use_default_value
132+
value_index
133+
}
134+
}
135+
}
136+
}
137+
}
138+
}
139+
QUERY;
140+
}
141+
}

0 commit comments

Comments
 (0)