/** * Quote item free shipping ability check * This process not affect information about applied rules, coupon code etc. * This information will be added during discount amounts processing * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return \Magento\OfflineShipping\Model\SalesRule\Calculator */ public function processFreeShipping(\Magento\Sales\Model\Quote\Item\AbstractItem $item) { $address = $item->getAddress(); $item->setFreeShipping(false); foreach ($this->_getRules() as $rule) { /* @var $rule \Magento\SalesRule\Model\Rule */ if (!$this->validatorUtility->canProcessRule($rule, $address)) { continue; } if (!$rule->getActions()->validate($item)) { continue; } switch ($rule->getSimpleFreeShipping()) { case \Magento\OfflineShipping\Model\SalesRule\Rule::FREE_SHIPPING_ITEM: $item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true); break; case \Magento\OfflineShipping\Model\SalesRule\Rule::FREE_SHIPPING_ADDRESS: $address->setFreeShipping(true); break; } if ($rule->getStopRulesProcessing()) { break; } } return $this; }
/** * @param \Magento\SalesRule\Model\Rule $rule * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param float $qty * @return \Magento\SalesRule\Model\Rule\Action\Discount\Data */ public function calculate($rule, $item, $qty) { /** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */ $discountData = $this->discountFactory->create(); $quoteAmount = $item->getQuote()->getStore()->convertPrice($rule->getDiscountAmount()); $discountData->setAmount($qty * $quoteAmount); $discountData->setBaseAmount($qty * $rule->getDiscountAmount()); return $discountData; }
protected function setUp() { $this->rule = $this->getMock('Magento\\Framework\\Object', null, array(), 'Rule', true); $this->item = $this->getMock('Magento\\Sales\\Model\\Quote\\Item\\AbstractItem', array(), array(), '', false); $this->data = $this->getMock('Magento\\SalesRule\\Model\\Rule\\Action\\Discount\\Data', null); $this->quote = $this->getMock('Magento\\Sales\\Model\\Quote', array(), array(), '', false); $this->address = $this->getMock('Magento\\Sales\\Model\\Quote\\Address', array('getCartFixedRules', 'setCartFixedRules', '__wakeup'), array(), '', false); $this->item->expects($this->any())->method('getQuote')->will($this->returnValue($this->quote)); $this->item->expects($this->any())->method('getAddress')->will($this->returnValue($this->address)); $this->validator = $this->getMock('Magento\\SalesRule\\Model\\Validator', array(), array(), '', false); $dataFactory = $this->getMock('Magento\\SalesRule\\Model\\Rule\\Action\\Discount\\DataFactory', array('create'), array(), '', false); $dataFactory->expects($this->any())->method('create')->will($this->returnValue($this->data)); $this->model = new CartFixed($this->validator, $dataFactory); }
/** * @param \Magento\SalesRule\Model\Rule $rule * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param float $qty * @return \Magento\SalesRule\Model\Rule\Action\Discount\Data */ public function calculate($rule, $item, $qty) { /** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */ $discountData = $this->discountFactory->create(); $ruleTotals = $this->validator->getRuleItemTotalsInfo($rule->getId()); $quote = $item->getQuote(); $address = $item->getAddress(); $itemPrice = $this->validator->getItemPrice($item); $baseItemPrice = $this->validator->getItemBasePrice($item); $itemOriginalPrice = $this->validator->getItemOriginalPrice($item); $baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item); /** * prevent applying whole cart discount for every shipping order, but only for first order */ if ($quote->getIsMultiShipping()) { $usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId()); if ($usedForAddressId && $usedForAddressId != $address->getId()) { return $discountData; } else { $this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId()); } } $cartRules = $address->getCartFixedRules(); if (!isset($cartRules[$rule->getId()])) { $cartRules[$rule->getId()] = $rule->getDiscountAmount(); } if ($cartRules[$rule->getId()] > 0) { $store = $quote->getStore(); if ($ruleTotals['items_count'] <= 1) { $quoteAmount = $store->convertPrice($cartRules[$rule->getId()]); $baseDiscountAmount = min($baseItemPrice * $qty, $cartRules[$rule->getId()]); } else { $discountRate = $baseItemPrice * $qty / $ruleTotals['base_items_price']; $maximumItemDiscount = $rule->getDiscountAmount() * $discountRate; $quoteAmount = $store->convertPrice($maximumItemDiscount); $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount); $this->validator->decrementRuleItemTotalsCount($rule->getId()); } $baseDiscountAmount = $store->roundPrice($baseDiscountAmount); $cartRules[$rule->getId()] -= $baseDiscountAmount; $discountData->setAmount($store->roundPrice(min($itemPrice * $qty, $quoteAmount))); $discountData->setBaseAmount($baseDiscountAmount); $discountData->setOriginalAmount(min($itemOriginalPrice * $qty, $quoteAmount)); $discountData->setBaseOriginalAmount($store->roundPrice($baseItemOriginalPrice)); } $address->setCartFixedRules($cartRules); return $discountData; }
/** * @param \Magento\SalesRule\Model\Rule $rule * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param float $qty * @return \Magento\SalesRule\Model\Rule\Action\Discount\Data */ public function calculate($rule, $item, $qty) { /** @var \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData */ $discountData = $this->discountFactory->create(); $store = $item->getQuote()->getStore(); $itemPrice = $this->validator->getItemPrice($item); $baseItemPrice = $this->validator->getItemBasePrice($item); $itemOriginalPrice = $this->validator->getItemOriginalPrice($item); $baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item); $quoteAmount = $store->convertPrice($rule->getDiscountAmount()); $discountData->setAmount($qty * ($itemPrice - $quoteAmount)); $discountData->setBaseAmount($qty * ($baseItemPrice - $rule->getDiscountAmount())); $discountData->setOriginalAmount($qty * ($itemOriginalPrice - $quoteAmount)); $discountData->setBaseOriginalAmount($qty * ($baseItemOriginalPrice - $rule->getDiscountAmount())); return $discountData; }
/** * Getter for nominal total item details * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $quoteItem * @return array */ public function getTotalItemDetails(\Magento\Sales\Model\Quote\Item\AbstractItem $quoteItem) { return $quoteItem->getNominalTotalDetails(); }
/** * Update tax related fields for quote item * * @param AbstractItem $quoteItem * @param ItemTaxDetails $itemTaxDetails * @param ItemTaxDetails $baseItemTaxDetails * @param Store $store * @return $this */ public function updateItemTaxInfo($quoteItem, $itemTaxDetails, $baseItemTaxDetails, $store) { //The price should be base price $quoteItem->setPrice($baseItemTaxDetails->getPrice()); $quoteItem->setConvertedPrice($itemTaxDetails->getPrice()); $quoteItem->setPriceInclTax($itemTaxDetails->getPriceInclTax()); $quoteItem->setRowTotal($itemTaxDetails->getRowTotal()); $quoteItem->setRowTotalInclTax($itemTaxDetails->getRowTotalInclTax()); $quoteItem->setTaxAmount($itemTaxDetails->getRowTax()); $quoteItem->setTaxPercent($itemTaxDetails->getTaxPercent()); $quoteItem->setHiddenTaxAmount($itemTaxDetails->getDiscountTaxCompensationAmount()); $quoteItem->setBasePrice($baseItemTaxDetails->getPrice()); $quoteItem->setBasePriceInclTax($baseItemTaxDetails->getPriceInclTax()); $quoteItem->setBaseRowTotal($baseItemTaxDetails->getRowTotal()); $quoteItem->setBaseRowTotalInclTax($baseItemTaxDetails->getRowTotalInclTax()); $quoteItem->setBaseTaxAmount($baseItemTaxDetails->getRowTax()); $quoteItem->setTaxPercent($baseItemTaxDetails->getTaxPercent()); $quoteItem->setBaseHiddenTaxAmount($baseItemTaxDetails->getDiscountTaxCompensationAmount()); //Set discount calculation price, this may be needed by discount collector if ($this->_config->discountTax($store)) { $quoteItem->setDiscountCalculationPrice($itemTaxDetails->getPriceInclTax()); $quoteItem->setBaseDiscountCalculationPrice($baseItemTaxDetails->getPriceInclTax()); } else { $quoteItem->setDiscountCalculationPrice($itemTaxDetails->getPrice()); $quoteItem->setBaseDiscountCalculationPrice($baseItemTaxDetails->getPrice()); } return $this; }
/** * Request shipping rates for entire address or specified address item * Returns true if current selected shipping method code corresponds to one of the found rates * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return bool */ public function requestShippingRates(\Magento\Sales\Model\Quote\Item\AbstractItem $item = null) { /** @var $request \Magento\Sales\Model\Quote\Address\RateRequest */ $request = $this->_rateRequestFactory->create(); $request->setAllItems($item ? array($item) : $this->getAllItems()); $request->setDestCountryId($this->getCountryId()); $request->setDestRegionId($this->getRegionId()); $request->setDestRegionCode($this->getRegionCode()); $request->setDestStreet($this->getStreetFull()); $request->setDestCity($this->getCity()); $request->setDestPostcode($this->getPostcode()); $request->setPackageValue($item ? $item->getBaseRowTotal() : $this->getBaseSubtotal()); $packageWithDiscount = $item ? $item->getBaseRowTotal() - $item->getBaseDiscountAmount() : $this->getBaseSubtotalWithDiscount(); $request->setPackageValueWithDiscount($packageWithDiscount); $request->setPackageWeight($item ? $item->getRowWeight() : $this->getWeight()); $request->setPackageQty($item ? $item->getQty() : $this->getItemQty()); /** * Need for shipping methods that use insurance based on price of physical products */ $packagePhysicalValue = $item ? $item->getBaseRowTotal() : $this->getBaseSubtotal() - $this->getBaseVirtualAmount(); $request->setPackagePhysicalValue($packagePhysicalValue); $request->setFreeMethodWeight($item ? 0 : $this->getFreeMethodWeight()); /** * Store and website identifiers need specify from quote */ /*$request->setStoreId($this->_storeManager->getStore()->getId()); $request->setWebsiteId($this->_storeManager->getStore()->getWebsiteId());*/ $request->setStoreId($this->getQuote()->getStore()->getId()); $request->setWebsiteId($this->getQuote()->getStore()->getWebsiteId()); $request->setFreeShipping($this->getFreeShipping()); /** * Currencies need to convert in free shipping */ $request->setBaseCurrency($this->getQuote()->getStore()->getBaseCurrency()); $request->setPackageCurrency($this->getQuote()->getStore()->getCurrentCurrency()); $request->setLimitCarrier($this->getLimitCarrier()); $request->setBaseSubtotalInclTax($this->getBaseSubtotalInclTax()); $result = $this->_rateCollector->create()->collectRates($request)->getResult(); $found = false; if ($result) { $shippingRates = $result->getAllRates(); foreach ($shippingRates as $shippingRate) { $rate = $this->_addressRateFactory->create()->importShippingRate($shippingRate); if (!$item) { $this->addShippingRate($rate); } if ($this->getShippingMethod() == $rate->getCode()) { if ($item) { $item->setBaseShippingAmount($rate->getPrice()); } else { /** * possible bug: this should be setBaseShippingAmount(), * see \Magento\Sales\Model\Quote\Address\Total\Shipping::collect() * where this value is set again from the current specified rate price * (looks like a workaround for this bug) */ $this->setShippingAmount($rate->getPrice()); } $found = true; } } } return $found; }
/** * Add extra amount which should be taxable by regular tax * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param float $value * @param float $baseValue * @param float $rowValue * @param float $baseRowValue * @return $this */ protected function _processTaxSettings($item, $value, $baseValue, $rowValue, $baseRowValue) { if ($this->_weeeData->isTaxable($this->_store) && $rowValue) { $item->setExtraTaxableAmount($value)->setBaseExtraTaxableAmount($baseValue)->setExtraRowTaxableAmount($rowValue)->setBaseExtraRowTaxableAmount($baseRowValue); } return $this; }
/** * @param Rule\Action\Discount\Data $discountData * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return $this */ protected function setDiscountData($discountData, $item) { $item->setDiscountAmount($discountData->getAmount()); $item->setBaseDiscountAmount($discountData->getBaseAmount()); $item->setOriginalDiscountAmount($discountData->getOriginalAmount()); $item->setBaseOriginalDiscountAmount($discountData->getBaseOriginalAmount()); return $this; }
/** * Calculate item fixed tax and prepare information for discount and regular taxation * * @param \Magento\Sales\Model\Quote\Address $address * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return void|$this */ protected function _process(\Magento\Sales\Model\Quote\Address $address, $item) { $attributes = $this->weeeData->getProductWeeeAttributes($item->getProduct(), $address, $address->getQuote()->getBillingAddress(), $this->_store->getWebsiteId()); $productTaxes = array(); $totalValueInclTax = 0; $baseTotalValueInclTax = 0; $totalRowValueInclTax = 0; $baseTotalRowValueInclTax = 0; $totalValueExclTax = 0; $baseTotalValueExclTax = 0; $totalRowValueExclTax = 0; $baseTotalRowValueExclTax = 0; $associatedTaxables = $item->getAssociatedTaxables(); if (!$associatedTaxables) { $associatedTaxables = []; } foreach ($attributes as $key => $attribute) { $title = $attribute->getName(); $baseValueExclTax = $baseValueInclTax = $attribute->getAmount(); $valueExclTax = $valueInclTax = $this->_store->roundPrice($this->_store->convertPrice($baseValueExclTax)); $rowValueInclTax = $rowValueExclTax = $this->_store->roundPrice($valueInclTax * $item->getTotalQty()); $baseRowValueInclTax = $this->_store->roundPrice($baseValueInclTax * $item->getTotalQty()); $baseRowValueExclTax = $baseRowValueInclTax; $totalValueInclTax += $valueInclTax; $baseTotalValueInclTax += $baseValueInclTax; $totalRowValueInclTax += $rowValueInclTax; $baseTotalRowValueInclTax += $baseRowValueInclTax; $totalValueExclTax += $valueExclTax; $baseTotalValueExclTax += $baseValueExclTax; $totalRowValueExclTax += $rowValueExclTax; $baseTotalRowValueExclTax += $baseRowValueExclTax; $productTaxes[] = array('title' => $title, 'base_amount' => $baseValueExclTax, 'amount' => $valueExclTax, 'row_amount' => $rowValueExclTax, 'base_row_amount' => $baseRowValueExclTax, 'base_amount_incl_tax' => $baseValueInclTax, 'amount_incl_tax' => $valueInclTax, 'row_amount_incl_tax' => $rowValueInclTax, 'base_row_amount_incl_tax' => $baseRowValueInclTax); if ($this->weeeData->isTaxable($this->_store)) { $itemTaxCalculationId = $item->getTaxCalculationItemId(); $weeeItemCode = self::ITEM_CODE_WEEE_PREFIX . $this->getNextIncrement(); $weeeItemCode .= '-' . $title; $associatedTaxables[] = [CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_TYPE => self::ITEM_TYPE, CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_CODE => $weeeItemCode, CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_UNIT_PRICE => $valueExclTax, CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_BASE_UNIT_PRICE => $baseValueExclTax, CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_QUANTITY => $item->getQty(), CommonTaxCollector::KEY_ASSOCIATED_TAXABLE_TAX_CLASS_ID => $item->getProduct()->getTaxClassId()]; $this->weeeCodeToItemMap[$weeeItemCode] = $item; } } $item->setAssociatedTaxables($associatedTaxables); $item->setWeeeTaxAppliedAmount($totalValueExclTax)->setBaseWeeeTaxAppliedAmount($baseTotalValueExclTax)->setWeeeTaxAppliedRowAmount($totalRowValueExclTax)->setBaseWeeeTaxAppliedRowAmnt($baseTotalRowValueExclTax); $item->setWeeeTaxAppliedAmountInclTax($totalValueInclTax)->setBaseWeeeTaxAppliedAmountInclTax($baseTotalValueInclTax)->setWeeeTaxAppliedRowAmountInclTax($totalRowValueInclTax)->setBaseWeeeTaxAppliedRowAmntInclTax($baseTotalRowValueInclTax); $this->processTotalAmount($address, $totalRowValueExclTax, $baseTotalRowValueExclTax, $totalRowValueInclTax, $baseTotalRowValueInclTax); $this->weeeData->setApplied($item, array_merge($this->weeeData->getApplied($item), $productTaxes)); }
/** * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param int[] $appliedRuleIds * @return $this */ public function setAppliedRuleIds(\Magento\Sales\Model\Quote\Item\AbstractItem $item, array $appliedRuleIds) { $address = $item->getAddress(); $quote = $item->getQuote(); $item->setAppliedRuleIds(join(',', $appliedRuleIds)); $address->setAppliedRuleIds($this->validatorUtility->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds)); $quote->setAppliedRuleIds($this->validatorUtility->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds)); return $this; }
/** * Return item base price * * @param AbstractItem $item * @return float */ public function getItemBasePrice($item) { $price = $item->getDiscountCalculationPrice(); return $price !== null ? $item->getBaseDiscountCalculationPrice() : $item->getBaseCalculationPrice(); }
/** * Whether the item row total may be compounded with others * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return bool */ public function getIsItemRowTotalCompoundable(\Magento\Sales\Model\Quote\Item\AbstractItem $item) { if ($item->getData("skip_compound_{$this->_itemRowTotalKey}")) { return false; } return true; }
/** * Set item for render * * @param QuoteItem|OrderItem|InvoiceItem|CreditMemoItem $item * @return $this */ public function setItem($item) { $this->item = $item; $this->storeId = $item->getStoreId(); return $this; }
/** * Return discount item qty * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param \Magento\SalesRule\Model\Rule $rule * @return int */ public function getItemQty($item, $rule) { $qty = $item->getTotalQty(); $discountQty = $rule->getDiscountQty(); return $discountQty ? min($qty, $discountQty) : $qty; }
/** * @return $this|\Magento\Sales\Model\Quote\Item\AbstractItem */ protected function _beforeSave() { parent::_beforeSave(); if ($this->getAddress()) { $this->setQuoteAddressId($this->getAddress()->getId()); } return $this; }
/** * Prevent compounding nominal subtotal in case if the trial payment exists * * @param \Magento\Sales\Model\Quote\Address $address * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return void * @see \Magento\Sales\Model\Quote\Address\Total\Nominal\Subtotal */ protected function _afterCollectSuccess($address, $item) { $item->setData('skip_compound_row_total', true); }
/** * Recalculate child discount. Separate discount between children * * @param AbstractItem $child * @return $this */ protected function _recalculateChildDiscount($child) { $item = $child->getParentItem(); $prices = array('base' => $item->getBaseOriginalPrice(), 'current' => $item->getPrice()); $keys = array('discount_amount', 'original_discount_amount'); foreach ($keys as $key) { $child->setData($key, $child->getData($key) * $child->getPrice() / $prices['current']); $child->setData('base_' . $key, $child->getData('base_' . $key) * $child->getPrice() / $prices['base']); } return $this; }
/** * Convert quote item to order item * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @return \Magento\Sales\Model\Order\Item */ public function itemToOrderItem(\Magento\Sales\Model\Quote\Item\AbstractItem $item) { $orderItem = $this->_orderItemFactory->create()->setStoreId($item->getStoreId())->setQuoteItemId($item->getId())->setQuoteParentItemId($item->getParentItemId())->setProductId($item->getProductId())->setProductType($item->getProductType())->setQtyBackordered($item->getBackorders())->setProduct($item->getProduct())->setBaseOriginalPrice($item->getBaseOriginalPrice()); $options = $item->getProductOrderOptions(); if (!$options) { $options = $item->getProduct()->getTypeInstance()->getOrderOptions($item->getProduct()); } $orderItem->setProductOptions($options); $this->_objectCopyService->copyFieldsetToTarget('sales_convert_quote_item', 'to_order_item', $item, $orderItem); if ($item->getParentItem()) { $orderItem->setQtyOrdered($orderItem->getQtyOrdered() * $item->getParentItem()->getQty()); } if (!$item->getNoDiscount()) { $this->_objectCopyService->copyFieldsetToTarget('sales_convert_quote_item', 'to_order_item_discount', $item, $orderItem); } return $orderItem; }
/** * @param AbstractItem $item * @return float */ public function getBaseSubtotalInclTax($item) { $tax = $item->getBaseTaxAmount() + $item->getBaseDiscountTaxCompensation(); return $item->getBaseRowTotal() + $tax; }
/** * Sets applied weee taxes * * @param \Magento\Sales\Model\Quote\Item\AbstractItem $item * @param array $value * @return $this */ public function setApplied($item, $value) { $item->setWeeeTaxApplied(serialize($value)); return $this; }
/** * Clone quote item * * @return $this */ public function __clone() { parent::__clone(); $options = $this->getOptions(); $this->_quote = null; $this->_options = array(); $this->_optionsByCode = array(); foreach ($options as $option) { $this->addOption(clone $option); } return $this; }
/** * Calculate base total amount for the item * * @param QuoteItem|Item|InvoiceItem|CreditmemoItem $item * @return mixed */ public function getBaseTotalAmount($item) { $baseTotalAmount = $item->getBaseRowTotal() - $item->getBaseDiscountAmount(); return $baseTotalAmount; }