Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
TaxCalculation.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Tax\Model;
8 
13 use Magento\Tax\Api\Data\TaxDetailsInterfaceFactory;
14 use Magento\Tax\Api\Data\TaxDetailsItemInterfaceFactory;
22 
27 {
34 
40  protected $config;
41 
47  protected $calculationTool;
48 
55 
62 
66  protected $storeManager;
67 
73  private $keyedItems;
74 
80  private $parentToChildren;
81 
88 
94  protected $calculatorFactory;
95 
99  protected $dataObjectHelper;
100 
111  public function __construct(
112  Calculation $calculation,
114  Config $config,
115  TaxDetailsInterfaceFactory $taxDetailsDataObjectFactory,
116  TaxDetailsItemInterfaceFactory $taxDetailsItemDataObjectFactory,
119  \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
120  ) {
121  $this->calculationTool = $calculation;
122  $this->calculatorFactory = $calculatorFactory;
123  $this->config = $config;
124  $this->taxDetailsDataObjectFactory = $taxDetailsDataObjectFactory;
125  $this->taxDetailsItemDataObjectFactory = $taxDetailsItemDataObjectFactory;
126  $this->storeManager = $storeManager;
127  $this->taxClassManagement = $taxClassManagement;
128  $this->dataObjectHelper = $dataObjectHelper;
129  }
130 
134  public function calculateTax(
135  \Magento\Tax\Api\Data\QuoteDetailsInterface $quoteDetails,
136  $storeId = null,
137  $round = true
138  ) {
139  if ($storeId === null) {
140  $storeId = $this->storeManager->getStore()->getStoreId();
141  }
142 
143  // initial TaxDetails data
144  $taxDetailsData = [
149  TaxDetails::KEY_ITEMS => [],
150  ];
151  $items = $quoteDetails->getItems();
152  if (empty($items)) {
153  return $this->taxDetailsDataObjectFactory->create()
154  ->setSubtotal(0.0)
155  ->setTaxAmount(0.0)
156  ->setDiscountTaxCompensationAmount(0.0)
157  ->setAppliedTaxes([])
158  ->setItems([]);
159  }
160  $this->computeRelationships($items);
161 
162  $calculator = $this->calculatorFactory->create(
163  $this->config->getAlgorithm($storeId),
164  $storeId,
165  $quoteDetails->getBillingAddress(),
166  $quoteDetails->getShippingAddress(),
167  $this->taxClassManagement->getTaxClassId($quoteDetails->getCustomerTaxClassKey(), 'customer'),
168  $quoteDetails->getCustomerId()
169  );
170 
171  $processedItems = [];
173  foreach ($this->keyedItems as $item) {
174  if (isset($this->parentToChildren[$item->getCode()])) {
175  $processedChildren = [];
176  foreach ($this->parentToChildren[$item->getCode()] as $child) {
177  $processedItem = $this->processItem($child, $calculator, $round);
178  $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
179  $processedItems[$processedItem->getCode()] = $processedItem;
180  $processedChildren[] = $processedItem;
181  }
182  $processedItem = $this->calculateParent($processedChildren, $item->getQuantity());
183  $processedItem->setCode($item->getCode());
184  $processedItem->setType($item->getType());
185  } else {
186  $processedItem = $this->processItem($item, $calculator, $round);
187  $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
188  }
189  $processedItems[$processedItem->getCode()] = $processedItem;
190  }
191 
192  $taxDetailsDataObject = $this->taxDetailsDataObjectFactory->create();
193  $this->dataObjectHelper->populateWithArray(
194  $taxDetailsDataObject,
195  $taxDetailsData,
196  \Magento\Tax\Api\Data\TaxDetailsInterface::class
197  );
198  $taxDetailsDataObject->setItems($processedItems);
199  return $taxDetailsDataObject;
200  }
201 
205  public function getDefaultCalculatedRate(
206  $productTaxClassID,
207  $customerId = null,
208  $storeId = null
209  ) {
210  return $this->getRate($productTaxClassID, $customerId, $storeId, true);
211  }
212 
216  public function getCalculatedRate(
217  $productTaxClassID,
218  $customerId = null,
219  $storeId = null
220  ) {
221  return $this->getRate($productTaxClassID, $customerId, $storeId);
222  }
223 
233  protected function getRate(
234  $productTaxClassID,
235  $customerId = null,
236  $storeId = null,
237  $isDefault = false
238  ) {
239  if ($storeId === null) {
240  $storeId = $this->storeManager->getStore()->getStoreId();
241  }
242  if (!$isDefault) {
243  $addressRequestObject = $this->calculationTool->getRateRequest(null, null, null, $storeId, $customerId);
244  } else {
245  $addressRequestObject = $this->calculationTool->getDefaultRateRequest($storeId, $customerId);
246  }
247  $addressRequestObject->setProductClassId($productTaxClassID);
248  return $this->calculationTool->getRate($addressRequestObject);
249  }
250 
257  private function computeRelationships($items)
258  {
259  $this->keyedItems = [];
260  $this->parentToChildren = [];
261  foreach ($items as $item) {
262  if ($item->getParentCode() === null) {
263  $this->keyedItems[$item->getCode()] = $item;
264  } else {
265  $this->parentToChildren[$item->getParentCode()][] = $item;
266  }
267  }
268  }
269 
278  protected function processItem(
280  AbstractCalculator $calculator,
281  $round = true
282  ) {
283  $quantity = $this->getTotalQuantity($item);
284  return $calculator->calculate($item, $quantity, $round);
285  }
286 
294  protected function calculateParent($children, $quantity)
295  {
296  $rowTotal = 0.00;
297  $rowTotalInclTax = 0.00;
298  $rowTax = 0.00;
299  $taxableAmount = 0.00;
300 
301  foreach ($children as $child) {
302  $rowTotal += $child->getRowTotal();
303  $rowTotalInclTax += $child->getRowTotalInclTax();
304  $rowTax += $child->getRowTax();
305  $taxableAmount += $child->getTaxableAmount();
306  }
307 
308  $price = $this->calculationTool->round($rowTotal / $quantity);
309  $priceInclTax = $this->calculationTool->round($rowTotalInclTax / $quantity);
310 
311  $taxDetailsItemDataObject = $this->taxDetailsItemDataObjectFactory->create()
312  ->setPrice($price)
313  ->setPriceInclTax($priceInclTax)
314  ->setRowTotal($rowTotal)
315  ->setRowTotalInclTax($rowTotalInclTax)
316  ->setRowTax($rowTax);
317 
318  return $taxDetailsItemDataObject;
319  }
320 
328  protected function aggregateItemData($taxDetailsData, TaxDetailsItemInterface $item)
329  {
330  $taxDetailsData[TaxDetails::KEY_SUBTOTAL]
331  = $taxDetailsData[TaxDetails::KEY_SUBTOTAL] + $item->getRowTotal();
332 
333  $taxDetailsData[TaxDetails::KEY_TAX_AMOUNT]
334  = $taxDetailsData[TaxDetails::KEY_TAX_AMOUNT] + $item->getRowTax();
335 
338  + $item->getDiscountTaxCompensationAmount();
339 
340  $itemAppliedTaxes = $item->getAppliedTaxes();
341  if ($itemAppliedTaxes === null) {
342  return $taxDetailsData;
343  }
344  $appliedTaxes = $taxDetailsData[TaxDetails::KEY_APPLIED_TAXES];
345  foreach ($itemAppliedTaxes as $taxId => $itemAppliedTax) {
346  if (!isset($appliedTaxes[$taxId])) {
347  //convert rate data object to array
348  $rates = [];
349  $rateDataObjects = $itemAppliedTax->getRates();
350  foreach ($rateDataObjects as $rateDataObject) {
351  $rates[$rateDataObject->getCode()] = [
352  AppliedTaxRate::KEY_CODE => $rateDataObject->getCode(),
353  AppliedTaxRate::KEY_TITLE => $rateDataObject->getTitle(),
354  AppliedTaxRate::KEY_PERCENT => $rateDataObject->getPercent(),
355  ];
356  }
357  $appliedTaxes[$taxId] = [
358  AppliedTax::KEY_AMOUNT => $itemAppliedTax->getAmount(),
359  AppliedTax::KEY_PERCENT => $itemAppliedTax->getPercent(),
361  AppliedTax::KEY_TAX_RATE_KEY => $itemAppliedTax->getTaxRateKey(),
362  ];
363  } else {
364  $appliedTaxes[$taxId][AppliedTax::KEY_AMOUNT] += $itemAppliedTax->getAmount();
365  }
366  }
367 
368  $taxDetailsData[TaxDetails::KEY_APPLIED_TAXES] = $appliedTaxes;
369  return $taxDetailsData;
370  }
371 
382  {
383  if ($item->getParentCode()) {
384  $parentQuantity = $this->keyedItems[$item->getParentCode()]->getQuantity();
385  return $parentQuantity * $item->getQuantity();
386  }
387  return $item->getQuantity();
388  }
389 }
processItem(QuoteDetailsItemInterface $item, AbstractCalculator $calculator, $round=true)
aggregateItemData($taxDetailsData, TaxDetailsItemInterface $item)
getTotalQuantity(QuoteDetailsItemInterface $item)
$price
$rates
Definition: tax.phtml:35
calculate(QuoteDetailsItemInterface $item, $quantity, $round=true)
getRate( $productTaxClassID, $customerId=null, $storeId=null, $isDefault=false)
__construct(Calculation $calculation, CalculatorFactory $calculatorFactory, Config $config, TaxDetailsInterfaceFactory $taxDetailsDataObjectFactory, TaxDetailsItemInterfaceFactory $taxDetailsItemDataObjectFactory, StoreManagerInterface $storeManager, TaxClassManagementInterface $taxClassManagement, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper)
getCalculatedRate( $productTaxClassID, $customerId=null, $storeId=null)
getDefaultCalculatedRate( $productTaxClassID, $customerId=null, $storeId=null)
$children
Definition: actions.phtml:11
calculateTax(\Magento\Tax\Api\Data\QuoteDetailsInterface $quoteDetails, $storeId=null, $round=true)
calculateParent($children, $quantity)
$items