Skip to content

Commit b06aa33

Browse files
author
Valeriy Nayda
committed
Merge remote-tracking branch 'origin/graphql-23' into GraphQL-165
# Conflicts: # composer.lock
2 parents 5c29598 + 171d40d commit b06aa33

File tree

10 files changed

+398
-0
lines changed

10 files changed

+398
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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\CatalogInventoryGraphQl\Model\Resolver;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\CatalogInventory\Api\StockRegistryInterface;
12+
use Magento\CatalogInventory\Model\Configuration;
13+
use Magento\Framework\App\Config\ScopeConfigInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
use Magento\Framework\GraphQl\Config\Element\Field;
16+
use Magento\Framework\GraphQl\Query\Resolver\Value;
17+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
18+
use Magento\Framework\GraphQl\Query\ResolverInterface;
19+
use Magento\Store\Model\ScopeInterface;
20+
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
class OnlyXLeftInStockResolver implements ResolverInterface
25+
{
26+
/**
27+
* @var ValueFactory
28+
*/
29+
private $valueFactory;
30+
31+
/**
32+
* @var ScopeConfigInterface
33+
*/
34+
private $scopeConfig;
35+
36+
/**
37+
* @var StockRegistryInterface
38+
*/
39+
private $stockRegistry;
40+
41+
/**
42+
* @param ValueFactory $valueFactory
43+
* @param ScopeConfigInterface $scopeConfig
44+
* @param StockRegistryInterface $stockRegistry
45+
*/
46+
public function __construct(
47+
ValueFactory $valueFactory,
48+
ScopeConfigInterface $scopeConfig,
49+
StockRegistryInterface $stockRegistry
50+
) {
51+
$this->valueFactory = $valueFactory;
52+
$this->scopeConfig = $scopeConfig;
53+
$this->stockRegistry = $stockRegistry;
54+
}
55+
56+
/**
57+
* {@inheritdoc}
58+
*/
59+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null): Value
60+
{
61+
if (!array_key_exists('model', $value) || !$value['model'] instanceof ProductInterface) {
62+
$result = function () {
63+
return null;
64+
};
65+
66+
return $this->valueFactory->create($result);
67+
}
68+
69+
/* @var $product ProductInterface */
70+
$product = $value['model'];
71+
$onlyXLeftQty = $this->getOnlyXLeftQty($product);
72+
73+
$result = function () use ($onlyXLeftQty) {
74+
return $onlyXLeftQty;
75+
};
76+
77+
return $this->valueFactory->create($result);
78+
}
79+
80+
/**
81+
* Get product qty left when "Catalog > Inventory > Stock Options > Only X left Threshold" is greater than 0
82+
*
83+
* @param ProductInterface $product
84+
*
85+
* @return null|float
86+
*/
87+
private function getOnlyXLeftQty(ProductInterface $product): ?float
88+
{
89+
$thresholdQty = (float)$this->scopeConfig->getValue(
90+
Configuration::XML_PATH_STOCK_THRESHOLD_QTY,
91+
ScopeInterface::SCOPE_STORE
92+
);
93+
if ($thresholdQty === 0) {
94+
return null;
95+
}
96+
97+
$stockItem = $this->stockRegistry->getStockItem($product->getId());
98+
99+
$stockCurrentQty = $this->stockRegistry->getStockStatus(
100+
$product->getId(),
101+
$product->getStore()->getWebsiteId()
102+
)->getQty();
103+
104+
$stockLeft = $stockCurrentQty - $stockItem->getMinQty();
105+
106+
$thresholdQty = (float)$this->scopeConfig->getValue(
107+
Configuration::XML_PATH_STOCK_THRESHOLD_QTY,
108+
ScopeInterface::SCOPE_STORE
109+
);
110+
111+
if ($stockCurrentQty > 0 && $stockLeft <= $thresholdQty) {
112+
return $stockLeft;
113+
}
114+
115+
return null;
116+
}
117+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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\CatalogInventoryGraphQl\Model\Resolver;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\CatalogInventory\Api\Data\StockStatusInterface;
12+
use Magento\CatalogInventory\Api\StockStatusRepositoryInterface;
13+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
14+
use Magento\Framework\GraphQl\Config\Element\Field;
15+
use Magento\Framework\GraphQl\Query\Resolver\Value;
16+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
17+
use Magento\Framework\GraphQl\Query\ResolverInterface;
18+
19+
/**
20+
* {@inheritdoc}
21+
*/
22+
class StockStatusProvider implements ResolverInterface
23+
{
24+
/**
25+
* @var ValueFactory
26+
*/
27+
private $valueFactory;
28+
29+
/**
30+
* @var StockStatusRepositoryInterface
31+
*/
32+
private $stockStatusRepository;
33+
34+
/**
35+
* @param ValueFactory $valueFactory
36+
* @param StockStatusRepositoryInterface $stockStatusRepository
37+
*/
38+
public function __construct(ValueFactory $valueFactory, StockStatusRepositoryInterface $stockStatusRepository)
39+
{
40+
$this->valueFactory = $valueFactory;
41+
$this->stockStatusRepository = $stockStatusRepository;
42+
}
43+
44+
/**
45+
* {@inheritdoc}
46+
*/
47+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null): Value
48+
{
49+
if (!array_key_exists('model', $value) || !$value['model'] instanceof ProductInterface) {
50+
$result = function () {
51+
return null;
52+
};
53+
54+
return $this->valueFactory->create($result);
55+
}
56+
57+
/* @var $product ProductInterface */
58+
$product = $value['model'];
59+
60+
$stockStatus = $this->stockStatusRepository->get($product->getId());
61+
$productStockStatus = (int)$stockStatus->getStockStatus();
62+
63+
$result = function () use ($productStockStatus) {
64+
return $productStockStatus === StockStatusInterface::STATUS_IN_STOCK ? 'IN_STOCK' : 'OUT_OF_STOCK';
65+
};
66+
67+
return $this->valueFactory->create($result);
68+
}
69+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# CatalogInventoryGraphQl
2+
3+
**CatalogInventoryGraphQl** provides type information for the GraphQl module
4+
to generate inventory stock fields for product information endpoints.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "magento/module-catalog-inventory-graph-ql",
3+
"description": "N/A",
4+
"type": "magento2-module",
5+
"require": {
6+
"php": "~7.1.3||~7.2.0",
7+
"magento/framework": "*",
8+
"magento/module-store": "*",
9+
"magento/module-catalog": "*",
10+
"magento/module-catalog-inventory": "*"
11+
},
12+
"license": [
13+
"OSL-3.0",
14+
"AFL-3.0"
15+
],
16+
"autoload": {
17+
"files": [
18+
"registration.php"
19+
],
20+
"psr-4": {
21+
"Magento\\CatalogInventoryGraphQl\\": ""
22+
}
23+
}
24+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
9+
<module name="Magento_CatalogInventoryGraphQl">
10+
<sequence>
11+
<module name="Magento_Store"/>
12+
<module name="Magento_Catalog"/>
13+
<module name="Magento_CatalogInventory"/>
14+
</sequence>
15+
</module>
16+
</config>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright © Magento, Inc. All rights reserved.
2+
# See COPYING.txt for license details.
3+
4+
interface ProductInterface {
5+
only_x_left_in_stock: Float @doc(description: "Product stock only x left count") @resolver(class: "Magento\\CatalogInventoryGraphQl\\Model\\Resolver\\OnlyXLeftInStockResolver")
6+
stock_status: ProductStockStatus @doc(description: "Stock status of the product") @resolver(class: "Magento\\CatalogInventoryGraphQl\\Model\\Resolver\\StockStatusProvider")
7+
}
8+
9+
enum ProductStockStatus @doc(description: "This enumeration states whether a product stock status is in stock or out of stock") {
10+
IN_STOCK
11+
OUT_OF_STOCK
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
use Magento\Framework\Component\ComponentRegistrar;
9+
10+
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_CatalogInventoryGraphQl', __DIR__);

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"magento/module-catalog-analytics": "*",
117117
"magento/module-catalog-import-export": "*",
118118
"magento/module-catalog-inventory": "*",
119+
"magento/module-catalog-inventory-graph-ql": "*",
119120
"magento/module-catalog-rule": "*",
120121
"magento/module-catalog-rule-configurable": "*",
121122
"magento/module-catalog-search": "*",
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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\CatalogInventory;
9+
10+
use Magento\TestFramework\TestCase\GraphQlAbstract;
11+
12+
class ProductOnlyXLeftInStockTest extends GraphQlAbstract
13+
{
14+
/**
15+
* @magentoApiDataFixture Magento/Catalog/_files/product_simple_with_all_fields.php
16+
*/
17+
public function testQueryProductOnlyXLeftInStockDisabled()
18+
{
19+
$this->cleanCache();
20+
$productSku = 'simple';
21+
22+
$query = <<<QUERY
23+
{
24+
products(filter: {sku: {eq: "{$productSku}"}})
25+
{
26+
items {
27+
only_x_left_in_stock
28+
}
29+
}
30+
}
31+
QUERY;
32+
33+
$response = $this->graphQlQuery($query);
34+
35+
$this->assertArrayHasKey(0, $response['products']['items']);
36+
$this->assertArrayHasKey('only_x_left_in_stock', $response['products']['items'][0]);
37+
$this->assertNull($response['products']['items'][0]['only_x_left_in_stock']);
38+
}
39+
40+
/**
41+
* @magentoApiDataFixture Magento/Catalog/_files/product_simple_with_all_fields.php
42+
* @magentoConfigFixture default_store cataloginventory/options/stock_threshold_qty 120
43+
*/
44+
public function testQueryProductOnlyXLeftInStockEnabled()
45+
{
46+
$productSku = 'simple';
47+
48+
$query = <<<QUERY
49+
{
50+
products(filter: {sku: {eq: "{$productSku}"}})
51+
{
52+
items {
53+
only_x_left_in_stock
54+
}
55+
}
56+
}
57+
QUERY;
58+
$response = $this->graphQlQuery($query);
59+
60+
$this->assertArrayHasKey(0, $response['products']['items']);
61+
$this->assertArrayHasKey('only_x_left_in_stock', $response['products']['items'][0]);
62+
$this->assertEquals(100, $response['products']['items'][0]['only_x_left_in_stock']);
63+
}
64+
}

0 commit comments

Comments
 (0)