CartFixed.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\SalesRule\Model\Rule\Action\Discount;
  7. use Magento\Framework\Pricing\PriceCurrencyInterface;
  8. use Magento\SalesRule\Model\DeltaPriceRound;
  9. use Magento\SalesRule\Model\Validator;
  10. /**
  11. * Calculates discount for cart item if fixed discount applied on whole cart.
  12. */
  13. class CartFixed extends AbstractDiscount
  14. {
  15. /**
  16. * Store information about addresses which cart fixed rule applied for
  17. *
  18. * @var int[]
  19. */
  20. protected $_cartFixedRuleUsedForAddress = [];
  21. /**
  22. * @var DeltaPriceRound
  23. */
  24. private $deltaPriceRound;
  25. /**
  26. * @var string
  27. */
  28. private static $discountType = 'CartFixed';
  29. /**
  30. * @param Validator $validator
  31. * @param DataFactory $discountDataFactory
  32. * @param PriceCurrencyInterface $priceCurrency
  33. * @param DeltaPriceRound $deltaPriceRound
  34. */
  35. public function __construct(
  36. Validator $validator,
  37. DataFactory $discountDataFactory,
  38. PriceCurrencyInterface $priceCurrency,
  39. DeltaPriceRound $deltaPriceRound
  40. ) {
  41. $this->deltaPriceRound = $deltaPriceRound;
  42. parent::__construct($validator, $discountDataFactory, $priceCurrency);
  43. }
  44. /**
  45. * Fixed discount for cart calculation
  46. *
  47. * @param \Magento\SalesRule\Model\Rule $rule
  48. * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
  49. * @param float $qty
  50. * @return \Magento\SalesRule\Model\Rule\Action\Discount\Data
  51. */
  52. public function calculate($rule, $item, $qty)
  53. {
  54. /** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */
  55. $discountData = $this->discountFactory->create();
  56. $ruleTotals = $this->validator->getRuleItemTotalsInfo($rule->getId());
  57. $quote = $item->getQuote();
  58. $address = $item->getAddress();
  59. $itemPrice = $this->validator->getItemPrice($item);
  60. $baseItemPrice = $this->validator->getItemBasePrice($item);
  61. $itemOriginalPrice = $this->validator->getItemOriginalPrice($item);
  62. $baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item);
  63. /**
  64. * prevent applying whole cart discount for every shipping order, but only for first order
  65. */
  66. if ($quote->getIsMultiShipping()) {
  67. $usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId());
  68. if ($usedForAddressId && $usedForAddressId != $address->getId()) {
  69. return $discountData;
  70. } else {
  71. $this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId());
  72. }
  73. }
  74. $cartRules = $address->getCartFixedRules();
  75. if (!isset($cartRules[$rule->getId()])) {
  76. $cartRules[$rule->getId()] = $rule->getDiscountAmount();
  77. }
  78. $availableDiscountAmount = (float)$cartRules[$rule->getId()];
  79. $discountType = self::$discountType . $rule->getId();
  80. if ($availableDiscountAmount > 0) {
  81. $store = $quote->getStore();
  82. if ($ruleTotals['items_count'] <= 1) {
  83. $quoteAmount = $this->priceCurrency->convert($availableDiscountAmount, $store);
  84. $baseDiscountAmount = min($baseItemPrice * $qty, $availableDiscountAmount);
  85. $this->deltaPriceRound->reset($discountType);
  86. } else {
  87. $ratio = $baseItemPrice * $qty / $ruleTotals['base_items_price'];
  88. $maximumItemDiscount = $this->deltaPriceRound->round(
  89. $rule->getDiscountAmount() * $ratio,
  90. $discountType
  91. );
  92. $quoteAmount = $this->priceCurrency->convert($maximumItemDiscount, $store);
  93. $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount);
  94. $this->validator->decrementRuleItemTotalsCount($rule->getId());
  95. }
  96. $baseDiscountAmount = $this->priceCurrency->round($baseDiscountAmount);
  97. $availableDiscountAmount -= $baseDiscountAmount;
  98. $cartRules[$rule->getId()] = $availableDiscountAmount;
  99. if ($availableDiscountAmount <= 0) {
  100. $this->deltaPriceRound->reset($discountType);
  101. }
  102. $discountData->setAmount($this->priceCurrency->round(min($itemPrice * $qty, $quoteAmount)));
  103. $discountData->setBaseAmount($baseDiscountAmount);
  104. $discountData->setOriginalAmount(min($itemOriginalPrice * $qty, $quoteAmount));
  105. $discountData->setBaseOriginalAmount($this->priceCurrency->round($baseItemOriginalPrice));
  106. }
  107. $address->setCartFixedRules($cartRules);
  108. return $discountData;
  109. }
  110. /**
  111. * Set information about usage cart fixed rule by quote address
  112. *
  113. * @param int $ruleId
  114. * @param int $itemId
  115. * @return void
  116. */
  117. protected function setCartFixedRuleUsedForAddress($ruleId, $itemId)
  118. {
  119. $this->_cartFixedRuleUsedForAddress[$ruleId] = $itemId;
  120. }
  121. /**
  122. * Retrieve information about usage cart fixed rule by quote address
  123. *
  124. * @param int $ruleId
  125. * @return int|null
  126. */
  127. protected function getCartFixedRuleUsedForAddress($ruleId)
  128. {
  129. if (isset($this->_cartFixedRuleUsedForAddress[$ruleId])) {
  130. return $this->_cartFixedRuleUsedForAddress[$ruleId];
  131. }
  132. return null;
  133. }
  134. }