| Current Path : /home/rtorresani/www/vendor/magento/module-tax/Model/Calculation/ |
| Current File : //home/rtorresani/www/vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Tax\Model\Calculation;
use Magento\Tax\Api\Data\QuoteDetailsItemInterface;
/**
* Abstract aggregate calculator.
*/
abstract class AbstractAggregateCalculator extends AbstractCalculator
{
/**
* @inheritdoc
*/
protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
$taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
$this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
);
$rate = $this->calculationTool->getRate($taxRateRequest);
$storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
$discountTaxCompensationAmount = 0;
$applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
$discountAmount = $item->getDiscountAmount();
// Calculate $rowTotalInclTax
$priceInclTax = $this->calculationTool->round($item->getUnitPrice());
$rowTotalInclTax = $priceInclTax * $quantity;
if (!$this->isSameRateAsStore($rate, $storeRate)) {
$priceInclTax = $this->calculatePriceInclTax($priceInclTax, $storeRate, $rate, $round);
$rowTotalInclTax = $priceInclTax * $quantity;
}
$rowTaxExact = $this->calculationTool->calcTaxAmount($rowTotalInclTax, $rate, true, false);
$deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
if ($applyTaxAfterDiscount) {
$deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
}
$rowTax = $this->roundAmount($rowTaxExact, $rate, true, $deltaRoundingType, $round, $item);
$rowTotal = $rowTotalInclTax - $rowTax;
$price = $rowTotal / $quantity;
if ($round) {
$price = $this->calculationTool->round($price);
}
//Handle discount
if ($applyTaxAfterDiscount) {
//TODO: handle originalDiscountAmount
$taxableAmount = max($rowTotalInclTax - $discountAmount, 0);
$rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
$taxableAmount,
$rate,
true,
false
);
$rowTaxAfterDiscount = $this->roundAmount(
$rowTaxAfterDiscount,
$rate,
true,
self::KEY_REGULAR_DELTA_ROUNDING,
$round,
$item
);
// Set discount tax compensation
$discountTaxCompensationAmount = $rowTax - $rowTaxAfterDiscount;
$rowTax = $rowTaxAfterDiscount;
}
// Calculate applied taxes
/** @var \Magento\Tax\Api\Data\AppliedTaxInterface[] $appliedTaxes */
$appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
$appliedTaxes = $this->getAppliedTaxes($rowTax, $rate, $appliedRates);
return $this->taxDetailsItemDataObjectFactory->create()
->setCode($item->getCode())
->setType($item->getType())
->setRowTax($rowTax)
->setPrice($price)
->setPriceInclTax($priceInclTax)
->setRowTotal($rowTotal)
->setRowTotalInclTax($rowTotalInclTax)
->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
->setAssociatedItemCode($item->getAssociatedItemCode())
->setTaxPercent($rate)
->setAppliedTaxes($appliedTaxes);
}
/**
* @inheritdoc
*/
protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
$taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
$this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
);
$rate = $this->calculationTool->getRate($taxRateRequest);
$appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
$applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
$discountAmount = $item->getDiscountAmount();
$discountTaxCompensationAmount = 0;
// Calculate $rowTotal
$price = $this->calculationTool->round($item->getUnitPrice());
$rowTotal = $price * $quantity;
$rowTaxes = [];
$rowTaxesBeforeDiscount = [];
$appliedTaxes = [];
$rowTotalForTaxCalculation = $this->getPriceForTaxCalculation($item, $price) * $quantity;
//Apply each tax rate separately
foreach ($appliedRates as $appliedRate) {
$taxId = $appliedRate['id'];
$taxRate = $appliedRate['percent'];
$rowTaxPerRate = $this->calculationTool->calcTaxAmount($rowTotalForTaxCalculation, $taxRate, false, false);
$deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
if ($applyTaxAfterDiscount) {
$deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
}
$rowTaxPerRate = $this->roundAmount($rowTaxPerRate, $taxId, false, $deltaRoundingType, $round, $item);
$rowTaxAfterDiscount = $rowTaxPerRate;
//Handle discount
if ($applyTaxAfterDiscount) {
//TODO: handle originalDiscountAmount
$taxableAmount = max($rowTotalForTaxCalculation - $discountAmount, 0);
if ($taxableAmount && !$applyTaxAfterDiscount) {
$taxableAmount = $rowTotalForTaxCalculation;
}
$rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
$taxableAmount,
$taxRate,
false,
false
);
$rowTaxAfterDiscount = $this->roundAmount(
$rowTaxAfterDiscount,
$taxId,
false,
self::KEY_REGULAR_DELTA_ROUNDING,
$round,
$item
);
}
$appliedTaxes[$taxId] = $this->getAppliedTax(
$rowTaxAfterDiscount,
$appliedRate
);
$rowTaxes[] = $rowTaxAfterDiscount;
$rowTaxesBeforeDiscount[] = $rowTaxPerRate;
}
$rowTax = array_sum($rowTaxes);
$rowTaxBeforeDiscount = array_sum($rowTaxesBeforeDiscount);
$rowTotalInclTax = $rowTotal + $rowTaxBeforeDiscount;
$priceInclTax = $rowTotalInclTax / $quantity;
if ($round) {
$priceInclTax = $this->calculationTool->round($priceInclTax);
}
return $this->taxDetailsItemDataObjectFactory->create()
->setCode($item->getCode())
->setType($item->getType())
->setRowTax($rowTax)
->setPrice($price)
->setPriceInclTax($priceInclTax)
->setRowTotal($rowTotal)
->setRowTotalInclTax($rowTotalInclTax)
->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
->setAssociatedItemCode($item->getAssociatedItemCode())
->setTaxPercent($rate)
->setAppliedTaxes($appliedTaxes);
}
/**
* Get price for tax calculation.
*
* @param QuoteDetailsItemInterface $item
* @param float $price
* @return float
*/
private function getPriceForTaxCalculation(QuoteDetailsItemInterface $item, float $price)
{
if ($item->getExtensionAttributes() && $item->getExtensionAttributes()->getPriceForTaxCalculation()) {
$priceForTaxCalculation = $this->calculationTool->round(
$item->getExtensionAttributes()->getPriceForTaxCalculation()
);
} else {
$priceForTaxCalculation = $price;
}
return $priceForTaxCalculation;
}
/**
* Round amount
*
* @param float $amount
* @param null|float $rate
* @param null|bool $direction
* @param string $type
* @param bool $round
* @param QuoteDetailsItemInterface $item
* @return float
*/
abstract protected function roundAmount(
$amount,
$rate = null,
$direction = null,
$type = self::KEY_REGULAR_DELTA_ROUNDING,
$round = true,
$item = null
);
}