Skip to content

Commit d95faea

Browse files
Merge pull request #530 from magento-lynx/graphql-api-enhancements
[LYNX] Delivery PR
2 parents 11ce816 + 16e8db2 commit d95faea

File tree

6 files changed

+320
-55
lines changed

6 files changed

+320
-55
lines changed

InventoryGraphQl/Model/Resolver/StockStatusProvider.php

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,26 @@
1414
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1515
use Magento\InventoryCatalog\Model\GetStockIdForCurrentWebsite;
1616
use Magento\InventorySalesApi\Api\AreProductsSalableInterface;
17-
use Magento\Catalog\Model\Product\Type;
17+
use Magento\Bundle\Model\Product\Type;
1818

1919
/**
2020
* @inheritdoc
2121
*/
2222
class StockStatusProvider implements ResolverInterface
2323
{
24-
/**
25-
* @var GetStockIdForCurrentWebsite
26-
*/
27-
private $getStockIdForCurrentWebsite;
28-
29-
/**
30-
* @var AreProductsSalableInterface|null
31-
*/
32-
private $areProductsSalable;
24+
private const IN_STOCK = "IN_STOCK";
25+
private const OUT_OF_STOCK = "OUT_OF_STOCK";
3326

3427
/**
3528
* @param GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite
3629
* @param AreProductsSalableInterface $areProductsSalable
30+
* @param Type $bundleType
3731
*/
3832
public function __construct(
39-
GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite,
40-
AreProductsSalableInterface $areProductsSalable
33+
private readonly GetStockIdForCurrentWebsite $getStockIdForCurrentWebsite,
34+
private readonly AreProductsSalableInterface $areProductsSalable,
35+
private readonly Type $bundleType
4136
) {
42-
$this->getStockIdForCurrentWebsite = $getStockIdForCurrentWebsite;
43-
$this->areProductsSalable = $areProductsSalable;
4437
}
4538

4639
/**
@@ -52,15 +45,25 @@ public function resolve(Field $field, $context, ResolveInfo $info, ?array $value
5245
throw new LocalizedException(__('"model" value should be specified'));
5346
}
5447

55-
/* @var $product ProductInterface */
5648
$product = $value['model'];
5749

58-
$productSku = ($product->getTypeId() === TYPE::TYPE_BUNDLE || !empty($product->getOptions()))
59-
? $value['sku'] : $product->getSku();
50+
if ($product->getTypeId() === Type::TYPE_CODE) {
51+
try {
52+
if (!$product->getCustomOption('bundle_selection_ids')) {
53+
return self::OUT_OF_STOCK;
54+
}
55+
$this->bundleType->checkProductBuyState($product);
56+
} catch (LocalizedException $e) {
57+
return self::OUT_OF_STOCK;
58+
}
59+
60+
return self::IN_STOCK;
61+
}
62+
63+
$productSku = (!empty($product->getOptions())) ? $value['sku'] : $product->getSku();
6064
$stockId = $this->getStockIdForCurrentWebsite->execute();
6165
$result = $this->areProductsSalable->execute([$productSku], $stockId);
62-
$result = current($result);
6366

64-
return $result->isSalable() ? 'IN_STOCK' : 'OUT_OF_STOCK';
67+
return current($result)->isSalable() ? self::IN_STOCK : self::OUT_OF_STOCK;
6568
}
6669
}

