Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
StockStateProvider.php
Go to the documentation of this file.
1 <?php
8 
9 use Magento\Catalog\Model\ProductFactory;
13 use Magento\Framework\Math\Division as MathDivision;
14 use Magento\Framework\DataObject\Factory as ObjectFactory;
15 
20 {
24  protected $mathDivision;
25 
29  protected $localeFormat;
30 
34  protected $objectFactory;
35 
39  protected $productFactory;
40 
45 
53  public function __construct(
54  MathDivision $mathDivision,
56  ObjectFactory $objectFactory,
57  ProductFactory $productFactory,
58  $qtyCheckApplicable = true
59  ) {
60  $this->mathDivision = $mathDivision;
61  $this->localeFormat = $localeFormat;
62  $this->objectFactory = $objectFactory;
63  $this->productFactory = $productFactory;
64  $this->qtyCheckApplicable = $qtyCheckApplicable;
65  }
66 
72  {
73  if ($stockItem->getQty() === null && $stockItem->getManageStock()) {
74  return false;
75  }
76  if ($stockItem->getBackorders() == StockItemInterface::BACKORDERS_NO
77  && $stockItem->getQty() <= $stockItem->getMinQty()
78  ) {
79  return false;
80  }
81  return true;
82  }
83 
89  {
90  return (float)$stockItem->getQty() < $stockItem->getNotifyStockQty();
91  }
92 
103  public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQty, $origQty = 0)
104  {
105  $result = $this->objectFactory->create();
106  $result->setHasError(false);
107 
108  $qty = $this->getNumber($qty);
109 
113  $result->setItemIsQtyDecimal($stockItem->getIsQtyDecimal());
114  if (!$stockItem->getIsQtyDecimal()) {
115  $result->setHasQtyOptionUpdate(true);
116  $qty = intval($qty);
120  $result->setItemQty($qty);
121  $qty = $this->getNumber($qty);
122  $origQty = intval($origQty);
123  $result->setOrigQty($origQty);
124  }
125 
126  if ($stockItem->getMinSaleQty() && $qty < $stockItem->getMinSaleQty()) {
127  $result->setHasError(true)
128  ->setMessage(__('The fewest you may purchase is %1.', $stockItem->getMinSaleQty() * 1))
129  ->setErrorCode('qty_min')
130  ->setQuoteMessage(__('Please correct the quantity for some products.'))
131  ->setQuoteMessageIndex('qty');
132  return $result;
133  }
134 
135  if ($stockItem->getMaxSaleQty() && $qty > $stockItem->getMaxSaleQty()) {
136  $result->setHasError(true)
137  ->setMessage(__('The most you may purchase is %1.', $stockItem->getMaxSaleQty() * 1))
138  ->setErrorCode('qty_max')
139  ->setQuoteMessage(__('Please correct the quantity for some products.'))
140  ->setQuoteMessageIndex('qty');
141  return $result;
142  }
143 
144  $result->addData($this->checkQtyIncrements($stockItem, $qty)->getData());
145  if ($result->getHasError()) {
146  return $result;
147  }
148 
149  if (!$stockItem->getManageStock()) {
150  return $result;
151  }
152 
153  if (!$stockItem->getIsInStock()) {
154  $result->setHasError(true)
155  ->setMessage(__('This product is out of stock.'))
156  ->setQuoteMessage(__('Some of the products are out of stock.'))
157  ->setQuoteMessageIndex('stock');
158  $result->setItemUseOldQty(true);
159  return $result;
160  }
161 
162  if (!$this->checkQty($stockItem, $summaryQty) || !$this->checkQty($stockItem, $qty)) {
163  $message = __('The requested qty is not available');
164  $result->setHasError(true)->setMessage($message)->setQuoteMessage($message)->setQuoteMessageIndex('qty');
165  return $result;
166  } else {
167  if ($stockItem->getQty() - $summaryQty < 0) {
168  if ($stockItem->getProductName()) {
169  if ($stockItem->getIsChildItem()) {
170  $backOrderQty = $stockItem->getQty() > 0 ? ($summaryQty - $stockItem->getQty()) * 1 : $qty * 1;
171  if ($backOrderQty > $qty) {
172  $backOrderQty = $qty;
173  }
174 
175  $result->setItemBackorders($backOrderQty);
176  } else {
177  $orderedItems = (int)$stockItem->getOrderedItems();
178 
179  // Available item qty in stock excluding item qty in other quotes
180  $qtyAvailable = ($stockItem->getQty() - ($summaryQty - $qty)) * 1;
181  if ($qtyAvailable > 0) {
182  $backOrderQty = $qty * 1 - $qtyAvailable;
183  } else {
184  $backOrderQty = $qty * 1;
185  }
186 
187  if ($backOrderQty > 0) {
188  $result->setItemBackorders($backOrderQty);
189  }
190  $stockItem->setOrderedItems($orderedItems + $qty);
191  }
192 
194  if (!$stockItem->getIsChildItem()) {
195  $result->setMessage(
196  __(
197  'We don\'t have as many "%1" as you requested, '
198  . 'but we\'ll back order the remaining %2.',
199  $stockItem->getProductName(),
200  $backOrderQty * 1
201  )
202  );
203  } else {
204  $result->setMessage(
205  __(
206  'We don\'t have "%1" in the requested quantity, '
207  . 'so we\'ll back order the remaining %2.',
208  $stockItem->getProductName(),
209  $backOrderQty * 1
210  )
211  );
212  }
213  } elseif ($stockItem->getShowDefaultNotificationMessage()) {
214  $result->setMessage(
215  __('The requested qty is not available')
216  );
217  }
218  }
219  } else {
220  if (!$stockItem->getIsChildItem()) {
221  $stockItem->setOrderedItems($qty + (int)$stockItem->getOrderedItems());
222  }
223  }
224  }
225  return $result;
226  }
227 
236  public function checkQty(StockItemInterface $stockItem, $qty)
237  {
238  if (!$this->qtyCheckApplicable) {
239  return true;
240  }
241  if (!$stockItem->getManageStock()) {
242  return true;
243  }
244  if ($stockItem->getQty() - $stockItem->getMinQty() - $qty < 0) {
245  switch ($stockItem->getBackorders()) {
246  case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NONOTIFY:
247  case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NOTIFY:
248  break;
249  default:
250  return false;
251  }
252  }
253  return true;
254  }
255 
264  public function suggestQty(StockItemInterface $stockItem, $qty)
265  {
266  // We do not manage stock
267  if ($qty <= 0 || !$stockItem->getManageStock()) {
268  return $qty;
269  }
270 
271  $qtyIncrements = (int)$stockItem->getQtyIncrements();
272  // Currently only integer increments supported
273  if ($qtyIncrements < 2) {
274  return $qty;
275  }
276 
277  $minQty = max($stockItem->getMinSaleQty(), $qtyIncrements);
278  $divisibleMin = ceil($minQty / $qtyIncrements) * $qtyIncrements;
279 
280  $maxQty = min($stockItem->getQty() - $stockItem->getMinQty(), $stockItem->getMaxSaleQty());
281  $divisibleMax = floor($maxQty / $qtyIncrements) * $qtyIncrements;
282 
283  if ($qty < $minQty || $qty > $maxQty || $divisibleMin > $divisibleMax) {
284  // Do not perform rounding for qty that does not satisfy min/max conditions to not confuse customer
285  return $qty;
286  }
287 
288  // Suggest value closest to given qty
289  $closestDivisibleLeft = floor($qty / $qtyIncrements) * $qtyIncrements;
290  $closestDivisibleRight = $closestDivisibleLeft + $qtyIncrements;
291  $acceptableLeft = min(max($divisibleMin, $closestDivisibleLeft), $divisibleMax);
292  $acceptableRight = max(min($divisibleMax, $closestDivisibleRight), $divisibleMin);
293  return abs($acceptableLeft - $qty) < abs($acceptableRight - $qty) ? $acceptableLeft : $acceptableRight;
294  }
295 
302  {
303  $result = new \Magento\Framework\DataObject();
304  if ($stockItem->getSuppressCheckQtyIncrements()) {
305  return $result;
306  }
307 
308  $qtyIncrements = $stockItem->getQtyIncrements() * 1;
309 
310  if ($qtyIncrements && $this->mathDivision->getExactDivision($qty, $qtyIncrements) != 0) {
311  $result->setHasError(true)
312  ->setQuoteMessage(__('Please correct the quantity for some products.'))
313  ->setErrorCode('qty_increments')
314  ->setQuoteMessageIndex('qty');
315  if ($stockItem->getIsChildItem()) {
316  $result->setMessage(
317  __(
318  'You can buy %1 only in quantities of %2 at a time.',
319  $stockItem->getProductName(),
320  $qtyIncrements
321  )
322  );
323  } else {
324  $result->setMessage(__('You can buy this product only in quantities of %1 at a time.', $qtyIncrements));
325  }
326  }
327  return $result;
328  }
329 
339  {
340  if (!$stockItem->hasStockQty()) {
341  $stockItem->setStockQty(0);
342  $product = $this->productFactory->create();
343  $product->load($stockItem->getProductId());
344  // prevent possible recursive loop
345  if (!$product->isComposite()) {
346  $stockQty = $stockItem->getQty();
347  } else {
348  $stockQty = null;
349  $productsByGroups = $product->getTypeInstance()->getProductsToPurchaseByReqGroups($product);
350  foreach ($productsByGroups as $productsInGroup) {
351  $qty = 0;
352  foreach ($productsInGroup as $childProduct) {
353  $qty += $this->getStockQty($stockItem);
354  }
355  if (null === $stockQty || $qty < $stockQty) {
356  $stockQty = $qty;
357  }
358  }
359  }
360  $stockQty = (float)$stockQty;
361  if ($stockQty < 0 || !$stockItem->getManageStock() || !$stockItem->getIsInStock()
362  || !$product->isSaleable()
363  ) {
364  $stockQty = 0;
365  }
366  $stockItem->setStockQty($stockQty);
367  }
368  return (float)$stockItem->getData('stock_qty');
369  }
370 
375  protected function getNumber($qty)
376  {
377  if (!is_numeric($qty)) {
378  $qty = $this->localeFormat->getNumber($qty);
379  return $qty;
380  }
381  return $qty;
382  }
383 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQty, $origQty=0)
__()
Definition: __.php:13
$message
suggestQty(StockItemInterface $stockItem, $qty)
checkQty(StockItemInterface $stockItem, $qty)
__construct(MathDivision $mathDivision, FormatInterface $localeFormat, ObjectFactory $objectFactory, ProductFactory $productFactory, $qtyCheckApplicable=true)
checkQtyIncrements(StockItemInterface $stockItem, $qty)