Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Calculation.php
Go to the documentation of this file.
1 <?php
6 namespace Magento\Tax\Model;
7 
8 use Magento\Customer\Api\AccountManagementInterface as CustomerAccountManagement;
10 use Magento\Customer\Api\Data\AddressInterface as CustomerAddress;
11 use Magento\Customer\Api\Data\CustomerInterface as CustomerDataObject;
13 use Magento\Customer\Api\GroupManagementInterface as CustomerGroupManagement;
14 use Magento\Customer\Api\GroupRepositoryInterface as CustomerGroupRepository;
21 
28 {
33 
38 
43 
48 
52  const CALC_UNIT_BASE = 'UNIT_BASE_CALCULATION';
53 
57  const CALC_ROW_BASE = 'ROW_BASE_CALCULATION';
58 
62  const CALC_TOTAL_BASE = 'TOTAL_BASE_CALCULATION';
63 
69  protected $_rates = [];
70 
76  protected $_ctc = [];
77 
83  protected $_ptc = [];
84 
90  protected $_rateCache = [];
91 
97  protected $_rateCalculationProcess = [];
98 
104  protected $_customer;
105 
110 
116  protected $_scopeConfig;
117 
121  protected $_storeManager;
122 
126  protected $_customerSession;
127 
131  protected $_customerFactory;
132 
136  protected $_classesFactory;
137 
143  protected $_config;
144 
149 
154 
159 
164 
168  protected $priceCurrency;
169 
175  protected $filterBuilder;
176 
183 
190 
213  public function __construct(
214  \Magento\Framework\Model\Context $context,
215  \Magento\Framework\Registry $registry,
216  \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
217  Config $taxConfig,
219  \Magento\Customer\Model\Session $customerSession,
220  \Magento\Customer\Model\CustomerFactory $customerFactory,
221  \Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory $classesFactory,
223  CustomerAccountManagement $customerAccountManagement,
224  CustomerGroupManagement $customerGroupManagement,
225  CustomerGroupRepository $customerGroupRepository,
226  CustomerRepository $customerRepository,
231  \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
232  array $data = []
233  ) {
234  $this->_scopeConfig = $scopeConfig;
235  $this->_config = $taxConfig;
236  $this->_storeManager = $storeManager;
237  $this->_customerSession = $customerSession;
238  $this->_customerFactory = $customerFactory;
239  $this->_classesFactory = $classesFactory;
240  $this->customerAccountManagement = $customerAccountManagement;
241  $this->customerGroupManagement = $customerGroupManagement;
242  $this->customerGroupRepository = $customerGroupRepository;
243  $this->customerRepository = $customerRepository;
244  $this->priceCurrency = $priceCurrency;
245  $this->searchCriteriaBuilder = $searchCriteriaBuilder;
246  $this->filterBuilder = $filterBuilder;
247  $this->taxClassRepository = $taxClassRepository;
248  parent::__construct($context, $registry, $resource, $resourceCollection, $data);
249  }
250 
254  protected function _construct()
255  {
256  $this->_init(\Magento\Tax\Model\ResourceModel\Calculation::class);
257  }
258 
265  public function getDefaultCustomerTaxClass($store = null)
266  {
267  if ($this->_defaultCustomerTaxClass === null) {
268  //Not catching the exception here since default group is expected
269  $defaultCustomerGroup = $this->customerGroupManagement->getDefaultGroup($store);
270  $this->_defaultCustomerTaxClass = $defaultCustomerGroup->getTaxClassId();
271  }
273  }
274 
281  public function deleteByRuleId($ruleId)
282  {
283  $this->_getResource()->deleteByRuleId($ruleId);
284  return $this;
285  }
286 
293  public function getRates($ruleId)
294  {
295  if (!isset($this->_rates[$ruleId])) {
296  $this->_rates[$ruleId] = $this->_getResource()->getCalculationsById('tax_calculation_rate_id', $ruleId);
297  }
298  return $this->_rates[$ruleId];
299  }
300 
308  {
309  if (!isset($this->_ctc[$ruleId])) {
310  $this->_ctc[$ruleId] = $this->_getResource()->getCalculationsById('customer_tax_class_id', $ruleId);
311  }
312  return $this->_ctc[$ruleId];
313  }
314 
321  public function getProductTaxClasses($ruleId)
322  {
323  if (!isset($this->_ptc[$ruleId])) {
324  $this->_ptc[$ruleId] = $this->getResource()->getCalculationsById('product_tax_class_id', $ruleId);
325  }
326  return $this->_ptc[$ruleId];
327  }
328 
334  protected function _formCalculationProcess()
335  {
336  $title = $this->getRateTitle();
337  $value = $this->getRateValue();
338  $id = $this->getRateId();
339 
340  $rate = ['code' => $title, 'title' => $title, 'percent' => $value, 'position' => 1, 'priority' => 1];
341 
342  $process = [];
343  $process['percent'] = $value;
344  $process['id'] = "{$id}-{$value}";
345  $process['rates'][] = $rate;
346 
347  return [$process];
348  }
349 
356  public function getRate($request)
357  {
358  if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
359  return 0;
360  }
361 
362  $cacheKey = $this->_getRequestCacheKey($request);
363  if (!isset($this->_rateCache[$cacheKey])) {
364  $this->unsRateValue();
365  $this->unsCalculationProcess();
366  $this->unsEventModuleId();
367  $this->_eventManager->dispatch('tax_rate_data_fetch', ['request' => $request, 'sender' => $this]);
368  if (!$this->hasRateValue()) {
369  $rateInfo = $this->_getResource()->getRateInfo($request);
370  $this->setCalculationProcess($rateInfo['process']);
371  $this->setRateValue($rateInfo['value']);
372  } else {
373  $this->setCalculationProcess($this->_formCalculationProcess());
374  }
375  $this->_rateCache[$cacheKey] = $this->getRateValue();
376  $this->_rateCalculationProcess[$cacheKey] = $this->getCalculationProcess();
377  }
378  return $this->_rateCache[$cacheKey];
379  }
380 
387  protected function _getRequestCacheKey($request)
388  {
389  $store = $request->getStore();
390  $key = '';
391  if ($store instanceof \Magento\Store\Model\Store) {
392  $key = $store->getId() . '|';
393  } elseif (is_numeric($store)) {
394  $key = $store . '|';
395  }
396  $key .= $request->getProductClassId() . '|'
397  . $request->getCustomerClassId() . '|'
398  . $request->getCountryId() . '|'
399  . $request->getRegionId() . '|'
400  . $request->getPostcode();
401  return $key;
402  }
403 
413  public function getStoreRate($request, $store = null)
414  {
415  $storeRequest = $this->getRateOriginRequest($store)->setProductClassId($request->getProductClassId());
416  return $this->getRate($storeRequest);
417  }
418 
425  protected function getRateOriginRequest($store = null)
426  {
427  $request = new \Magento\Framework\DataObject();
428  $request->setCountryId(
429  $this->_scopeConfig->getValue(
430  \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_COUNTRY_ID,
432  $store
433  )
434  )->setRegionId(
435  $this->_scopeConfig->getValue(
436  \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_REGION_ID,
438  $store
439  )
440  )->setPostcode(
441  $this->_scopeConfig->getValue(
442  \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_POSTCODE,
444  $store
445  )
446  )->setCustomerClassId(
448  )->setStore(
449  $store
450  );
451  return $request;
452  }
453 
461  public function getDefaultRateRequest($store = null, $customerId = null)
462  {
463  if ($this->_isCrossBorderTradeEnabled($store)) {
464  //If cross border trade is enabled, we will use customer tax rate as store tax rate
465  return $this->getRateRequest(null, null, null, $store, $customerId);
466  } else {
467  return $this->getRateOriginRequest($store);
468  }
469  }
470 
477  protected function _isCrossBorderTradeEnabled($store = null)
478  {
479  return (bool)$this->_config->crossBorderTradeEnabled($store);
480  }
481 
502  public function getRateRequest(
503  $shippingAddress = null,
504  $billingAddress = null,
505  $customerTaxClass = null,
506  $store = null,
507  $customerId = null
508  ) {
509  if ($shippingAddress === false && $billingAddress === false && $customerTaxClass === false) {
510  return $this->getRateOriginRequest($store);
511  }
512  $address = new \Magento\Framework\DataObject();
513  $basedOn = $this->_scopeConfig->getValue(
516  $store
517  );
518 
519  if ($shippingAddress === false && $basedOn == 'shipping' || $billingAddress === false && $basedOn == 'billing'
520  ) {
521  $basedOn = 'default';
522  } else {
523  if (($billingAddress === null || !$billingAddress->getCountryId())
524  && $basedOn == 'billing'
525  || ($shippingAddress === null || !$shippingAddress->getCountryId())
526  && $basedOn == 'shipping'
527  ) {
528  if ($customerId) {
529  //fallback to default address for registered customer
530  try {
531  $defaultBilling = $this->customerAccountManagement->getDefaultBillingAddress($customerId);
532  } catch (NoSuchEntityException $e) {
533  }
534 
535  try {
536  $defaultShipping = $this->customerAccountManagement->getDefaultShippingAddress($customerId);
537  } catch (NoSuchEntityException $e) {
538  }
539 
540  if ($basedOn == 'billing' && isset($defaultBilling) && $defaultBilling->getCountryId()) {
541  $billingAddress = $defaultBilling;
542  } elseif ($basedOn == 'shipping' && isset($defaultShipping) && $defaultShipping->getCountryId()) {
543  $shippingAddress = $defaultShipping;
544  } else {
545  $basedOn = 'default';
546  }
547  } else {
548  //fallback for guest
549  if ($basedOn == 'billing' && is_object($shippingAddress) && $shippingAddress->getCountryId()) {
551  } elseif ($basedOn == 'shipping' && is_object($billingAddress) && $billingAddress->getCountryId()) {
553  } else {
554  $basedOn = 'default';
555  }
556  }
557  }
558  }
559 
560  switch ($basedOn) {
561  case 'billing':
563  break;
564  case 'shipping':
566  break;
567  case 'origin':
569  break;
570  case 'default':
571  $address->setCountryId(
572  $this->_scopeConfig->getValue(
575  $store
576  )
577  )->setRegionId(
578  $this->_scopeConfig->getValue(
581  $store
582  )
583  )->setPostcode(
584  $this->_scopeConfig->getValue(
587  $store
588  )
589  );
590  break;
591  default:
592  break;
593  }
594 
595  if ($customerTaxClass === null || $customerTaxClass === false) {
596  if ($customerId) {
597  $customerData = $this->customerRepository->getById($customerId);
598  $customerTaxClass = $this->customerGroupRepository
599  ->getById($customerData->getGroupId())
600  ->getTaxClassId();
601  } else {
602  $customerTaxClass = $this->customerGroupManagement->getNotLoggedInGroup()->getTaxClassId();
603  }
604  }
605 
606  $request = new \Magento\Framework\DataObject();
607  //TODO: Address is not completely refactored to use Data objects
608  if ($address->getRegion() instanceof AddressRegion) {
609  $regionId = $address->getRegion()->getRegionId();
610  } else {
611  $regionId = $address->getRegionId();
612  }
613  $request->setCountryId($address->getCountryId())
614  ->setRegionId($regionId)
615  ->setPostcode($address->getPostcode())
616  ->setStore($store)
617  ->setCustomerClassId($customerTaxClass);
618  return $request;
619  }
620 
627  public function getAppliedRates($request)
628  {
629  if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
630  return [];
631  }
632 
633  $cacheKey = $this->_getRequestCacheKey($request);
634  if (!isset($this->_rateCalculationProcess[$cacheKey])) {
635  $this->_rateCalculationProcess[$cacheKey] = $this->_getResource()->getCalculationProcess($request);
636  }
637  return $this->_rateCalculationProcess[$cacheKey];
638  }
639 
646  public function reproduceProcess($rates)
647  {
648  return $this->getResource()->getCalculationProcess(null, $rates);
649  }
650 
661  public function calcTaxAmount($price, $taxRate, $priceIncludeTax = false, $round = true)
662  {
663  $taxRate = $taxRate / 100;
664 
665  if ($priceIncludeTax) {
666  $amount = $price * (1 - 1 / (1 + $taxRate));
667  } else {
668  $amount = $price * $taxRate;
669  }
670 
671  if ($round) {
672  return $this->round($amount);
673  }
674 
675  return $amount;
676  }
677 
684  public function round($price)
685  {
686  return $this->priceCurrency->round($price);
687  }
688 
695  public function getTaxRates($billingAddress, $shippingAddress, $customerTaxClassId)
696  {
697  $billingAddressObj = null;
698  $shippingAddressObj = null;
699  if (!empty($billingAddress)) {
700  $billingAddressObj = new \Magento\Framework\DataObject($billingAddress);
701  }
702  if (!empty($shippingAddress)) {
703  $shippingAddressObj = new \Magento\Framework\DataObject($shippingAddress);
704  }
705  $rateRequest = $this->getRateRequest($shippingAddressObj, $billingAddressObj, $customerTaxClassId);
706 
707  $searchCriteria = $this->searchCriteriaBuilder->addFilters(
708  [$this->filterBuilder->setField(ClassModel::KEY_TYPE)
710  ->create()]
711  )->create();
712  $ids = $this->taxClassRepository->getList($searchCriteria)->getItems();
713 
714  $productRates = [];
715  $idKeys = array_keys($ids);
716  foreach ($idKeys as $idKey) {
717  $rateRequest->setProductClassId($idKey);
718  $rate = $this->getRate($rateRequest);
719  $productRates[$idKey] = $rate;
720  }
721  return $productRates;
722  }
723 }
$title
Definition: default.phtml:14
$customerData
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$billingAddress
Definition: order.php:25
const CONFIG_XML_PATH_DEFAULT_POSTCODE
Definition: Config.php:55
$id
Definition: fieldset.phtml:14
const CONFIG_XML_PATH_DEFAULT_REGION
Definition: Config.php:53
$shippingAddress
Definition: order.php:40
$storeManager
$resource
Definition: bulk.php:12
$price
$rates
Definition: tax.phtml:35
$searchCriteria
$address
Definition: customer.php:38
$customerTaxClass
Definition: tax_rule.php:9
const CONFIG_XML_PATH_DEFAULT_COUNTRY
Definition: Config.php:51
$amount
Definition: order.php:14
getDefaultCustomerTaxClass($store=null)
$value
Definition: gender.phtml:16
getDefaultRateRequest($store=null, $customerId=null)
calcTaxAmount($price, $taxRate, $priceIncludeTax=false, $round=true)
getRateRequest( $shippingAddress=null, $billingAddress=null, $customerTaxClass=null, $store=null, $customerId=null)
const CONFIG_XML_PATH_BASED_ON
Definition: Config.php:38
getTaxRates($billingAddress, $shippingAddress, $customerTaxClassId)
__construct(\Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, Config $taxConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Customer\Model\Session $customerSession, \Magento\Customer\Model\CustomerFactory $customerFactory, \Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory $classesFactory, \Magento\Tax\Model\ResourceModel\Calculation $resource, CustomerAccountManagement $customerAccountManagement, CustomerGroupManagement $customerGroupManagement, CustomerGroupRepository $customerGroupRepository, CustomerRepository $customerRepository, PriceCurrencyInterface $priceCurrency, SearchCriteriaBuilder $searchCriteriaBuilder, FilterBuilder $filterBuilder, TaxClassRepositoryInterface $taxClassRepository, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection=null, array $data=[])
getStoreRate($request, $store=null)
$taxRate
Definition: tax_rule.php:12
_isCrossBorderTradeEnabled($store=null)