| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 | 
							- <?php
 
- /**
 
-  * Copyright © Magento, Inc. All rights reserved.
 
-  * See COPYING.txt for license details.
 
-  */
 
- namespace Magento\CatalogInventory\Model;
 
- use Magento\Catalog\Model\ProductFactory;
 
- use Magento\CatalogInventory\Api\Data\StockItemInterface;
 
- use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface;
 
- use Magento\Framework\DataObject\Factory as ObjectFactory;
 
- use Magento\Framework\Locale\FormatInterface;
 
- use Magento\Framework\Math\Division as MathDivision;
 
- /**
 
-  * Interface StockStateProvider
 
-  */
 
- class StockStateProvider implements StockStateProviderInterface
 
- {
 
-     /**
 
-      * @var MathDivision
 
-      */
 
-     protected $mathDivision;
 
-     /**
 
-      * @var FormatInterface
 
-      */
 
-     protected $localeFormat;
 
-     /**
 
-      * @var ObjectFactory
 
-      */
 
-     protected $objectFactory;
 
-     /**
 
-      * @var ProductFactory
 
-      */
 
-     protected $productFactory;
 
-     /**
 
-      * @var bool
 
-      */
 
-     protected $qtyCheckApplicable;
 
-     /**
 
-      * @param MathDivision $mathDivision
 
-      * @param FormatInterface $localeFormat
 
-      * @param ObjectFactory $objectFactory
 
-      * @param ProductFactory $productFactory
 
-      * @param bool $qtyCheckApplicable
 
-      */
 
-     public function __construct(
 
-         MathDivision $mathDivision,
 
-         FormatInterface $localeFormat,
 
-         ObjectFactory $objectFactory,
 
-         ProductFactory $productFactory,
 
-         $qtyCheckApplicable = true
 
-     ) {
 
-         $this->mathDivision = $mathDivision;
 
-         $this->localeFormat = $localeFormat;
 
-         $this->objectFactory = $objectFactory;
 
-         $this->productFactory = $productFactory;
 
-         $this->qtyCheckApplicable = $qtyCheckApplicable;
 
-     }
 
-     /**
 
-      * Validate stock
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @return bool
 
-      */
 
-     public function verifyStock(StockItemInterface $stockItem)
 
-     {
 
-         if ($stockItem->getQty() === null && $stockItem->getManageStock()) {
 
-             return false;
 
-         }
 
-         if ($stockItem->getBackorders() == StockItemInterface::BACKORDERS_NO
 
-             && $stockItem->getQty() <= $stockItem->getMinQty()
 
-         ) {
 
-             return false;
 
-         }
 
-         return true;
 
-     }
 
-     /**
 
-      * Verify notification
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @return bool
 
-      */
 
-     public function verifyNotification(StockItemInterface $stockItem)
 
-     {
 
-         return (float)$stockItem->getQty() < $stockItem->getNotifyStockQty();
 
-     }
 
-     /**
 
-      * Validate quote qty
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @param int|float $qty
 
-      * @param int|float $summaryQty
 
-      * @param int|float $origQty
 
-      * @return \Magento\Framework\DataObject
 
-      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 
-      * @SuppressWarnings(PHPMD.NPathComplexity)
 
-      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 
-      */
 
-     public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQty, $origQty = 0)
 
