Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Discount.php
Go to the documentation of this file.
1 <?php
7 
8 class Discount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
9 {
15  protected $calculator;
16 
22  protected $eventManager = null;
23 
27  protected $storeManager;
28 
32  protected $priceCurrency;
33 
40  public function __construct(
41  \Magento\Framework\Event\ManagerInterface $eventManager,
43  \Magento\SalesRule\Model\Validator $validator,
45  ) {
46  $this->setCode('discount');
47  $this->eventManager = $eventManager;
48  $this->calculator = $validator;
49  $this->storeManager = $storeManager;
50  $this->priceCurrency = $priceCurrency;
51  }
52 
62  public function collect(
63  \Magento\Quote\Model\Quote $quote,
64  \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
66  ) {
67  parent::collect($quote, $shippingAssignment, $total);
68 
69  $store = $this->storeManager->getStore($quote->getStoreId());
70  $address = $shippingAssignment->getShipping()->getAddress();
71  $this->calculator->reset($address);
72 
73  $items = $shippingAssignment->getItems();
74  if (!count($items)) {
75  return $this;
76  }
77 
78  $eventArgs = [
79  'website_id' => $store->getWebsiteId(),
80  'customer_group_id' => $quote->getCustomerGroupId(),
81  'coupon_code' => $quote->getCouponCode(),
82  ];
83 
84  $this->calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode());
85  $this->calculator->initTotals($items, $address);
86 
87  $address->setDiscountDescription([]);
88  $items = $this->calculator->sortItemsByPriority($items, $address);
89 
91  foreach ($items as $item) {
92  if ($item->getNoDiscount() || !$this->calculator->canApplyDiscount($item)) {
93  $item->setDiscountAmount(0);
94  $item->setBaseDiscountAmount(0);
95 
96  // ensure my children are zeroed out
97  if ($item->getHasChildren() && $item->isChildrenCalculated()) {
98  foreach ($item->getChildren() as $child) {
99  $child->setDiscountAmount(0);
100  $child->setBaseDiscountAmount(0);
101  }
102  }
103  continue;
104  }
105  // to determine the child item discount, we calculate the parent
106  if ($item->getParentItem()) {
107  continue;
108  }
109 
110  $eventArgs['item'] = $item;
111  $this->eventManager->dispatch('sales_quote_address_discount_item', $eventArgs);
112 
113  if ($item->getHasChildren() && $item->isChildrenCalculated()) {
114  $this->calculator->process($item);
115  $this->distributeDiscount($item);
116  foreach ($item->getChildren() as $child) {
117  $eventArgs['item'] = $child;
118  $this->eventManager->dispatch('sales_quote_address_discount_item', $eventArgs);
119  $this->aggregateItemDiscount($child, $total);
120  }
121  } else {
122  $this->calculator->process($item);
123  $this->aggregateItemDiscount($item, $total);
124  }
125  }
126 
128  $address->setShippingDiscountAmount(0);
129  $address->setBaseShippingDiscountAmount(0);
130  if ($address->getShippingAmount()) {
131  $this->calculator->processShippingAmount($address);
132  $total->addTotalAmount($this->getCode(), -$address->getShippingDiscountAmount());
133  $total->addBaseTotalAmount($this->getCode(), -$address->getBaseShippingDiscountAmount());
134  $total->setShippingDiscountAmount($address->getShippingDiscountAmount());
135  $total->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount());
136  }
137 
138  $this->calculator->prepareDescription($address);
139  $total->setDiscountDescription($address->getDiscountDescription());
140  $total->setSubtotalWithDiscount($total->getSubtotal() + $total->getDiscountAmount());
141  $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $total->getBaseDiscountAmount());
142  return $this;
143  }
144 
152  protected function aggregateItemDiscount(
153  \Magento\Quote\Model\Quote\Item\AbstractItem $item,
154  \Magento\Quote\Model\Quote\Address\Total $total
155  ) {
156  $total->addTotalAmount($this->getCode(), -$item->getDiscountAmount());
157  $total->addBaseTotalAmount($this->getCode(), -$item->getBaseDiscountAmount());
158  return $this;
159  }
160 
167  protected function distributeDiscount(\Magento\Quote\Model\Quote\Item\AbstractItem $item)
168  {
169  $parentBaseRowTotal = $item->getBaseRowTotal();
170  $keys = [
171  'discount_amount',
172  'base_discount_amount',
173  'original_discount_amount',
174  'base_original_discount_amount',
175  ];
176  $roundingDelta = [];
177  foreach ($keys as $key) {
178  //Initialize the rounding delta to a tiny number to avoid floating point precision problem
179  $roundingDelta[$key] = 0.0000001;
180  }
181  foreach ($item->getChildren() as $child) {
182  $ratio = $parentBaseRowTotal != 0 ? $child->getBaseRowTotal() / $parentBaseRowTotal : 0;
183  foreach ($keys as $key) {
184  if (!$item->hasData($key)) {
185  continue;
186  }
187  $value = $item->getData($key) * $ratio;
188  $roundedValue = $this->priceCurrency->round($value + $roundingDelta[$key]);
189  $roundingDelta[$key] += $value - $roundedValue;
190  $child->setData($key, $roundedValue);
191  }
192  }
193 
194  foreach ($keys as $key) {
195  $item->setData($key, 0);
196  }
197  return $this;
198  }
199 
208  public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
209  {
210  $result = null;
211  $amount = $total->getDiscountAmount();
212 
213  if ($amount != 0) {
214  $description = $total->getDiscountDescription();
215  $result = [
216  'code' => $this->getCode(),
217  'title' => strlen($description) ? __('Discount (%1)', $description) : __('Discount'),
218  'value' => $amount
219  ];
220  }
221  return $result;
222  }
223 }
collect(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Model\Quote\Address\Total $total)
$quote
__()
Definition: __.php:13
$address
Definition: customer.php:38
$amount
Definition: order.php:14
$value
Definition: gender.phtml:16
__construct(\Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\SalesRule\Model\Validator $validator, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency)
Definition: Discount.php:40
aggregateItemDiscount(\Magento\Quote\Model\Quote\Item\AbstractItem $item, \Magento\Quote\Model\Quote\Address\Total $total)
Definition: Discount.php:152
distributeDiscount(\Magento\Quote\Model\Quote\Item\AbstractItem $item)
Definition: Discount.php:167
fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
Definition: Discount.php:208
$items