Skip to content

Commit

Permalink
Merge pull request #186 from magento-lynx/LYNX-310-LYNX-302
Browse files Browse the repository at this point in the history
LYNX-310 & LYNX-302: GraphQl: Added `status` attribute in cart query and add product to cart
  • Loading branch information
sumesh-GL authored Dec 19, 2023
2 parents 92c4421 + dbfe81c commit 802bc51
Show file tree
Hide file tree
Showing 6 changed files with 647 additions and 1 deletion.
77 changes: 77 additions & 0 deletions app/code/Magento/Catalog/Test/Fixture/ProductStock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* Copyright 2023 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe.
*/
declare(strict_types=1);

namespace Magento\Catalog\Test\Fixture;

use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Framework\DataObject;
use Magento\Framework\DataObjectFactory;
use Magento\TestFramework\Fixture\Api\DataMerger;
use Magento\TestFramework\Fixture\DataFixtureInterface;

class ProductStock implements DataFixtureInterface
{
private const DEFAULT_DATA = [
'prod_id' => null,
'prod_qty' => 1
];

/**
* @var DataObjectFactory
*/
protected DataObjectFactory $dataObjectFactory;

/**
* @var StockRegistryInterface
*/
protected StockRegistryInterface $stockRegistry;

/**
* @var DataMerger
*/
protected DataMerger $dataMerger;

/**
* @param DataObjectFactory $dataObjectFactory
* @param StockRegistryInterface $stockRegistry
* @param DataMerger $dataMerger
*/
public function __construct(
DataObjectFactory $dataObjectFactory,
StockRegistryInterface $stockRegistry,
DataMerger $dataMerger
) {
$this->dataObjectFactory = $dataObjectFactory;
$this->stockRegistry = $stockRegistry;
$this->dataMerger = $dataMerger;
}

/**
* {@inheritdoc}
* @param array $data Parameters. Same format as ProductStock::DEFAULT_DATA
*/
public function apply(array $data = []): ?DataObject
{
$data = $this->dataMerger->merge(self::DEFAULT_DATA, $data);
$stockItem = $this->stockRegistry->getStockItem($data['prod_id']);
$stockItem->setData('is_in_stock', 1);
$stockItem->setData('qty', 90);
$stockItem->setData('manage_stock', 1);
$stockItem->save();

return $this->dataObjectFactory->create(['data' => [$data]]);
}
}
5 changes: 4 additions & 1 deletion app/code/Magento/Quote/Model/Quote/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
protected $_optionsByCode = [];

/**
* Not Represent options
* Not Represent option
*
* @var array
*/
Expand All @@ -148,6 +148,7 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
/**
* Flag stating that options were successfully saved
*
* @var bool
*/
protected $_flagOptionsSaved;

Expand Down Expand Up @@ -176,6 +177,7 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
/**
* @var \Magento\CatalogInventory\Api\StockRegistryInterface
* @deprecated 101.0.0
* @see nothing
*/
protected $stockRegistry;

Expand Down Expand Up @@ -348,6 +350,7 @@ public function addQty($qty)
if (!$this->getParentItem() || !$this->getId()) {
$qty = $this->_prepareQty($qty);
$this->setQtyToAdd($qty);
$this->setPreviousQty($this->getQty());
$this->setQty($this->getQty() + $qty);
}
return $this;
Expand Down
95 changes: 95 additions & 0 deletions app/code/Magento/QuoteGraphQl/Model/CartItem/ProductStock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/************************************************************************
*
* Copyright 2023 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\QuoteGraphQl\Model\CartItem;

use Magento\CatalogInventory\Api\StockStatusRepositoryInterface;
use Magento\Quote\Model\Quote\Item;

/**
* Product Stock class to check availability of product
*/
class ProductStock
{
/**
* Product type code
*/
private const PRODUCT_TYPE_BUNDLE = "bundle";

/**
* ProductStock constructor
*
* @param StockStatusRepositoryInterface $stockStatusRepository
*/
public function __construct(
private StockStatusRepositoryInterface $stockStatusRepository
) {
}

/**
* Check item status available or unavailable
*
* @param Item $cartItem
* @return bool
*/
public function isProductAvailable($cartItem): bool
{
$requestedQty = 0;
$previousQty = 0;

foreach ($cartItem->getQuote()->getItems() as $item) {
if ($item->getItemId() === $cartItem->getItemId()) {
$requestedQty = $item->getQtyToAdd() ?? $item->getQty();
$previousQty = $item->getPreviousQty() ?? 0;
}
}

if ($cartItem->getProductType() === self::PRODUCT_TYPE_BUNDLE) {
$qtyOptions = $cartItem->getQtyOptions();
$totalRequestedQty = $previousQty + $requestedQty;
foreach ($qtyOptions as $qtyOption) {
$productId = (int) $qtyOption->getProductId();
$requiredItemQty = (float) $qtyOption->getValue();
if ($totalRequestedQty) {
$requiredItemQty = $requiredItemQty * $totalRequestedQty;
}
if (!$this->isStockAvailable($productId, $requiredItemQty)) {
return false;
}
}
} else {
$requiredItemQty = $requestedQty + $previousQty;
$productId = (int) $cartItem->getProduct()->getId();
return $this->isStockAvailable($productId, $requiredItemQty);
}
return true;
}

/**
* Check if is required product available in stock
*
* @param int $productId
* @param float $requiredQuantity
* @return bool
*/
private function isStockAvailable(int $productId, float $requiredQuantity): bool
{
$stock = $this->stockStatusRepository->get($productId);
return $stock->getQty() >= $requiredQuantity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/************************************************************************
*
* Copyright 2023 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\QuoteGraphQl\Model\Resolver;

use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\QuoteGraphQl\Model\CartItem\ProductStock;
use Magento\Quote\Model\Quote\Item;

/**
* @inheritdoc
*/
class CheckProductStockAvailability implements ResolverInterface
{
/**
* CheckProductStockAvailability constructor
*
* @param ProductStock $productStock
*/
public function __construct(
private ProductStock $productStock
) {
}

/**
* @inheritdoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (!isset($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}
/** @var Item $cartItem */
$cartItem = $value['model'];

return $this->productStock->isProductAvailable($cartItem);
}
}
1 change: 1 addition & 0 deletions app/code/Magento/QuoteGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ interface CartItemInterface @typeResolver(class: "Magento\\QuoteGraphQl\\Model\\
id: String! @deprecated(reason: "Use `uid` instead.")
uid: ID! @doc(description: "The unique ID for a `CartItemInterface` object.")
quantity: Float! @doc(description: "The quantity of this item in the cart.")
is_available: Boolean! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CheckProductStockAvailability") @doc(description: "True if requested quantity is less than available stock, false otherwise.")
prices: CartItemPrices @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemPrices") @doc(description: "Contains details about the price of the item, including taxes and discounts.")
product: ProductInterface! @doc(description: "Details about an item in the cart.")
errors: [CartItemError!] @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemErrors") @doc(description: "An array of errors encountered while loading the cart item")
Expand Down
Loading

0 comments on commit 802bc51

Please sign in to comment.