-     {
 
-         $result = $this->objectFactory->create();
 
-         $result->setHasError(false);
 
-         $qty = $this->getNumber($qty);
 
-         /**
 
-          * Check quantity type
 
-          */
 
-         $result->setItemIsQtyDecimal($stockItem->getIsQtyDecimal());
 
-         if (!$stockItem->getIsQtyDecimal()) {
 
-             $result->setHasQtyOptionUpdate(true);
 
-             $qty = (int) $qty;
 
-             /**
 
-              * Adding stock data to quote item
 
-              */
 
-             $result->setItemQty($qty);
 
-             $qty = $this->getNumber($qty);
 
-             $origQty = (int) $origQty;
 
-             $result->setOrigQty($origQty);
 
-         }
 
-         if ($stockItem->getMinSaleQty() && $qty < $stockItem->getMinSaleQty()) {
 
-             $result->setHasError(true)
 
-                 ->setMessage(__('The fewest you may purchase is %1.', $stockItem->getMinSaleQty() * 1))
 
-                 ->setErrorCode('qty_min')
 
-                 ->setQuoteMessage(__('Please correct the quantity for some products.'))
 
-                 ->setQuoteMessageIndex('qty');
 
-             return $result;
 
-         }
 
-         if ($stockItem->getMaxSaleQty() && $qty > $stockItem->getMaxSaleQty()) {
 
-             $result->setHasError(true)
 
-                 ->setMessage(__('The most you may purchase is %1.', $stockItem->getMaxSaleQty() * 1))
 
-                 ->setErrorCode('qty_max')
 
-                 ->setQuoteMessage(__('Please correct the quantity for some products.'))
 
-                 ->setQuoteMessageIndex('qty');
 
-             return $result;
 
-         }
 
-         $result->addData($this->checkQtyIncrements($stockItem, $qty)->getData());
 
-         if ($result->getHasError()) {
 
-             return $result;
 
-         }
 
-         if (!$stockItem->getManageStock()) {
 
-             return $result;
 
-         }
 
-         if (!$stockItem->getIsInStock()) {
 
-             $result->setHasError(true)
 
-                 ->setMessage(__('This product is out of stock.'))
 
-                 ->setQuoteMessage(__('Some of the products are out of stock.'))
 
-                 ->setQuoteMessageIndex('stock');
 
-             $result->setItemUseOldQty(true);
 
-             return $result;
 
-         }
 
-         if (!$this->checkQty($stockItem, $summaryQty) || !$this->checkQty($stockItem, $qty)) {
 
-             $message = __('The requested qty is not available');
 
-             $result->setHasError(true)->setMessage($message)->setQuoteMessage($message)->setQuoteMessageIndex('qty');
 
-             return $result;
 
-         } else {
 
-             if ($stockItem->getQty() - $summaryQty < 0) {
 
-                 if ($stockItem->getProductName()) {
 
-                     if ($stockItem->getIsChildItem()) {
 
-                         $backOrderQty = $stockItem->getQty() > 0 ? ($summaryQty - $stockItem->getQty()) * 1 : $qty * 1;
 
-                         if ($backOrderQty > $qty) {
 
-                             $backOrderQty = $qty;
 
-                         }
 
-                         $result->setItemBackorders($backOrderQty);
 
-                     } else {
 
-                         $orderedItems = (int)$stockItem->getOrderedItems();
 
-                         // Available item qty in stock excluding item qty in other quotes
 
-                         $qtyAvailable = ($stockItem->getQty() - ($summaryQty - $qty)) * 1;
 
-                         if ($qtyAvailable > 0) {
 
-                             $backOrderQty = $qty * 1 - $qtyAvailable;
 
-                         } else {
 
-                             $backOrderQty = $qty * 1;
 
-                         }
 
-                         if ($backOrderQty > 0) {
 
-                             $result->setItemBackorders($backOrderQty);
 
-                         }
 
-                         $stockItem->setOrderedItems($orderedItems + $qty);
 
-                     }
 
-                     if ($stockItem->getBackorders() == \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NOTIFY) {
 
-                         if (!$stockItem->getIsChildItem()) {
 
-                             $result->setMessage(
 
-                                 __(
 
-                                     'We don\'t have as many "%1" as you requested, '
 
-                                     . 'but we\'ll back order the remaining %2.',
 
-                                     $stockItem->getProductName(),
 
-                                     $backOrderQty * 1
 
-                                 )
 
-                             );
 
-                         } else {
 
-                             $result->setMessage(
 
-                                 __(
 
-                                     'We don\'t have "%1" in the requested quantity, '
 
-                                     . 'so we\'ll back order the remaining %2.',
 
-                                     $stockItem->getProductName(),
 
-                                     $backOrderQty * 1
 
-                                 )
 
-                             );
 
-                         }
 
-                     } elseif ($stockItem->getShowDefaultNotificationMessage()) {
 
-                         $result->setMessage(
 
-                             __('The requested qty is not available')
 
-                         );
 
-                     }
 
-                 }
 
-             } else {
 
-                 if (!$stockItem->getIsChildItem()) {
 
-                     $stockItem->setOrderedItems($qty + (int)$stockItem->getOrderedItems());
 
-                 }
 
-             }
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      * Check quantity
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @param int|float $qty
 
-      * @exception \Magento\Framework\Exception\LocalizedException
 
-      * @return bool
 
-      */
 
-     public function checkQty(StockItemInterface $stockItem, $qty)
 
-     {
 
-         if (!$this->qtyCheckApplicable) {
 
-             return true;
 
-         }
 
-         if (!$stockItem->getManageStock()) {
 
-             return true;
 
-         }
 
-         if ($stockItem->getQty() - $stockItem->getMinQty() - $qty < 0) {
 
-             switch ($stockItem->getBackorders()) {
 
-                 case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NONOTIFY:
 
-                 case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NOTIFY:
 
-                     break;
 
-                 default:
 
-                     return false;
 
-             }
 
-         }
 
-         return true;
 
-     }
 
-     /**
 
-      * Returns suggested qty
 
-      *
 
-      * Returns suggested qty that satisfies qty increments and minQty/maxQty/minSaleQty/maxSaleQty conditions
 
-      * or original qty if such value does not exist
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @param int|float $qty
 
-      * @return int|float
 
-      */
 
-     public function suggestQty(StockItemInterface $stockItem, $qty)
 
-     {
 
-         // We do not manage stock
 
-         if ($qty <= 0 || !$stockItem->getManageStock()) {
 
-             return $qty;
 
-         }
 
-         $qtyIncrements = (int)$stockItem->getQtyIncrements();
 
-         // Currently only integer increments supported
 
-         if ($qtyIncrements < 2) {
 
-             return $qty;
 
-         }
 
-         $minQty = max($stockItem->getMinSaleQty(), $qtyIncrements);
 
-         $divisibleMin = ceil($minQty / $qtyIncrements) * $qtyIncrements;
 
-         $maxQty = min($stockItem->getQty() - $stockItem->getMinQty(), $stockItem->getMaxSaleQty());
 
-         $divisibleMax = floor($maxQty / $qtyIncrements) * $qtyIncrements;
 
-         if ($qty < $minQty || $qty > $maxQty || $divisibleMin > $divisibleMax) {
 
-             // Do not perform rounding for qty that does not satisfy min/max conditions to not confuse customer
 
-             return $qty;
 
-         }
 
-         // Suggest value closest to given qty
 
-         $closestDivisibleLeft = floor($qty / $qtyIncrements) * $qtyIncrements;
 
-         $closestDivisibleRight = $closestDivisibleLeft + $qtyIncrements;
 
-         $acceptableLeft = min(max($divisibleMin, $closestDivisibleLeft), $divisibleMax);
 
-         $acceptableRight = max(min($divisibleMax, $closestDivisibleRight), $divisibleMin);
 
-         return abs($acceptableLeft - $qty) < abs($acceptableRight - $qty) ? $acceptableLeft : $acceptableRight;
 
-     }
 
-     /**
 
-      * Check Qty Increments
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @param float|int $qty
 
-      * @return \Magento\Framework\DataObject
 
-      */
 
-     public function checkQtyIncrements(StockItemInterface $stockItem, $qty)
 
-     {
 
-         $result = new \Magento\Framework\DataObject();
 
-         if ($stockItem->getSuppressCheckQtyIncrements()) {
 
-             return $result;
 
-         }
 
-         $qtyIncrements = $stockItem->getQtyIncrements() * 1;
 
-         if ($qtyIncrements && $this->mathDivision->getExactDivision($qty, $qtyIncrements) != 0) {
 
-             $result->setHasError(true)
 
-                 ->setQuoteMessage(__('Please correct the quantity for some products.'))
 
-                 ->setErrorCode('qty_increments')
 
-                 ->setQuoteMessageIndex('qty');
 
-             if ($stockItem->getIsChildItem()) {
 
-                 $result->setMessage(
 
-                     __(
 
-                         'You can buy %1 only in quantities of %2 at a time.',
 
-                         $stockItem->getProductName(),
 
-                         $qtyIncrements
 
-                     )
 
-                 );
 
-             } else {
 
-                 $result->setMessage(__('You can buy this product only in quantities of %1 at a time.', $qtyIncrements));
 
-             }
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      * Retrieve stock qty whether product is composite or no
 
-      *
 
-      * @param StockItemInterface $stockItem
 
-      * @return float
 
-      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 
-      * @SuppressWarnings(PHPMD.UnusedLocalVariable)
 
-      */
 
-     public function getStockQty(StockItemInterface $stockItem)
 
-     {
 
-         if (!$stockItem->hasStockQty()) {
 
-             $stockItem->setStockQty(0);
 
-             $product = $this->productFactory->create();
 
-             $product->load($stockItem->getProductId());
 
-             // prevent possible recursive loop
 
-             if (!$product->isComposite()) {
 
-                 $stockQty = $stockItem->getQty();
 
-             } else {
 
-                 $stockQty = null;
 
-                 $productsByGroups = $product->getTypeInstance()->getProductsToPurchaseByReqGroups($product);
 
-                 foreach ($productsByGroups as $productsInGroup) {
 
-                     $qty = 0;
 
-                     foreach ($productsInGroup as $childProduct) {
 
-                         $qty += $this->getStockQty($stockItem);
 
-                     }
 
-                     if (null === $stockQty || $qty < $stockQty) {
 
-                         $stockQty = $qty;
 
-                     }
 
-                 }
 
-             }
 
-             $stockQty = (float)$stockQty;
 
-             if ($stockQty < 0 || !$stockItem->getManageStock() || !$stockItem->getIsInStock()
 
-                 || !$product->isSaleable()
 
-             ) {
 
-                 $stockQty = 0;
 
-             }
 
-             $stockItem->setStockQty($stockQty);
 
-         }
 
-         return (float)$stockItem->getData('stock_qty');
 
-     }
 
-     /**
 
-      * Get numeric qty
 
-      *
 
-      * @param string|float|int|null $qty
 
-      * @return float|null
 
-      */
 
-     protected function getNumber($qty)
 
-     {
 
-         if (!is_numeric($qty)) {
 
-             $qty = $this->localeFormat->getNumber($qty);
 
-             return $qty;
 
-         }
 
-         return $qty;
 
-     }
 
- }
 
 
  |