/** * Prepare order data for refund * * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return void */ protected function prepareOrder(\Magento\Sales\Model\Order\Creditmemo $creditmemo) { $order = $creditmemo->getOrder(); $baseOrderRefund = $this->priceCurrency->round($order->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal()); $orderRefund = $this->priceCurrency->round($order->getTotalRefunded() + $creditmemo->getGrandTotal()); $order->setBaseTotalRefunded($baseOrderRefund); $order->setTotalRefunded($orderRefund); $order->setBaseSubtotalRefunded($order->getBaseSubtotalRefunded() + $creditmemo->getBaseSubtotal()); $order->setSubtotalRefunded($order->getSubtotalRefunded() + $creditmemo->getSubtotal()); $order->setBaseTaxRefunded($order->getBaseTaxRefunded() + $creditmemo->getBaseTaxAmount()); $order->setTaxRefunded($order->getTaxRefunded() + $creditmemo->getTaxAmount()); $order->setBaseDiscountTaxCompensationRefunded($order->getBaseDiscountTaxCompensationRefunded() + $creditmemo->getBaseDiscountTaxCompensationAmount()); $order->setDiscountTaxCompensationRefunded($order->getDiscountTaxCompensationRefunded() + $creditmemo->getDiscountTaxCompensationAmount()); $order->setBaseShippingRefunded($order->getBaseShippingRefunded() + $creditmemo->getBaseShippingAmount()); $order->setShippingRefunded($order->getShippingRefunded() + $creditmemo->getShippingAmount()); $order->setBaseShippingTaxRefunded($order->getBaseShippingTaxRefunded() + $creditmemo->getBaseShippingTaxAmount()); $order->setShippingTaxRefunded($order->getShippingTaxRefunded() + $creditmemo->getShippingTaxAmount()); $order->setAdjustmentPositive($order->getAdjustmentPositive() + $creditmemo->getAdjustmentPositive()); $order->setBaseAdjustmentPositive($order->getBaseAdjustmentPositive() + $creditmemo->getBaseAdjustmentPositive()); $order->setAdjustmentNegative($order->getAdjustmentNegative() + $creditmemo->getAdjustmentNegative()); $order->setBaseAdjustmentNegative($order->getBaseAdjustmentNegative() + $creditmemo->getBaseAdjustmentNegative()); $order->setDiscountRefunded($order->getDiscountRefunded() + $creditmemo->getDiscountAmount()); $order->setBaseDiscountRefunded($order->getBaseDiscountRefunded() + $creditmemo->getBaseDiscountAmount()); if ($creditmemo->getDoTransaction()) { $order->setTotalOnlineRefunded($order->getTotalOnlineRefunded() + $creditmemo->getGrandTotal()); $order->setBaseTotalOnlineRefunded($order->getBaseTotalOnlineRefunded() + $creditmemo->getBaseGrandTotal()); } else { $order->setTotalOfflineRefunded($order->getTotalOfflineRefunded() + $creditmemo->getGrandTotal()); $order->setBaseTotalOfflineRefunded($order->getBaseTotalOfflineRefunded() + $creditmemo->getBaseGrandTotal()); } $order->setBaseTotalInvoicedCost($order->getBaseTotalInvoicedCost() - $creditmemo->getBaseCost()); }
/** * Filter value * * @param float $value * @return string */ public function filter($value) { $value = $this->_localeFormat->getNumber($value); $value = $this->priceCurrency->round($this->_rate * $value); $value = sprintf("%f", $value); return $this->_currency->toCurrency($value); }
/** * MOBI-486: Add partial payment data to totals are requested with REST API. * MOBI-489: Add partial payment configuration to totals extension attributes. * * @param \Magento\Quote\Model\Cart\CartTotalRepository $subject * @param \Closure $proceed * @param $cartId * @return \Magento\Quote\Api\Data\TotalsInterface */ public function aroundGet(\Magento\Quote\Model\Cart\CartTotalRepository $subject, \Closure $proceed, $cartId) { /** @var \Magento\Quote\Model\Cart\Totals $result */ $result = $proceed($cartId); /* Get partial method configuration */ $isPartialEnabled = $this->_hlpCfg->getWalletPartialEnabled(); if ($isPartialEnabled) { // $partialMaxPercent = $this->_hlpCfg->getWalletPartialPercent(); // /** @var \Magento\Quote\Api\Data\TotalExtensionInterface $exts */ // $exts = $this->_factTotalExt->create(); // /** @var \Praxigento\Wallet\Api\Data\Config\Payment\Method $extData */ // $extData = new \Praxigento\Wallet\Api\Data\Config\Payment\Method(); // $extData->setPartialMaxPercent($partialMaxPercent); // $extData->setIsPartialEnabled($isPartialEnabled); // $exts->setPraxigentoWalletPaymentConfig($extData); // $result->setExtensionAttributes($exts); /* get partial data from repository */ /** @var \Praxigento\Wallet\Data\Entity\Partial\Quote $found */ $found = $this->_repoPartialQuote->getById($cartId); if ($found) { $basePartial = $found->getBasePartialAmount(); $basePartial = $this->_hlpPriceCurrency->round($basePartial); /* add current partial total to segment */ $segments = $result->getTotalSegments(); /** @var \Magento\Quote\Api\Data\TotalSegmentInterface $seg */ $seg = $this->_manObj->create(\Magento\Quote\Api\Data\TotalSegmentInterface::class); $seg->setCode(self::TOTAL_SEGMENT); $seg->setValue($basePartial); $segments[self::TOTAL_SEGMENT] = $seg; $result->setTotalSegments($segments); } } return $result; }
/** * Get credit memo shipping amount depend on configuration settings * * @return float */ public function getShippingAmount() { $source = $this->getSource(); if ($this->_taxConfig->displaySalesShippingInclTax($source->getOrder()->getStoreId())) { $shipping = $source->getBaseShippingInclTax(); } else { $shipping = $source->getBaseShippingAmount(); } return $this->priceCurrency->round($shipping) * 1; }
/** * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @throws \Magento\Framework\Exception\LocalizedException */ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) { $order = $creditmemo->getOrder(); $allowedAmount = $order->getShippingAmount() - $order->getShippingRefunded(); $baseAllowedAmount = $order->getBaseShippingAmount() - $order->getBaseShippingRefunded(); $orderShippingAmount = $order->getShippingAmount(); $orderBaseShippingAmount = $order->getBaseShippingAmount(); $orderShippingInclTax = $order->getShippingInclTax(); $orderBaseShippingInclTax = $order->getBaseShippingInclTax(); $shippingAmount = $baseShippingAmount = $shippingInclTax = $baseShippingInclTax = 0; /** * Check if shipping amount was specified (from invoice or another source). * Using has magic method to allow setting 0 as shipping amount. */ if ($creditmemo->hasBaseShippingAmount()) { $baseShippingAmount = $this->priceCurrency->round($creditmemo->getBaseShippingAmount()); /* * Rounded allowed shipping refund amount is the highest acceptable shipping refund amount. * Shipping refund amount shouldn't cause errors, if it doesn't exceed that limit. * Note: ($x < $y + 0.0001) means ($x <= $y) for floats */ if ($baseShippingAmount < $this->priceCurrency->round($baseAllowedAmount) + 0.0001) { $ratio = 0; if ($orderBaseShippingAmount > 0) { $ratio = $baseShippingAmount / $orderBaseShippingAmount; } /* * Shipping refund amount should be equated to allowed refund amount, * if it exceeds that limit. * Note: ($x > $y - 0.0001) means ($x >= $y) for floats */ if ($baseShippingAmount > $baseAllowedAmount - 0.0001) { $shippingAmount = $allowedAmount; $baseShippingAmount = $baseAllowedAmount; } else { $shippingAmount = $this->priceCurrency->round($orderShippingAmount * $ratio); } $shippingInclTax = $this->priceCurrency->round($orderShippingInclTax * $ratio); $baseShippingInclTax = $this->priceCurrency->round($orderBaseShippingInclTax * $ratio); } else { $baseAllowedAmount = $order->getBaseCurrency()->format($baseAllowedAmount, null, false); throw new \Magento\Framework\Exception\LocalizedException(__('Maximum shipping amount allowed to refund is: %1', $baseAllowedAmount)); } } else { $shippingAmount = $allowedAmount; $baseShippingAmount = $baseAllowedAmount; $allowedTaxAmount = $order->getShippingTaxAmount() - $order->getShippingTaxRefunded(); $baseAllowedTaxAmount = $order->getBaseShippingTaxAmount() - $order->getBaseShippingTaxRefunded(); $shippingInclTax = $this->priceCurrency->round($allowedAmount + $allowedTaxAmount); $baseShippingInclTax = $this->priceCurrency->round($baseAllowedAmount + $baseAllowedTaxAmount); } $creditmemo->setShippingAmount($shippingAmount); $creditmemo->setBaseShippingAmount($baseShippingAmount); $creditmemo->setShippingInclTax($shippingInclTax); $creditmemo->setBaseShippingInclTax($baseShippingInclTax); $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $shippingAmount); $creditmemo->setBaseGrandTotal($creditmemo->getBaseGrandTotal() + $baseShippingAmount); return $this; }
/** * @param AbstractItem $item * @return float */ public function getBasePriceInclTax($item) { $qty = $item->getQty() ? $item->getQty() : ($item->getQtyOrdered() ? $item->getQtyOrdered() : 1); $taxAmount = $item->getBaseTaxAmount() + $item->getBaseDiscountTaxCompensation(); $price = floatval($qty) ? ($item->getBaseRowTotal() + $taxAmount) / $qty : 0; return $this->priceCurrency->round($price); }
/** * 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] = 1.0E-7; } foreach ($item->getChildren() as $child) { $ratio = $child->getBaseRowTotal() / $parentBaseRowTotal; 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; }
/** * Prepare order based on quote address * * @param \Magento\Quote\Model\Quote\Address $address * @return \Magento\Sales\Model\Order * @throws \Magento\Checkout\Exception */ protected function _prepareOrder(\Magento\Quote\Model\Quote\Address $address) { $quote = $this->getQuote(); $quote->unsReservedOrderId(); $quote->reserveOrderId(); $quote->collectTotals(); $order = $this->quoteAddressToOrder->convert($address); $order->setQuote($quote); $order->setBillingAddress($this->quoteAddressToOrderAddress->convert($quote->getBillingAddress())); if ($address->getAddressType() == 'billing') { $order->setIsVirtual(1); } else { $order->setShippingAddress($this->quoteAddressToOrderAddress->convert($address)); } $order->setPayment($this->quotePaymentToOrderPayment->convert($quote->getPayment())); if ($this->priceCurrency->round($address->getGrandTotal()) == 0) { $order->getPayment()->setMethod('free'); } foreach ($address->getAllItems() as $item) { $_quoteItem = $item->getQuoteItem(); if (!$_quoteItem) { throw new \Magento\Checkout\Exception(__('Item not found or already ordered')); } $item->setProductType($_quoteItem->getProductType())->setProductOptions($_quoteItem->getProduct()->getTypeInstance()->getOrderOptions($_quoteItem->getProduct())); $orderItem = $this->quoteItemToOrderItem->convert($item); if ($item->getParentItem()) { $orderItem->setParentItem($order->getItemByQuoteItemId($item->getParentItem()->getId())); } $order->addItem($orderItem); } return $order; }
/** * Round price considering delta * * @param float $price * @param bool $negative Indicates if we perform addition (true) or subtraction (false) of rounded value * @return float */ public function deltaRound($price, $negative = false) { $roundedPrice = $price; if ($roundedPrice) { if ($negative) { $this->_delta = -$this->_delta; } $price += $this->_delta; $roundedPrice = $this->priceCurrency->round($price); $this->_delta = $price - $roundedPrice; if ($negative) { $this->_delta = -$this->_delta; } } return $roundedPrice; }
/** * @param array $ruleData * @param null $productData * @return float */ protected function calcRuleProductPrice($ruleData, $productData = null) { if ($productData !== null && isset($productData['rule_price'])) { $productPrice = $productData['rule_price']; } else { $productPrice = $ruleData['default_price']; } switch ($ruleData['action_operator']) { case 'to_fixed': $productPrice = min($ruleData['action_amount'], $productPrice); break; case 'to_percent': $productPrice = $productPrice * $ruleData['action_amount'] / 100; break; case 'by_fixed': $productPrice = max(0, $productPrice - $ruleData['action_amount']); break; case 'by_percent': $productPrice = $productPrice * (1 - $ruleData['action_amount'] / 100); break; default: $productPrice = 0; } return $this->priceCurrency->round($productPrice); }
/** * Calculate amount for dynamic bundle product * * @param float $basePriceValue * @param Product $bundleProduct * @param \Magento\Bundle\Pricing\Price\BundleSelectionPrice[] $selectionPriceList * @param null|string $exclude * @return \Magento\Framework\Pricing\Amount\AmountInterface */ protected function calculateDynamicBundleAmount($basePriceValue, $bundleProduct, $selectionPriceList, $exclude) { $fullAmount = 0.0; $adjustments = []; $amountList = [$this->calculator->getAmount($basePriceValue, $bundleProduct, $exclude)]; /** @var $option \Magento\Bundle\Model\Option */ foreach ($selectionPriceList as $selectionPrice) { $amountList[] = $selectionPrice->getAmount(); } /** @var Store $store */ $store = $bundleProduct->getStore(); $roundingMethod = $this->taxHelper->getCalculationAgorithm($store); /** @var \Magento\Framework\Pricing\Amount\AmountInterface $itemAmount */ foreach ($amountList as $itemAmount) { if ($roundingMethod != TaxCalculationServiceInterface::CALC_TOTAL_BASE) { //We need to round the individual selection first $fullAmount += $this->priceCurrency->round($itemAmount->getValue()); foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) { $adjustment = $this->priceCurrency->round($adjustment); $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment; } } else { $fullAmount += $itemAmount->getValue(); foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) { $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment; } } } if ($exclude && isset($adjustments[$exclude])) { $fullAmount -= $adjustments[$exclude]; unset($adjustments[$exclude]); } return $this->amountFactory->create($fullAmount, $adjustments); }
/** * Calculate item row total price * * @return $this */ public function calcRowTotal() { $qty = $this->getTotalQty(); // Round unit price before multiplying to prevent losing 1 cent on subtotal $total = $this->priceCurrency->round($this->getCalculationPriceOriginal()) * $qty; $baseTotal = $this->priceCurrency->round($this->getBaseCalculationPriceOriginal()) * $qty; $this->setRowTotal($this->priceCurrency->round($total)); $this->setBaseRowTotal($this->priceCurrency->round($baseTotal)); return $this; }
/** * Convert price from default currency to current currency * * @param float $price * @param bool $round * @return float */ protected function _convertPrice($price, $round = false) { if (empty($price)) { return 0; } $price = $this->priceCurrency->convert($price); if ($round) { $price = $this->priceCurrency->round($price); } return $price; }
/** * Process row amount based on FPT total amount configuration setting * * @param \Magento\Quote\Model\Quote\Address\Total $total * @param float $rowValueExclTax * @param float $baseRowValueExclTax * @param float $rowValueInclTax * @param float $baseRowValueInclTax * @return $this */ protected function processTotalAmount($total, $rowValueExclTax, $baseRowValueExclTax, $rowValueInclTax, $baseRowValueInclTax) { if (!$this->weeeData->isTaxable($this->_store)) { //Accumulate the values. Will be used later in the 'weee tax' collector $this->weeeTotalExclTax += $this->priceCurrency->round($rowValueExclTax); $this->weeeBaseTotalExclTax += $this->priceCurrency->round($baseRowValueExclTax); } //This value is used to calculate shipping cost; it will be overridden by tax collector $total->setSubtotalInclTax($total->getSubtotalInclTax() + $this->priceCurrency->round($rowValueInclTax)); $total->setBaseSubtotalInclTax($total->getBaseSubtotalInclTax() + $this->priceCurrency->round($baseRowValueInclTax)); return $this; }
/** * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo * @return bool * @throws \Magento\Framework\Exception\LocalizedException */ protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo) { if ($creditmemo->getId()) { throw new \Magento\Framework\Exception\LocalizedException(__('We cannot register an existing credit memo.')); } $baseOrderRefund = $this->priceCurrency->round($creditmemo->getOrder()->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal()); if ($baseOrderRefund > $this->priceCurrency->round($creditmemo->getOrder()->getBaseTotalPaid())) { $baseAvailableRefund = $creditmemo->getOrder()->getBaseTotalPaid() - $creditmemo->getOrder()->getBaseTotalRefunded(); throw new \Magento\Framework\Exception\LocalizedException(__('The most money available to refund is %1.', $creditmemo->getOrder()->formatBasePrice($baseAvailableRefund))); } return true; }
/** * Calculate amount for dynamic bundle product * * @param float $basePriceValue * @param Product $bundleProduct * @param \Magento\Bundle\Pricing\Price\BundleSelectionPrice[] $selectionPriceList * @param null|bool|string|array $exclude * @return \Magento\Framework\Pricing\Amount\AmountInterface * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function calculateDynamicBundleAmount($basePriceValue, $bundleProduct, $selectionPriceList, $exclude) { $fullAmount = 0.0; $adjustments = []; $i = 0; $amountList[$i]['amount'] = $this->calculator->getAmount($basePriceValue, $bundleProduct, $exclude); $amountList[$i]['quantity'] = 1; foreach ($selectionPriceList as $selectionPrice) { ++$i; $amountList[$i]['amount'] = $selectionPrice->getAmount(); // always honor the quantity given $amountList[$i]['quantity'] = $selectionPrice->getQuantity(); } /** @var Store $store */ $store = $bundleProduct->getStore(); $roundingMethod = $this->taxHelper->getCalculationAlgorithm($store); foreach ($amountList as $amountInfo) { /** @var \Magento\Framework\Pricing\Amount\AmountInterface $itemAmount */ $itemAmount = $amountInfo['amount']; $qty = $amountInfo['quantity']; if ($roundingMethod != TaxCalculationInterface::CALC_TOTAL_BASE) { //We need to round the individual selection first $fullAmount += $this->priceCurrency->round($itemAmount->getValue()) * $qty; foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) { $adjustment = $this->priceCurrency->round($adjustment) * $qty; $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment; } } else { $fullAmount += $itemAmount->getValue() * $qty; foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) { $adjustment = $adjustment * $qty; $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment; } } } if (is_array($exclude) == false) { if ($exclude && isset($adjustments[$exclude])) { $fullAmount -= $adjustments[$exclude]; unset($adjustments[$exclude]); } } else { foreach ($exclude as $oneExclusion) { if ($oneExclusion && isset($adjustments[$oneExclusion])) { $fullAmount -= $adjustments[$oneExclusion]; unset($adjustments[$oneExclusion]); } } } return $this->amountFactory->create($fullAmount, $adjustments); }
/** * Process "delta" rounding * * @param \Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item * @return $this * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ public function deltaRoundingFix(\Magento\SalesRule\Model\Rule\Action\Discount\Data $discountData, \Magento\Quote\Model\Quote\Item\AbstractItem $item) { $store = $item->getQuote()->getStore(); $discountAmount = $discountData->getAmount(); $baseDiscountAmount = $discountData->getBaseAmount(); //TODO Seems \Magento\Quote\Model\Quote\Item\AbstractItem::getDiscountPercent() returns float value //that can not be used as array index $percentKey = $item->getDiscountPercent(); if ($percentKey) { $delta = isset($this->_roundingDeltas[$percentKey]) ? $this->_roundingDeltas[$percentKey] : 0; $baseDelta = isset($this->_baseRoundingDeltas[$percentKey]) ? $this->_baseRoundingDeltas[$percentKey] : 0; $discountAmount += $delta; $baseDiscountAmount += $baseDelta; $this->_roundingDeltas[$percentKey] = $discountAmount - $this->priceCurrency->round($discountAmount); $this->_baseRoundingDeltas[$percentKey] = $baseDiscountAmount - $this->priceCurrency->round($baseDiscountAmount); } $discountData->setAmount($this->priceCurrency->round($discountAmount)); $discountData->setBaseAmount($this->priceCurrency->round($baseDiscountAmount)); return $this; }
/** * Get calculated taxes for each tax class * * This method returns array with format: * array( * $index => array( * 'tax_amount' => $taxAmount, * 'base_tax_amount' => $baseTaxAmount, * 'title' => $title, * 'percent' => $percent * ) * ) * * @param \Magento\Sales\Model\Order|\Magento\Sales\Model\Order\Invoice|\Magento\Sales\Model\Order\Creditmemo $source * @return array */ public function getCalculatedTaxes($source) { $taxClassAmount = []; if (empty($source)) { return $taxClassAmount; } $current = $source; if ($source instanceof Invoice || $source instanceof Creditmemo) { $source = $current->getOrder(); } if ($current == $source) { $taxClassAmount = $this->calculateTaxForOrder($current); } else { $taxClassAmount = $this->calculateTaxForItems($source, $current); } foreach ($taxClassAmount as $key => $tax) { $taxClassAmount[$key]['tax_amount'] = $this->priceCurrency->round($tax['tax_amount']); $taxClassAmount[$key]['base_tax_amount'] = $this->priceCurrency->round($tax['base_tax_amount']); } return array_values($taxClassAmount); }
/** * @param string $amount * @return $this */ public function setAdjustmentNegative($amount) { $amount = trim($amount); if (substr($amount, -1) == '%') { $amount = (double) substr($amount, 0, -1); $amount = $this->getOrder()->getGrandTotal() * $amount / 100; } $amount = $this->priceCurrency->round($amount); $this->setData('base_adjustment_negative', $amount); $amount = $this->priceCurrency->round($amount * $this->getOrder()->getBaseToOrderRate()); $this->setData('adjustment_negative', $amount); return $this; }
/** * Get calculated taxes for each tax class * * This method returns array with format: * array( * $index => array( * 'tax_amount' => $taxAmount, * 'base_tax_amount' => $baseTaxAmount, * 'title' => $title, * 'percent' => $percent * ) * ) * * @param \Magento\Sales\Model\Order $source * @return array */ public function getCalculatedTaxes($source) { if ($this->_coreRegistry->registry('current_invoice')) { $current = $this->_coreRegistry->registry('current_invoice'); } elseif ($this->_coreRegistry->registry('current_creditmemo')) { $current = $this->_coreRegistry->registry('current_creditmemo'); } else { $current = $source; } $taxClassAmount = array(); if ($current && $source) { if ($current == $source) { $orderTaxDetails = $this->orderTaxService->getOrderTaxDetails($current->getId()); $appliedTaxes = $orderTaxDetails->getAppliedTaxes(); foreach ($appliedTaxes as $appliedTax) { $taxCode = $appliedTax->getCode(); $taxClassAmount[$taxCode]['tax_amount'] = $appliedTax->getAmount(); $taxClassAmount[$taxCode]['base_tax_amount'] = $appliedTax->getBaseAmount(); $taxClassAmount[$taxCode]['title'] = $appliedTax->getTitle(); $taxClassAmount[$taxCode]['percent'] = $appliedTax->getPercent(); } } else { $orderTaxDetails = $this->orderTaxService->getOrderTaxDetails($source->getId()); // Apply any taxes for shipping $shippingTaxAmount = $current->getShippingTaxAmount(); $originalShippingTaxAmount = $source->getShippingTaxAmount(); if ($shippingTaxAmount && $originalShippingTaxAmount && $shippingTaxAmount != 0 && $originalShippingTaxAmount != 0) { //An invoice or credit memo can have a different qty than its order $shippingRatio = $shippingTaxAmount / $originalShippingTaxAmount; $itemTaxDetails = $orderTaxDetails->getItems(); foreach ($itemTaxDetails as $itemTaxDetail) { //Aggregate taxable items associated with shipping if ($itemTaxDetail->getType() == \Magento\Sales\Model\Quote\Address::TYPE_SHIPPING) { $taxClassAmount = $this->_aggregateTaxes($taxClassAmount, $itemTaxDetail, $shippingRatio); } } } // Apply any taxes for the items /** @var $item \Magento\Sales\Model\Order\Invoice\Item|\Magento\Sales\Model\Order\Creditmemo\Item */ foreach ($current->getItemsCollection() as $item) { $orderItem = $item->getOrderItem(); $orderItemId = $orderItem->getId(); $orderItemTax = $orderItem->getTaxAmount(); $itemTax = $item->getTaxAmount(); if (!$itemTax || !$orderItemTax) { continue; } //An invoiced item or credit memo item can have a different qty than its order item qty $itemRatio = $itemTax / $orderItemTax; $itemTaxDetails = $orderTaxDetails->getItems(); foreach ($itemTaxDetails as $itemTaxDetail) { //Aggregate taxable items associated with an item if ($itemTaxDetail->getItemId() == $orderItemId || $itemTaxDetail->getAssociatedItemId() == $orderItemId) { $taxClassAmount = $this->_aggregateTaxes($taxClassAmount, $itemTaxDetail, $itemRatio); } } } } // Finish foreach ($taxClassAmount as $key => $tax) { if ($tax['tax_amount'] == 0 && $tax['base_tax_amount'] == 0) { unset($taxClassAmount[$key]); } else { $taxClassAmount[$key]['tax_amount'] = $this->priceCurrency->round($tax['tax_amount']); $taxClassAmount[$key]['base_tax_amount'] = $this->priceCurrency->round($tax['base_tax_amount']); } } $taxClassAmount = array_values($taxClassAmount); } return $taxClassAmount; }
/** * Round up and cast specified amount to float or string * * @param string|float $amount * @param bool $asFloat * @return string|float */ protected function _formatAmount($amount, $asFloat = false) { $amount = $this->priceCurrency->round($amount); return !$asFloat ? (string) $amount : $amount; }
/** * Check whether method is available * * @param \Magento\Sales\Model\Quote|null $quote * @return bool */ public function isAvailable($quote = null) { return parent::isAvailable($quote) && !empty($quote) && $this->priceCurrency->round($quote->getGrandTotal()) == 0; }
/** * @param Product $product * @param null|false|\Magento\Quote\Model\Quote\Address $shipping * @param null|false|\Magento\Quote\Model\Quote\Address $billing * @param Website $website * @param bool $calculateTax * @return \Magento\Framework\Object[] * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function getProductWeeeAttributes($product, $shipping = null, $billing = null, $website = null, $calculateTax = null) { $result = []; $websiteId = $this->_storeManager->getWebsite($website)->getId(); /** @var \Magento\Store\Model\Store $store */ $store = $this->_storeManager->getWebsite($website)->getDefaultGroup()->getDefaultStore(); $allWeee = $this->getWeeeTaxAttributeCodes($store); if (!$allWeee) { return $result; } /** @var \Magento\Tax\Model\Calculation $calculator */ $calculator = $this->_calculationFactory->create(); if ($shipping && $shipping->getCountryId()) { $customerTaxClass = $shipping->getQuote()->getCustomerTaxClassId(); } else { // if customer logged use it default shipping and billing address if ($customerId = $this->_customerSession->getCustomerId()) { $shipping = $this->accountManagement->getDefaultShippingAddress($customerId); $billing = $this->accountManagement->getDefaultBillingAddress($customerId); $customerTaxClass = null; } else { $shippingAddressArray = $this->_customerSession->getDefaultTaxShippingAddress(); $billingAddressArray = $this->_customerSession->getDefaultTaxBillingAddress(); if (!empty($billingAddressArray)) { $billing = new \Magento\Framework\Object($billingAddressArray); } if (!empty($shippingAddressArray)) { $shipping = new \Magento\Framework\Object($shippingAddressArray); } $customerTaxClass = $this->_customerSession->getCustomerTaxClassId(); } } $rateRequest = $calculator->getRateRequest($shipping, $billing, $customerTaxClass, $store); $defaultRateRequest = $calculator->getDefaultRateRequest($store); $productAttributes = $product->getTypeInstance()->getSetAttributes($product); foreach ($productAttributes as $code => $attribute) { if (in_array($code, $allWeee)) { $attributeSelect = $this->getResource()->getReadConnection()->select(); $attributeSelect->from($this->getResource()->getTable('weee_tax'), 'value')->where('attribute_id = ?', (int) $attribute->getId())->where('website_id IN(?)', [$websiteId, 0])->where('country = ?', $rateRequest->getCountryId())->where('state IN(?)', [$rateRequest->getRegionId(), 0])->where('entity_id = ?', (int) $product->getId())->limit(1); $order = ['state ' . \Magento\Framework\DB\Select::SQL_DESC, 'website_id ' . \Magento\Framework\DB\Select::SQL_DESC]; $attributeSelect->order($order); $value = $this->getResource()->getReadConnection()->fetchOne($attributeSelect); if ($value) { $taxAmount = $amount = 0; $amount = $value; if ($calculateTax && $this->weeeConfig->isTaxable($store)) { /** @var \Magento\Tax\Model\Calculation $calculator */ $defaultPercent = $calculator->getRate($defaultRateRequest->setProductClassId($product->getTaxClassId())); $currentPercent = $calculator->getRate($rateRequest->setProductClassId($product->getTaxClassId())); if ($this->_taxData->priceIncludesTax($store)) { $amountInclTax = $value / (100 + $defaultPercent) * (100 + $currentPercent); //round the "golden price" $amountInclTax = $this->priceCurrency->round($amountInclTax); $taxAmount = $amountInclTax - $amountInclTax / (100 + $currentPercent) * 100; $taxAmount = $this->priceCurrency->round($taxAmount); } else { $appliedRates = $this->_calculationFactory->create()->getAppliedRates($rateRequest); if (count($appliedRates) > 1) { $taxAmount = 0; foreach ($appliedRates as $appliedRate) { $taxRate = $appliedRate['percent']; $taxAmount += $this->priceCurrency->round($value * $taxRate / 100); } } else { $taxAmount = $this->priceCurrency->round($value * $currentPercent / 100); } $taxAmount = $this->priceCurrency->round($value * $currentPercent / 100); } } $one = new \Magento\Framework\Object(); $one->setName(__($attribute->getFrontend()->getLabel()))->setAmount($amount)->setTaxAmount($taxAmount)->setCode($attribute->getAttributeCode()); $result[] = $one; } } } return $result; }
/** * Custom setter for 'price' attribute * * @param Entry $entry * @param Product $product * @param mixed $value Fload price value * @param string $name Google Content attribute name * @return Entry */ protected function _setAttributePrice($entry, $product, $value, $name = 'price') { $store = $this->_storeManager->getStore($product->getStoreId()); $price = $this->priceCurrency->convert($value, $store); return $this->_setAttribute($entry, $name, self::ATTRIBUTE_TYPE_FLOAT, sprintf('%.2f', $this->priceCurrency->round($price)), $store->getDefaultCurrencyCode()); }
/** * Retrieve order total due value * * @return float */ public function getBaseTotalDue() { $total = $this->getBaseGrandTotal() - $this->getBaseTotalPaid(); $total = $this->priceCurrency->round($total); return max($total, 0); }
/** * Round tax amount * * @param float $price * @return float */ public function round($price) { return $this->priceCurrency->round($price); }
/** * @param Product $product * @param null|false|\Magento\Quote\Model\Quote\Address $shipping * @param null|false|\Magento\Quote\Model\Quote\Address $billing * @param Website $website * @param bool $calculateTax * @param bool $round * @return \Magento\Framework\DataObject[] * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function getProductWeeeAttributes($product, $shipping = null, $billing = null, $website = null, $calculateTax = null, $round = true) { $result = []; $websiteId = $this->_storeManager->getWebsite($website)->getId(); /** @var \Magento\Store\Model\Store $store */ $store = $this->_storeManager->getWebsite($website)->getDefaultGroup()->getDefaultStore(); $allWeee = $this->getWeeeTaxAttributeCodes($store); if (!$allWeee) { return $result; } /** @var \Magento\Tax\Model\Calculation $calculator */ $calculator = $this->_calculationFactory->create(); $customerId = $this->_customerSession->getCustomerId(); if ($shipping && $shipping->getCountryId()) { $customerTaxClass = $shipping->getQuote()->getCustomerTaxClassId(); } else { // if customer logged use it default shipping and billing address if ($customerId) { $shipping = $this->accountManagement->getDefaultShippingAddress($customerId); $billing = $this->accountManagement->getDefaultBillingAddress($customerId); $customerTaxClass = null; } else { $shippingAddressArray = $this->_customerSession->getDefaultTaxShippingAddress(); $billingAddressArray = $this->_customerSession->getDefaultTaxBillingAddress(); if (!empty($billingAddressArray)) { $billing = new \Magento\Framework\DataObject($billingAddressArray); } if (!empty($shippingAddressArray)) { $shipping = new \Magento\Framework\DataObject($shippingAddressArray); } $customerTaxClass = $this->_customerSession->getCustomerTaxClassId(); } } $rateRequest = $calculator->getRateRequest($shipping, $billing, $customerTaxClass, $store, $customerId); $defaultRateRequest = $calculator->getDefaultRateRequest($store); $productAttributes = $this->getResource()->fetchWeeeTaxCalculationsByEntity($rateRequest->getCountryId(), $rateRequest->getRegionId(), $websiteId, $store->getId(), $product->getId()); foreach ($productAttributes as $attribute) { $value = $attribute['weee_value']; if ($value) { $taxAmount = $amount = 0; $amount = $value; $amountExclTax = $value; if ($calculateTax && $this->weeeConfig->isTaxable($store)) { /** @var \Magento\Tax\Model\Calculation $calculator */ $defaultPercent = $calculator->getRate($defaultRateRequest->setProductClassId($product->getTaxClassId())); $currentPercent = $calculator->getRate($rateRequest->setProductClassId($product->getTaxClassId())); if ($this->_taxData->priceIncludesTax($store)) { $amountInclTax = $value / (100 + $defaultPercent) * (100 + $currentPercent); if ($round) { $amountInclTax = $this->priceCurrency->round($amountInclTax); } $taxAmount = $amountInclTax - $amountInclTax / (100 + $currentPercent) * 100; if ($round) { $taxAmount = $this->priceCurrency->round($taxAmount); } $amountExclTax = $amountInclTax - $taxAmount; } else { $appliedRates = $this->_calculationFactory->create()->getAppliedRates($rateRequest); if (count($appliedRates) > 1) { $taxAmount = 0; foreach ($appliedRates as $appliedRate) { $taxRate = $appliedRate['percent']; if ($round) { $taxAmount += $this->priceCurrency->round($value * $taxRate / 100); } else { $taxAmount += $value * $taxRate / 100; } } } else { if ($round) { $taxAmount = $this->priceCurrency->round($value * $currentPercent / 100); } else { $taxAmount = $value * $currentPercent / 100; } } } } $one = new \Magento\Framework\DataObject(); $one->setName($attribute['label_value'] ? __($attribute['label_value']) : __($attribute['frontend_label']))->setAmount($amount)->setTaxAmount($taxAmount)->setAmountExclTax($amountExclTax)->setCode($attribute['attribute_code']); $result[] = $one; } } return $result; }
/** * Retrieve attribute source value for search * * @param int $attributeId * @param mixed $value * @param int $storeId * @return mixed */ protected function getAttributeValue($attributeId, $value, $storeId) { $attribute = $this->getSearchableAttribute($attributeId); if (!$attribute->getIsSearchable()) { if ($this->engineProvider->get()->allowAdvancedIndex()) { if ($attribute->getAttributeCode() == 'visibility') { return $value; } elseif (!($attribute->getIsVisibleInAdvancedSearch() || $attribute->getIsFilterable() || $attribute->getIsFilterableInSearch() || $attribute->getUsedForSortBy())) { return null; } } else { return null; } } if ($attribute->usesSource()) { if ($this->engineProvider->get()->allowAdvancedIndex()) { return $value; } $attribute->setStoreId($storeId); $value = $attribute->getSource()->getIndexOptionText($value); if (is_array($value)) { $value = implode($this->separator, $value); } elseif (empty($value)) { $inputType = $attribute->getFrontend()->getInputType(); if ($inputType == 'select' || $inputType == 'multiselect') { return null; } } } elseif ($attribute->getBackendType() == 'datetime') { $value = $this->getStoreDate($storeId, $value); } else { $inputType = $attribute->getFrontend()->getInputType(); if ($inputType == 'price') { $value = $this->priceCurrency->round($value); } } $value = preg_replace("#\\s+#siu", ' ', trim(strip_tags($value))); return $value; }
/** * Get product price with all tax settings processing * * @param \Magento\Catalog\Model\Product $product * @param float $price inputted product price * @param bool $includingTax return price include tax flag * @param null|\Magento\Customer\Model\Address\AbstractAddress $shippingAddress * @param null|\Magento\Customer\Model\Address\AbstractAddress $billingAddress * @param null|int $ctc customer tax class * @param null|string|bool|int|\Magento\Store\Model\Store $store * @param bool $priceIncludesTax flag what price parameter contain tax * @param bool $roundPrice * @return float * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function getTaxPrice($product, $price, $includingTax = null, $shippingAddress = null, $billingAddress = null, $ctc = null, $store = null, $priceIncludesTax = null, $roundPrice = true) { if (!$price) { return $price; } $store = $this->_storeManager->getStore($store); if ($this->_taxConfig->needPriceConversion($store)) { if ($priceIncludesTax === null) { $priceIncludesTax = $this->_taxConfig->priceIncludesTax($store); } $shippingAddressDataObject = null; if ($shippingAddress === null) { $shippingAddressDataObject = $this->convertDefaultTaxAddress($this->_customerSession->getDefaultTaxShippingAddress()); } elseif ($shippingAddress instanceof \Magento\Customer\Model\Address\AbstractAddress) { $shippingAddressDataObject = $shippingAddress->getDataModel(); } $billingAddressDataObject = null; if ($billingAddress === null) { $billingAddressDataObject = $this->convertDefaultTaxAddress($this->_customerSession->getDefaultTaxBillingAddress()); } elseif ($billingAddress instanceof \Magento\Customer\Model\Address\AbstractAddress) { $billingAddressDataObject = $billingAddress->getDataModel(); } $taxClassKey = $this->_taxClassKeyFactory->create(); $taxClassKey->setType(TaxClassKeyInterface::TYPE_ID)->setValue($product->getTaxClassId()); if ($ctc === null && $this->_customerSession->getCustomerGroupId() != null) { $ctc = $this->customerGroupRepository->getById($this->_customerSession->getCustomerGroupId())->getTaxClassId(); } $customerTaxClassKey = $this->_taxClassKeyFactory->create(); $customerTaxClassKey->setType(TaxClassKeyInterface::TYPE_ID)->setValue($ctc); $item = $this->_quoteDetailsItemFactory->create(); $item->setQuantity(1)->setCode($product->getSku())->setShortDescription($product->getShortDescription())->setTaxClassKey($taxClassKey)->setIsTaxIncluded($priceIncludesTax)->setType('product')->setUnitPrice($price); $quoteDetails = $this->_quoteDetailsFactory->create(); $quoteDetails->setShippingAddress($shippingAddressDataObject)->setBillingAddress($billingAddressDataObject)->setCustomerTaxClassKey($customerTaxClassKey)->setItems([$item])->setCustomerId($this->_customerSession->getCustomerId()); $storeId = null; if ($store) { $storeId = $store->getId(); } $taxDetails = $this->_taxCalculationService->calculateTax($quoteDetails, $storeId, $roundPrice); $items = $taxDetails->getItems(); $taxDetailsItem = array_shift($items); if ($includingTax !== null) { if ($includingTax) { $price = $taxDetailsItem->getPriceInclTax(); } else { $price = $taxDetailsItem->getPrice(); } } else { switch ($this->_taxConfig->getPriceDisplayType($store)) { case Config::DISPLAY_TYPE_EXCLUDING_TAX: case Config::DISPLAY_TYPE_BOTH: $price = $taxDetailsItem->getPrice(); break; case Config::DISPLAY_TYPE_INCLUDING_TAX: $price = $taxDetailsItem->getPriceInclTax(); break; default: break; } } } if ($roundPrice) { return $this->priceCurrency->round($price); } else { return $price; } }
/** * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @throws \Magento\Framework\Exception\LocalizedException */ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) { $order = $creditmemo->getOrder(); // amounts without tax $orderShippingAmount = $order->getShippingAmount(); $orderBaseShippingAmount = $order->getBaseShippingAmount(); $allowedAmount = $orderShippingAmount - $order->getShippingRefunded(); $baseAllowedAmount = $orderBaseShippingAmount - $order->getBaseShippingRefunded(); // amounts including tax $orderShippingInclTax = $order->getShippingInclTax(); $orderBaseShippingInclTax = $order->getBaseShippingInclTax(); $allowedTaxAmount = $order->getShippingTaxAmount() - $order->getShippingTaxRefunded(); $baseAllowedTaxAmount = $order->getBaseShippingTaxAmount() - $order->getBaseShippingTaxRefunded(); $allowedAmountInclTax = $allowedAmount + $allowedTaxAmount; $baseAllowedAmountInclTax = $baseAllowedAmount + $baseAllowedTaxAmount; // for the credit memo $shippingAmount = $baseShippingAmount = $shippingInclTax = $baseShippingInclTax = 0; // Check if the desired shipping amount to refund was specified (from invoice or another source). if ($creditmemo->hasBaseShippingAmount()) { // For the conditional logic, we will either use amounts that always include tax -OR- never include tax. // The logic uses the 'base' currency to be consistent with what the user (admin) provided as input. $useAmountsWithTax = $this->isSuppliedShippingAmountInclTax($order); // Since the user (admin) supplied 'desiredAmount' it already has tax -OR- does not include tax $desiredAmount = $this->priceCurrency->round($creditmemo->getBaseShippingAmount()); $maxAllowedAmount = $useAmountsWithTax ? $baseAllowedAmountInclTax : $baseAllowedAmount; $originalTotalAmount = $useAmountsWithTax ? $orderBaseShippingInclTax : $orderBaseShippingAmount; // Note: ($x < $y + 0.0001) means ($x <= $y) for floats if ($desiredAmount < $this->priceCurrency->round($maxAllowedAmount) + 0.0001) { // since the admin is returning less than the allowed amount, compute the ratio being returned $ratio = 0; if ($originalTotalAmount > 0) { $ratio = $desiredAmount / $originalTotalAmount; } // capture amounts without tax // Note: ($x > $y - 0.0001) means ($x >= $y) for floats if ($desiredAmount > $maxAllowedAmount - 0.0001) { $shippingAmount = $allowedAmount; $baseShippingAmount = $baseAllowedAmount; } else { $shippingAmount = $this->priceCurrency->round($orderShippingAmount * $ratio); $baseShippingAmount = $this->priceCurrency->round($orderBaseShippingAmount * $ratio); } $shippingInclTax = $this->priceCurrency->round($orderShippingInclTax * $ratio); $baseShippingInclTax = $this->priceCurrency->round($orderBaseShippingInclTax * $ratio); } else { $maxAllowedAmount = $order->getBaseCurrency()->format($maxAllowedAmount, null, false); throw new \Magento\Framework\Exception\LocalizedException(__('Maximum shipping amount allowed to refund is: %1', $maxAllowedAmount)); } } else { $shippingAmount = $allowedAmount; $baseShippingAmount = $baseAllowedAmount; $shippingInclTax = $this->priceCurrency->round($allowedAmountInclTax); $baseShippingInclTax = $this->priceCurrency->round($baseAllowedAmountInclTax); } $creditmemo->setShippingAmount($shippingAmount); $creditmemo->setBaseShippingAmount($baseShippingAmount); $creditmemo->setShippingInclTax($shippingInclTax); $creditmemo->setBaseShippingInclTax($baseShippingInclTax); $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $shippingAmount); $creditmemo->setBaseGrandTotal($creditmemo->getBaseGrandTotal() + $baseShippingAmount); return $this; }