123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\SalesRule\Model\Quote;
- /**
- * Discount totals calculation model.
- */
- class Discount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
- {
- const COLLECTOR_TYPE_CODE = 'discount';
- /**
- * Discount calculation object
- *
- * @var \Magento\SalesRule\Model\Validator
- */
- protected $calculator;
- /**
- * Core event manager proxy
- *
- * @var \Magento\Framework\Event\ManagerInterface
- */
- protected $eventManager = null;
- /**
- * @var \Magento\Store\Model\StoreManagerInterface
- */
- protected $storeManager;
- /**
- * @var \Magento\Framework\Pricing\PriceCurrencyInterface
- */
- protected $priceCurrency;
- /**
- * @param \Magento\Framework\Event\ManagerInterface $eventManager
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
- * @param \Magento\SalesRule\Model\Validator $validator
- * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
- */
- public function __construct(
- \Magento\Framework\Event\ManagerInterface $eventManager,
- \Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\SalesRule\Model\Validator $validator,
- \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
- ) {
- $this->setCode(self::COLLECTOR_TYPE_CODE);
- $this->eventManager = $eventManager;
- $this->calculator = $validator;
- $this->storeManager = $storeManager;
- $this->priceCurrency = $priceCurrency;
- }
- /**
- * Collect address discount amount
- *
- * @param \Magento\Quote\Model\Quote $quote
- * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
- * @param \Magento\Quote\Model\Quote\Address\Total $total
- * @return $this
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- public function collect(
- \Magento\Quote\Model\Quote $quote,
- \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
- \Magento\Quote\Model\Quote\Address\Total $total
- ) {
- parent::collect($quote, $shippingAssignment, $total);
- $store = $this->storeManager->getStore($quote->getStoreId());
- $address = $shippingAssignment->getShipping()->getAddress();
- $this->calculator->reset($address);
- $items = $shippingAssignment->getItems();
- if (!count($items)) {
- return $this;
- }
- $eventArgs = [
- 'website_id' => $store->getWebsiteId(),
- 'customer_group_id' => $quote->getCustomerGroupId(),
- 'coupon_code' => $quote->getCouponCode(),
- ];
- $this->calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode());
- $this->calculator->initTotals($items, $address);
- $address->setDiscountDescription([]);
- $items = $this->calculator->sortItemsByPriority($items, $address);
- /** @var \Magento\Quote\Model\Quote\Item $item */
- foreach ($items as $item) {
- if ($item->getNoDiscount() || !$this->calculator->canApplyDiscount($item)) {
- $item->setDiscountAmount(0);
- $item->setBaseDiscountAmount(0);
- // ensure my children are zeroed out
- if ($item->getHasChildren() && $item->isChildrenCalculated()) {
- foreach ($item->getChildren() as $child) {
- $child->setDiscountAmount(0);
- $child->setBaseDiscountAmount(0);
- }
- }
- continue;
- }
- // to determine the child item discount, we calculate the parent
- if ($item->getParentItem()) {
- continue;
- }
- $eventArgs['item'] = $item;
- $this->eventManager->dispatch('sales_quote_address_discount_item', $eventArgs);
- if ($item->getHasChildren() && $item->isChildrenCalculated()) {
- $this->calculator->process($item);
- $this->distributeDiscount($item);
- foreach ($item->getChildren() as $child) {
- $eventArgs['item'] = $child;
- $this->eventManager->dispatch('sales_quote_address_discount_item', $eventArgs);
- $this->aggregateItemDiscount($child, $total);
- }
- } else {
- $this->calculator->process($item);
- $this->aggregateItemDiscount($item, $total);
- }
- }
- $this->calculator->prepareDescription($address);
- $total->setDiscountDescription($address->getDiscountDescription());
- $total->setSubtotalWithDiscount($total->getSubtotal() + $total->getDiscountAmount());
- $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $total->getBaseDiscountAmount());
- $address->setDiscountAmount($total->getDiscountAmount());
- $address->setBaseDiscountAmount($total->getBaseDiscountAmount());
- return $this;
- }
- /**
- * Aggregate item discount information to total data and related properties
- *
- * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
- * @param \Magento\Quote\Model\Quote\Address\Total $total
- * @return $this
- */
- protected function aggregateItemDiscount(
- \Magento\Quote\Model\Quote\Item\AbstractItem $item,
- \Magento\Quote\Model\Quote\Address\Total $total
- ) {
- $total->addTotalAmount($this->getCode(), -$item->getDiscountAmount());
- $total->addBaseTotalAmount($this->getCode(), -$item->getBaseDiscountAmount());
- return $this;
- }
- /**
- * Distribute discount at parent item to children items
- *
- * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
- * @return $this
- */
- protected function distributeDiscount(\Magento\Quote\Model\Quote\Item\AbstractItem $item)
- {
- $parentBaseRowTotal = $item->getBaseRowTotal();
- $keys = [
- 'discount_amount',
- 'base_discount_amount',
- 'original_discount_amount',
- 'base_original_discount_amount',
- ];
- $roundingDelta = [];
- foreach ($keys as $key) {
- //Initialize the rounding delta to a tiny number to avoid floating point precision problem
- $roundingDelta[$key] = 0.0000001;
- }
- foreach ($item->getChildren() as $child) {
- $ratio = $parentBaseRowTotal != 0 ? $child->getBaseRowTotal() / $parentBaseRowTotal : 0;
- foreach ($keys as $key) {
- if (!$item->hasData($key)) {
- continue;
- }
- $value = $item->getData($key) * $ratio;
- $roundedValue = $this->priceCurrency->round($value + $roundingDelta[$key]);
- $roundingDelta[$key] += $value - $roundedValue;
- $child->setData($key, $roundedValue);
- }
- }
- foreach ($keys as $key) {
- $item->setData($key, 0);
- }
- return $this;
- }
- /**
- * Add discount total information to address
- *
- * @param \Magento\Quote\Model\Quote $quote
- * @param \Magento\Quote\Model\Quote\Address\Total $total
- * @return array|null
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
- {
- $result = null;
- $amount = $total->getDiscountAmount();
- if ($amount != 0) {
- $description = $total->getDiscountDescription();
- $result = [
- 'code' => $this->getCode(),
- 'title' => strlen($description) ? __('Discount (%1)', $description) : __('Discount'),
- 'value' => $amount
- ];
- }
- return $result;
- }
- }
|