InventoryGraphQl/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"magento/module-catalog": "*",
99
"magento/module-inventory-catalog": "*",
1010
"magento/module-inventory-configuration-api": "*",
11-
"magento/module-inventory-sales-api": "*"
11+
"magento/module-inventory-sales-api": "*",
12+
"magento/module-bundle": "*"
1213
},
1314
"license": [
1415
"OSL-3.0",

InventoryInStorePickupQuoteGraphQl/Model/Cart/GetShippingAddress/AdaptGetShippingAddressPlugin.php

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
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
declare(strict_types=1);
77

88
namespace Magento\InventoryInStorePickupQuoteGraphQl\Model\Cart\GetShippingAddress;
99

10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\Exception\NoSuchEntityException;
12+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1013
use Magento\GraphQl\Model\Query\ContextInterface;
14+
use Magento\Inventory\Model\SourceRepository;
1115
use Magento\Quote\Api\Data\AddressExtensionFactory;
1216
use Magento\Quote\Model\Quote\Address;
1317
use Magento\QuoteGraphQl\Model\Cart\GetShippingAddress;
@@ -18,17 +22,47 @@
1822
class AdaptGetShippingAddressPlugin
1923
{
2024
/**
21-
* @var AddressExtensionFactory
22-
*/
23-
private $addressExtensionFactory;
24-
25-
/**
25+
* AdaptGetShippingAddressPlugin Constructor
26+
*
2627
* @param AddressExtensionFactory $addressExtensionFactory
28+
* @param SourceRepository $sourceRepository
2729
*/
2830
public function __construct(
29-
AddressExtensionFactory $addressExtensionFactory
31+
private readonly AddressExtensionFactory $addressExtensionFactory,
32+
private readonly SourceRepository $sourceRepository
3033
) {
31-
$this->addressExtensionFactory = $addressExtensionFactory;
34+
}
35+
36+
/**
37+
* Set shipping address in quote from pickup_location_code
38+
*
39+
* @param GetShippingAddress $subject
40+
* @param ContextInterface $context
41+
* @param array $shippingAddressInput
42+
* @return array
43+
* @throws GraphQlInputException
44+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
45+
*/
46+
public function beforeExecute(
47+
GetShippingAddress $subject,
48+
ContextInterface $context,
49+
array $shippingAddressInput
50+
): array {
51+
try {
52+
if (!empty($shippingAddressInput['pickup_location_code']) &&
53+
empty($shippingAddressInput['customer_address_id']) &&
54+
empty($shippingAddressInput['address'])
55+
) {
56+
$address = $this->getStoreAddress($shippingAddressInput['pickup_location_code']);
57+
if ($address) {
58+
$shippingAddressInput['address'] = $address;
59+
}
60+
}
61+
} catch (LocalizedException $e) {
62+
throw new GraphQlInputException(__($e->getMessage()));
63+
}
64+
65+
return [$context, $shippingAddressInput];
3266
}
3367

3468
/**
@@ -74,4 +108,30 @@ private function assignPickupLocation(Address $address, array $shippingAddressIn
74108

75109
$extension->setPickupLocationCode($pickupLocationCode);
76110
}
111+
112+
/**
113+
* Get store address
114+
*
115+
* @param string $pickupLocationCode
116+
* @return array
117+
* @throws NoSuchEntityException
118+
*/
119+
private function getStoreAddress(string $pickupLocationCode): array
120+
{
121+
$storeAddress = $this->sourceRepository->get($pickupLocationCode);
122+
if ($storeAddress->getEnabled() && $storeAddress->getIsPickupLocationActive()) {
123+
return [
124+
'firstname' => $storeAddress->getFrontendName(),
125+
'lastname' => 'Store',
126+
'street' => $storeAddress->getStreet(),
127+
'city' => $storeAddress->getCity(),
128+
'region' => $storeAddress->getRegionId(),
129+
'postcode' => $storeAddress->getPostcode(),
130+
'country_code' => $storeAddress->getCountryId(),
131+
'telephone' => $storeAddress->getPhone()
132+
];
133+
}
134+
135+
return [];
136+
}
77137
}

InventoryInStorePickupQuoteGraphQl/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"magento/framework": "*",
77
"magento/module-quote-graph-ql": "*",
88
"magento/module-quote": "*",
9-
"magento/module-graph-ql": "*"
9+
"magento/module-graph-ql": "*",
10+
"magento/module-inventory": "*"
1011
},
1112
"type": "magento2-module",
1213
"license": [

dev/tests/api-functional/testsuite/Magento/GraphQl/Inventory/BundleProductStockStatusTest.php

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
11
<?php
22
/**
3-
* ADOBE CONFIDENTIAL
4-
*
53
* Copyright 2024 Adobe
64
* All Rights Reserved.
7-
*
8-
* NOTICE: All information contained herein is, and remains
9-
* the property of Adobe and its suppliers, if any. The intellectual
10-
* and technical concepts contained herein are proprietary to Adobe
11-
* and its suppliers and are protected by all applicable intellectual
12-
* property laws, including trade secret and copyright laws.
13-
* Dissemination of this information or reproduction of this material
14-
* is strictly forbidden unless prior written permission is obtained
15-
* from Adobe.
165
*/
176
declare(strict_types=1);
187

@@ -25,6 +14,10 @@
2514
use Magento\Catalog\Api\ProductRepositoryInterface;
2615
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
2716
use Magento\Framework\DataObject;
17+
use Magento\Framework\Exception\CouldNotSaveException;
18+
use Magento\Framework\Exception\InputException;
19+
use Magento\Framework\Exception\NoSuchEntityException;
20+
use Magento\Framework\Exception\StateException;
2821
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
2922
use Magento\Quote\Test\Fixture\QuoteIdMask as QuoteMaskFixture;
3023
use Magento\TestFramework\Fixture\DataFixture;
@@ -91,29 +84,32 @@ protected function setUp(): void
9184
* @param string $expected
9285
* @return void
9386
*
87+
* @throws CouldNotSaveException
88+
* @throws InputException
89+
* @throws NoSuchEntityException
90+
* @throws StateException
9491
* @dataProvider stockStatusProvider
9592
*/
9693
public function testStockStatusBundleProduct(bool $inStock, string $expected): void
9794
{
98-
$bundleProductSku = $this->fixtures->get('bundle_product')->getSku();
99-
$product = $this->productRepository->get($bundleProductSku);
95+
$product = $this->productRepository->get($this->fixtures->get('product1')->getSku());
10096
$product->getExtensionAttributes()->getStockItem()->setIsInStock($inStock);
10197
$this->productRepository->save($product);
10298

10399
$maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
104100
$query = <<<QUERY
105-
{
106-
cart(cart_id: "$maskedQuoteId") {
107-
itemsV2 {
108-
items {
109-
product {
110-
stock_status
111-
}
112-
}
113-
}
114-
}
115-
}
116-
QUERY;
101+
{
102+
cart(cart_id: "$maskedQuoteId") {
103+
itemsV2 {
104+
items {
105+
product {
106+
stock_status
107+
}
108+
}
109+
}
110+
}
111+
}
112+
QUERY;
117113

118114
$response = $this->graphQlQuery($query);
119115
$responseDataObject = new DataObject($response);

0 commit comments

Comments
 (0)