FreeShipping.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\OfflineShipping\Model\Quote\Address;
  8. use Magento\OfflineShipping\Model\SalesRule\Calculator;
  9. use Magento\OfflineShipping\Model\SalesRule\ExtendedCalculator;
  10. use Magento\Quote\Model\Quote\Address\FreeShippingInterface;
  11. use Magento\Quote\Model\Quote\Item\AbstractItem;
  12. use Magento\Store\Model\StoreManagerInterface;
  13. class FreeShipping implements FreeShippingInterface
  14. {
  15. /**
  16. * @var ExtendedCalculator
  17. */
  18. protected $calculator;
  19. /**
  20. * @var StoreManagerInterface
  21. */
  22. protected $storeManager;
  23. /**
  24. * @param StoreManagerInterface $storeManager
  25. * @param Calculator $calculator
  26. */
  27. public function __construct(
  28. StoreManagerInterface $storeManager,
  29. Calculator $calculator
  30. ) {
  31. $this->storeManager = $storeManager;
  32. $this->calculator = $calculator;
  33. }
  34. /**
  35. * {@inheritDoc}
  36. */
  37. public function isFreeShipping(\Magento\Quote\Model\Quote $quote, $items)
  38. {
  39. /** @var \Magento\Quote\Api\Data\CartItemInterface[] $items */
  40. if (!count($items)) {
  41. return false;
  42. }
  43. $result = false;
  44. $addressFreeShipping = true;
  45. $store = $this->storeManager->getStore($quote->getStoreId());
  46. $this->calculator->init(
  47. $store->getWebsiteId(),
  48. $quote->getCustomerGroupId(),
  49. $quote->getCouponCode()
  50. );
  51. $shippingAddress = $quote->getShippingAddress();
  52. $shippingAddress->setFreeShipping(0);
  53. /** @var \Magento\Quote\Api\Data\CartItemInterface $item */
  54. foreach ($items as $item) {
  55. if ($item->getNoDiscount()) {
  56. $addressFreeShipping = false;
  57. $item->setFreeShipping(false);
  58. continue;
  59. }
  60. /** Child item discount we calculate for parent */
  61. if ($item->getParentItemId()) {
  62. continue;
  63. }
  64. $this->calculator->processFreeShipping($item);
  65. // at least one item matches to the rule and the rule mode is not a strict
  66. if ((bool)$item->getAddress()->getFreeShipping()) {
  67. $result = true;
  68. break;
  69. }
  70. $itemFreeShipping = (bool)$item->getFreeShipping();
  71. $addressFreeShipping = $addressFreeShipping && $itemFreeShipping;
  72. $result = $addressFreeShipping;
  73. }
  74. $shippingAddress->setFreeShipping((int)$result);
  75. $this->applyToItems($items, $result);
  76. return $result;
  77. }
  78. /**
  79. * @param AbstractItem $item
  80. * @param bool $isFreeShipping
  81. * @return void
  82. */
  83. protected function applyToChildren(\Magento\Quote\Model\Quote\Item\AbstractItem $item, $isFreeShipping)
  84. {
  85. if ($item->getHasChildren() && $item->isChildrenCalculated()) {
  86. foreach ($item->getChildren() as $child) {
  87. $this->calculator->processFreeShipping($child);
  88. if ($isFreeShipping) {
  89. $child->setFreeShipping($isFreeShipping);
  90. }
  91. }
  92. }
  93. }
  94. /**
  95. * Sets free shipping availability to the quote items.
  96. *
  97. * @param array $items
  98. * @param bool $freeShipping
  99. */
  100. private function applyToItems(array $items, bool $freeShipping)
  101. {
  102. /** @var AbstractItem $item */
  103. foreach ($items as $item) {
  104. $item->getAddress()
  105. ->setFreeShipping((int)$freeShipping);
  106. $this->applyToChildren($item, $freeShipping);
  107. }
  108. }
  109. }