/** * Collect address discount amount * * @param Address $address * @return $this */ public function collect(Address $address) { parent::collect($address); $quote = $address->getQuote(); $store = $this->_storeManager->getStore($quote->getStoreId()); $this->_calculator->reset($address); $items = $this->_getAddressItems($address); if (!count($items)) { return $this; } $eventArgs = array('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(array()); $items = $this->_calculator->sortItemsByPriority($items); foreach ($items as $item) { if ($item->getNoDiscount()) { $item->setDiscountAmount(0); $item->setBaseDiscountAmount(0); continue; } /** * Child item discount we calculate for parent */ if ($item->getParentItemId()) { continue; } $eventArgs['item'] = $item; $this->_eventManager->dispatch('sales_quote_address_discount_item', $eventArgs); if ($item->getHasChildren() && $item->isChildrenCalculated()) { $isMatchedParent = $this->_calculator->canApplyRules($item); $this->_calculator->setSkipActionsValidation($isMatchedParent); foreach ($item->getChildren() as $child) { $this->_calculator->process($child); if ($isMatchedParent) { $this->_recalculateChildDiscount($child); } $eventArgs['item'] = $child; $this->_eventManager->dispatch('sales_quote_address_discount_item', $eventArgs); $this->_aggregateItemDiscount($child); } $this->_calculator->setSkipActionsValidation(false); } else { $this->_calculator->process($item); $this->_aggregateItemDiscount($item); } } /** * Process shipping amount discount */ $address->setShippingDiscountAmount(0); $address->setBaseShippingDiscountAmount(0); if ($address->getShippingAmount()) { $this->_calculator->processShippingAmount($address); $this->_addAmount(-$address->getShippingDiscountAmount()); $this->_addBaseAmount(-$address->getBaseShippingDiscountAmount()); } $this->_calculator->prepareDescription($address); return $this; }
/** * @param string $action * @dataProvider dataProviderActions */ public function testProcessShippingAmountActions($action) { $discountAmount = 50; $ruleMock = $this->getMockBuilder('Magento\\SalesRule\\Model\\Rule')->disableOriginalConstructor()->setMethods(['getApplyToShipping', 'getSimpleAction', 'getDiscountAmount'])->getMock(); $ruleMock->expects($this->any())->method('getApplyToShipping')->willReturn(true); $ruleMock->expects($this->any())->method('getDiscountAmount')->willReturn($discountAmount); $ruleMock->expects($this->any())->method('getSimpleAction')->willReturn($action); $iterator = new \ArrayIterator([$ruleMock]); $this->ruleCollection->expects($this->any())->method('getIterator')->willReturn($iterator); $this->utility->expects($this->any())->method('canProcessRule')->willReturn(true); $this->model->init($this->model->getWebsiteId(), $this->model->getCustomerGroupId(), $this->model->getCouponCode()); $this->assertInstanceOf('Magento\\SalesRule\\Model\\Validator', $this->model->processShippingAmount($this->getAddressMock(5))); }
/** * 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); /** @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); } } /** Process shipping amount discount */ $address->setShippingDiscountAmount(0); $address->setBaseShippingDiscountAmount(0); if ($address->getShippingAmount()) { $this->calculator->processShippingAmount($address); $total->addTotalAmount($this->getCode(), -$address->getShippingDiscountAmount()); $total->addBaseTotalAmount($this->getCode(), -$address->getBaseShippingDiscountAmount()); } $this->calculator->prepareDescription($address); $total->setDiscountDescription($address->getDiscountDescription()); $total->setSubtotalWithDiscount($total->getSubtotal() + $total->getDiscountAmount()); $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $total->getBaseDiscountAmount()); return $this; }