Calculation.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Tax\Model;
  7. use Magento\Customer\Api\AccountManagementInterface as CustomerAccountManagement;
  8. use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository;
  9. use Magento\Customer\Api\Data\AddressInterface as CustomerAddress;
  10. use Magento\Customer\Api\Data\CustomerInterface as CustomerDataObject;
  11. use Magento\Customer\Api\Data\RegionInterface as AddressRegion;
  12. use Magento\Customer\Api\GroupManagementInterface as CustomerGroupManagement;
  13. use Magento\Customer\Api\GroupRepositoryInterface as CustomerGroupRepository;
  14. use Magento\Framework\Api\FilterBuilder;
  15. use Magento\Framework\Api\SearchCriteriaBuilder;
  16. use Magento\Framework\Exception\NoSuchEntityException;
  17. use Magento\Framework\Pricing\PriceCurrencyInterface;
  18. use Magento\Store\Model\Store;
  19. use Magento\Tax\Api\TaxClassRepositoryInterface;
  20. /**
  21. * Tax Calculation Model
  22. * @SuppressWarnings(PHPMD.TooManyFields)
  23. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  24. */
  25. class Calculation extends \Magento\Framework\Model\AbstractModel
  26. {
  27. /**
  28. * Identifier constant for Tax calculation before discount excluding TAX
  29. */
  30. const CALC_TAX_BEFORE_DISCOUNT_ON_EXCL = '0_0';
  31. /**
  32. * Identifier constant for Tax calculation before discount including TAX
  33. */
  34. const CALC_TAX_BEFORE_DISCOUNT_ON_INCL = '0_1';
  35. /**
  36. * Identifier constant for Tax calculation after discount excluding TAX
  37. */
  38. const CALC_TAX_AFTER_DISCOUNT_ON_EXCL = '1_0';
  39. /**
  40. * Identifier constant for Tax calculation after discount including TAX
  41. */
  42. const CALC_TAX_AFTER_DISCOUNT_ON_INCL = '1_1';
  43. /**
  44. * Identifier constant for unit based calculation
  45. */
  46. const CALC_UNIT_BASE = 'UNIT_BASE_CALCULATION';
  47. /**
  48. * Identifier constant for row based calculation
  49. */
  50. const CALC_ROW_BASE = 'ROW_BASE_CALCULATION';
  51. /**
  52. * Identifier constant for total based calculation
  53. */
  54. const CALC_TOTAL_BASE = 'TOTAL_BASE_CALCULATION';
  55. /**
  56. * Identifier constant for unit based calculation
  57. *
  58. * @var array
  59. */
  60. protected $_rates = [];
  61. /**
  62. * Identifier constant for row based calculation
  63. *
  64. * @var array
  65. */
  66. protected $_ctc = [];
  67. /**
  68. * Identifier constant for total based calculation
  69. *
  70. * @var array
  71. */
  72. protected $_ptc = [];
  73. /**
  74. * Cache to hold the rates
  75. *
  76. * @var array
  77. */
  78. protected $_rateCache = [];
  79. /**
  80. * Store the rate calculation process
  81. *
  82. * @var array
  83. */
  84. protected $_rateCalculationProcess = [];
  85. /**
  86. * Hold the customer
  87. *
  88. * @var CustomerDataObject|bool
  89. */
  90. protected $_customer;
  91. /**
  92. * @var int
  93. */
  94. protected $_defaultCustomerTaxClass;
  95. /**
  96. * Core store config
  97. *
  98. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  99. */
  100. protected $_scopeConfig;
  101. /**
  102. * @var \Magento\Store\Model\StoreManagerInterface
  103. */
  104. protected $_storeManager;
  105. /**
  106. * @var \Magento\Customer\Model\Session
  107. */
  108. protected $_customerSession;
  109. /**
  110. * @var \Magento\Customer\Model\CustomerFactory
  111. */
  112. protected $_customerFactory;
  113. /**
  114. * @var \Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory
  115. */
  116. protected $_classesFactory;
  117. /**
  118. * Tax configuration object
  119. *
  120. * @var Config
  121. */
  122. protected $_config;
  123. /**
  124. * @var CustomerAccountManagement
  125. */
  126. protected $customerAccountManagement;
  127. /**
  128. * @var CustomerGroupManagement
  129. */
  130. protected $customerGroupManagement;
  131. /**
  132. * @var CustomerGroupRepository
  133. */
  134. protected $customerGroupRepository;
  135. /**
  136. * @var CustomerRepository
  137. */
  138. protected $customerRepository;
  139. /**
  140. * @var PriceCurrencyInterface
  141. */
  142. protected $priceCurrency;
  143. /**
  144. * Filter Builder
  145. *
  146. * @var FilterBuilder
  147. */
  148. protected $filterBuilder;
  149. /**
  150. * Search Criteria Builder
  151. *
  152. * @var SearchCriteriaBuilder
  153. */
  154. protected $searchCriteriaBuilder;
  155. /**
  156. * Tax Class Repository
  157. *
  158. * @var TaxClassRepositoryInterface
  159. */
  160. protected $taxClassRepository;
  161. /**
  162. * @param \Magento\Framework\Model\Context $context
  163. * @param \Magento\Framework\Registry $registry
  164. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  165. * @param Config $taxConfig
  166. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  167. * @param \Magento\Customer\Model\Session $customerSession
  168. * @param \Magento\Customer\Model\CustomerFactory $customerFactory
  169. * @param \Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory $classesFactory
  170. * @param \Magento\Tax\Model\ResourceModel\Calculation $resource
  171. * @param CustomerAccountManagement $customerAccountManagement
  172. * @param CustomerGroupManagement $customerGroupManagement
  173. * @param CustomerGroupRepository $customerGroupRepository
  174. * @param CustomerRepository $customerRepository
  175. * @param PriceCurrencyInterface $priceCurrency
  176. * @param SearchCriteriaBuilder $searchCriteriaBuilder
  177. * @param FilterBuilder $filterBuilder
  178. * @param TaxClassRepositoryInterface $taxClassRepository
  179. * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
  180. * @param array $data
  181. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  182. */
  183. public function __construct(
  184. \Magento\Framework\Model\Context $context,
  185. \Magento\Framework\Registry $registry,
  186. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  187. Config $taxConfig,
  188. \Magento\Store\Model\StoreManagerInterface $storeManager,
  189. \Magento\Customer\Model\Session $customerSession,
  190. \Magento\Customer\Model\CustomerFactory $customerFactory,
  191. \Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory $classesFactory,
  192. \Magento\Tax\Model\ResourceModel\Calculation $resource,
  193. CustomerAccountManagement $customerAccountManagement,
  194. CustomerGroupManagement $customerGroupManagement,
  195. CustomerGroupRepository $customerGroupRepository,
  196. CustomerRepository $customerRepository,
  197. PriceCurrencyInterface $priceCurrency,
  198. SearchCriteriaBuilder $searchCriteriaBuilder,
  199. FilterBuilder $filterBuilder,
  200. TaxClassRepositoryInterface $taxClassRepository,
  201. \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
  202. array $data = []
  203. ) {
  204. $this->_scopeConfig = $scopeConfig;
  205. $this->_config = $taxConfig;
  206. $this->_storeManager = $storeManager;
  207. $this->_customerSession = $customerSession;
  208. $this->_customerFactory = $customerFactory;
  209. $this->_classesFactory = $classesFactory;
  210. $this->customerAccountManagement = $customerAccountManagement;
  211. $this->customerGroupManagement = $customerGroupManagement;
  212. $this->customerGroupRepository = $customerGroupRepository;
  213. $this->customerRepository = $customerRepository;
  214. $this->priceCurrency = $priceCurrency;
  215. $this->searchCriteriaBuilder = $searchCriteriaBuilder;
  216. $this->filterBuilder = $filterBuilder;
  217. $this->taxClassRepository = $taxClassRepository;
  218. parent::__construct($context, $registry, $resource, $resourceCollection, $data);
  219. }
  220. /**
  221. * @return void
  222. */
  223. protected function _construct()
  224. {
  225. $this->_init(\Magento\Tax\Model\ResourceModel\Calculation::class);
  226. }
  227. /**
  228. * Fetch default customer tax class
  229. *
  230. * @param null|Store|string|int $store
  231. * @return int
  232. */
  233. public function getDefaultCustomerTaxClass($store = null)
  234. {
  235. if ($this->_defaultCustomerTaxClass === null) {
  236. //Not catching the exception here since default group is expected
  237. $defaultCustomerGroup = $this->customerGroupManagement->getDefaultGroup($store);
  238. $this->_defaultCustomerTaxClass = $defaultCustomerGroup->getTaxClassId();
  239. }
  240. return $this->_defaultCustomerTaxClass;
  241. }
  242. /**
  243. * Delete calculation settings by rule id
  244. *
  245. * @param int $ruleId
  246. * @return $this
  247. */
  248. public function deleteByRuleId($ruleId)
  249. {
  250. $this->_getResource()->deleteByRuleId($ruleId);
  251. return $this;
  252. }
  253. /**
  254. * Get calculation rates by rule id
  255. *
  256. * @param int $ruleId
  257. * @return array
  258. */
  259. public function getRates($ruleId)
  260. {
  261. if (!isset($this->_rates[$ruleId])) {
  262. $this->_rates[$ruleId] = $this->_getResource()->getCalculationsById('tax_calculation_rate_id', $ruleId);
  263. }
  264. return $this->_rates[$ruleId];
  265. }
  266. /**
  267. * Get allowed customer tax classes by rule id
  268. *
  269. * @param int $ruleId
  270. * @return array
  271. */
  272. public function getCustomerTaxClasses($ruleId)
  273. {
  274. if (!isset($this->_ctc[$ruleId])) {
  275. $this->_ctc[$ruleId] = $this->_getResource()->getCalculationsById('customer_tax_class_id', $ruleId);
  276. }
  277. return $this->_ctc[$ruleId];
  278. }
  279. /**
  280. * Get allowed product tax classes by rule id
  281. *
  282. * @param int $ruleId
  283. * @return array
  284. */
  285. public function getProductTaxClasses($ruleId)
  286. {
  287. if (!isset($this->_ptc[$ruleId])) {
  288. $this->_ptc[$ruleId] = $this->getResource()->getCalculationsById('product_tax_class_id', $ruleId);
  289. }
  290. return $this->_ptc[$ruleId];
  291. }
  292. /**
  293. * Aggregate tax calculation data to array
  294. *
  295. * @return array
  296. */
  297. protected function _formCalculationProcess()
  298. {
  299. $title = $this->getRateTitle();
  300. $value = $this->getRateValue();
  301. $id = $this->getRateId();
  302. $rate = ['code' => $title, 'title' => $title, 'percent' => $value, 'position' => 1, 'priority' => 1];
  303. $process = [];
  304. $process['percent'] = $value;
  305. $process['id'] = "{$id}-{$value}";
  306. $process['rates'][] = $rate;
  307. return [$process];
  308. }
  309. /**
  310. * Get calculation tax rate by specific request
  311. *
  312. * @param \Magento\Framework\DataObject $request
  313. * @return float
  314. */
  315. public function getRate($request)
  316. {
  317. if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
  318. return 0;
  319. }
  320. $cacheKey = $this->_getRequestCacheKey($request);
  321. if (!isset($this->_rateCache[$cacheKey])) {
  322. $this->unsRateValue();
  323. $this->unsCalculationProcess();
  324. $this->unsEventModuleId();
  325. $this->_eventManager->dispatch('tax_rate_data_fetch', ['request' => $request, 'sender' => $this]);
  326. if (!$this->hasRateValue()) {
  327. $rateInfo = $this->_getResource()->getRateInfo($request);
  328. $this->setCalculationProcess($rateInfo['process']);
  329. $this->setRateValue($rateInfo['value']);
  330. } else {
  331. $this->setCalculationProcess($this->_formCalculationProcess());
  332. }
  333. $this->_rateCache[$cacheKey] = $this->getRateValue();
  334. $this->_rateCalculationProcess[$cacheKey] = $this->getCalculationProcess();
  335. }
  336. return $this->_rateCache[$cacheKey];
  337. }
  338. /**
  339. * Get cache key value for specific tax rate request
  340. *
  341. * @param \Magento\Framework\DataObject $request
  342. * @return string
  343. */
  344. protected function _getRequestCacheKey($request)
  345. {
  346. $store = $request->getStore();
  347. $key = '';
  348. if ($store instanceof \Magento\Store\Model\Store) {
  349. $key = $store->getId() . '|';
  350. } elseif (is_numeric($store)) {
  351. $key = $store . '|';
  352. }
  353. $key .= $request->getProductClassId() . '|'
  354. . $request->getCustomerClassId() . '|'
  355. . $request->getCountryId() . '|'
  356. . $request->getRegionId() . '|'
  357. . $request->getPostcode();
  358. return $key;
  359. }
  360. /**
  361. * Get tax rate based on store shipping origin address settings
  362. * This rate can be used for conversion store price including tax to
  363. * store price excluding tax
  364. *
  365. * @param \Magento\Framework\DataObject $request
  366. * @param null|string|bool|int|Store $store
  367. * @return float
  368. */
  369. public function getStoreRate($request, $store = null)
  370. {
  371. $storeRequest = $this->getRateOriginRequest($store)->setProductClassId($request->getProductClassId());
  372. return $this->getRate($storeRequest);
  373. }
  374. /**
  375. * Get request object for getting tax rate based on store shipping original address
  376. *
  377. * @param null|string|bool|int|Store $store
  378. * @return \Magento\Framework\DataObject
  379. */
  380. protected function getRateOriginRequest($store = null)
  381. {
  382. $request = new \Magento\Framework\DataObject();
  383. $request->setCountryId(
  384. $this->_scopeConfig->getValue(
  385. \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_COUNTRY_ID,
  386. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  387. $store
  388. )
  389. )->setRegionId(
  390. $this->_scopeConfig->getValue(
  391. \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_REGION_ID,
  392. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  393. $store
  394. )
  395. )->setPostcode(
  396. $this->_scopeConfig->getValue(
  397. \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_POSTCODE,
  398. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  399. $store
  400. )
  401. )->setCustomerClassId(
  402. $this->getDefaultCustomerTaxClass($store)
  403. )->setStore(
  404. $store
  405. );
  406. return $request;
  407. }
  408. /**
  409. * Return the default rate request. It can be either based on store address or customer address
  410. *
  411. * @param null|int|string|Store $store
  412. * @param int $customerId
  413. * @return \Magento\Framework\DataObject
  414. */
  415. public function getDefaultRateRequest($store = null, $customerId = null)
  416. {
  417. if ($this->_isCrossBorderTradeEnabled($store)) {
  418. //If cross border trade is enabled, we will use customer tax rate as store tax rate
  419. return $this->getRateRequest(null, null, null, $store, $customerId);
  420. } else {
  421. return $this->getRateOriginRequest($store);
  422. }
  423. }
  424. /**
  425. * Return whether cross border trade is enabled or not
  426. *
  427. * @param null|int|string|Store $store
  428. * @return bool
  429. */
  430. protected function _isCrossBorderTradeEnabled($store = null)
  431. {
  432. return (bool)$this->_config->crossBorderTradeEnabled($store);
  433. }
  434. /**
  435. * Get request object with information necessary for getting tax rate
  436. *
  437. * Request object contain:
  438. * country_id (->getCountryId())
  439. * region_id (->getRegionId())
  440. * postcode (->getPostcode())
  441. * customer_class_id (->getCustomerClassId())
  442. * store (->getStore())
  443. *
  444. * @param null|bool|\Magento\Framework\DataObject|CustomerAddress $shippingAddress
  445. * @param null|bool|\Magento\Framework\DataObject|CustomerAddress $billingAddress
  446. * @param null|int $customerTaxClass
  447. * @param null|int|\Magento\Store\Model\Store $store
  448. * @param int $customerId
  449. * @return \Magento\Framework\DataObject
  450. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  451. * @SuppressWarnings(PHPMD.NPathComplexity)
  452. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  453. */
  454. public function getRateRequest(
  455. $shippingAddress = null,
  456. $billingAddress = null,
  457. $customerTaxClass = null,
  458. $store = null,
  459. $customerId = null
  460. ) {
  461. if ($shippingAddress === false && $billingAddress === false && $customerTaxClass === false) {
  462. return $this->getRateOriginRequest($store);
  463. }
  464. $address = new \Magento\Framework\DataObject();
  465. $basedOn = $this->_scopeConfig->getValue(
  466. \Magento\Tax\Model\Config::CONFIG_XML_PATH_BASED_ON,
  467. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  468. $store
  469. );
  470. if ($shippingAddress === false && $basedOn == 'shipping' || $billingAddress === false && $basedOn == 'billing'
  471. ) {
  472. $basedOn = 'default';
  473. } else {
  474. if (($billingAddress === null || !$billingAddress->getCountryId())
  475. && $basedOn == 'billing'
  476. || ($shippingAddress === null || !$shippingAddress->getCountryId())
  477. && $basedOn == 'shipping'
  478. ) {
  479. if ($customerId) {
  480. //fallback to default address for registered customer
  481. try {
  482. $defaultBilling = $this->customerAccountManagement->getDefaultBillingAddress($customerId);
  483. } catch (NoSuchEntityException $e) {
  484. }
  485. try {
  486. $defaultShipping = $this->customerAccountManagement->getDefaultShippingAddress($customerId);
  487. } catch (NoSuchEntityException $e) {
  488. }
  489. if ($basedOn == 'billing' && isset($defaultBilling) && $defaultBilling->getCountryId()) {
  490. $billingAddress = $defaultBilling;
  491. } elseif ($basedOn == 'shipping' && isset($defaultShipping) && $defaultShipping->getCountryId()) {
  492. $shippingAddress = $defaultShipping;
  493. } else {
  494. $basedOn = 'default';
  495. }
  496. } else {
  497. //fallback for guest
  498. if ($basedOn == 'billing' && is_object($shippingAddress) && $shippingAddress->getCountryId()) {
  499. $billingAddress = $shippingAddress;
  500. } elseif ($basedOn == 'shipping' && is_object($billingAddress) && $billingAddress->getCountryId()) {
  501. $shippingAddress = $billingAddress;
  502. } else {
  503. $basedOn = 'default';
  504. }
  505. }
  506. }
  507. }
  508. switch ($basedOn) {
  509. case 'billing':
  510. $address = $billingAddress;
  511. break;
  512. case 'shipping':
  513. $address = $shippingAddress;
  514. break;
  515. case 'origin':
  516. $address = $this->getRateOriginRequest($store);
  517. break;
  518. case 'default':
  519. $address->setCountryId(
  520. $this->_scopeConfig->getValue(
  521. \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_COUNTRY,
  522. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  523. $store
  524. )
  525. )->setRegionId(
  526. $this->_scopeConfig->getValue(
  527. \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_REGION,
  528. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  529. $store
  530. )
  531. )->setPostcode(
  532. $this->_scopeConfig->getValue(
  533. \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_POSTCODE,
  534. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  535. $store
  536. )
  537. );
  538. break;
  539. default:
  540. break;
  541. }
  542. if ($customerTaxClass === null || $customerTaxClass === false) {
  543. if ($customerId) {
  544. $customerData = $this->customerRepository->getById($customerId);
  545. $customerTaxClass = $this->customerGroupRepository
  546. ->getById($customerData->getGroupId())
  547. ->getTaxClassId();
  548. } else {
  549. $customerTaxClass = $this->customerGroupManagement->getNotLoggedInGroup()->getTaxClassId();
  550. }
  551. }
  552. $request = new \Magento\Framework\DataObject();
  553. //TODO: Address is not completely refactored to use Data objects
  554. if ($address->getRegion() instanceof AddressRegion) {
  555. $regionId = $address->getRegion()->getRegionId();
  556. } else {
  557. $regionId = $address->getRegionId();
  558. }
  559. $request->setCountryId($address->getCountryId())
  560. ->setRegionId($regionId)
  561. ->setPostcode($address->getPostcode())
  562. ->setStore($store)
  563. ->setCustomerClassId($customerTaxClass);
  564. return $request;
  565. }
  566. /**
  567. * Get information about tax rates applied to request
  568. *
  569. * @param \Magento\Framework\DataObject $request
  570. * @return array
  571. */
  572. public function getAppliedRates($request)
  573. {
  574. if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
  575. return [];
  576. }
  577. $cacheKey = $this->_getRequestCacheKey($request);
  578. if (!isset($this->_rateCalculationProcess[$cacheKey])) {
  579. $this->_rateCalculationProcess[$cacheKey] = $this->_getResource()->getCalculationProcess($request);
  580. }
  581. return $this->_rateCalculationProcess[$cacheKey];
  582. }
  583. /**
  584. * Gets the calculation process
  585. *
  586. * @param array $rates
  587. * @return array
  588. */
  589. public function reproduceProcess($rates)
  590. {
  591. return $this->getResource()->getCalculationProcess(null, $rates);
  592. }
  593. /**
  594. * Calculate rated tax amount based on price and tax rate.
  595. * If you are using price including tax $priceIncludeTax should be true.
  596. *
  597. * @param float $price
  598. * @param float $taxRate
  599. * @param boolean $priceIncludeTax
  600. * @param boolean $round
  601. * @return float
  602. */
  603. public function calcTaxAmount($price, $taxRate, $priceIncludeTax = false, $round = true)
  604. {
  605. $taxRate = $taxRate / 100;
  606. if ($priceIncludeTax) {
  607. $amount = $price * (1 - 1 / (1 + $taxRate));
  608. } else {
  609. $amount = $price * $taxRate;
  610. }
  611. if ($round) {
  612. return $this->round($amount);
  613. }
  614. return $amount;
  615. }
  616. /**
  617. * Round tax amount
  618. *
  619. * @param float $price
  620. * @return float
  621. */
  622. public function round($price)
  623. {
  624. return $this->priceCurrency->round($price);
  625. }
  626. /**
  627. * @param array $billingAddress
  628. * @param array $shippingAddress
  629. * @param int $customerTaxClassId
  630. * @return array
  631. */
  632. public function getTaxRates($billingAddress, $shippingAddress, $customerTaxClassId)
  633. {
  634. $billingAddressObj = null;
  635. $shippingAddressObj = null;
  636. if (!empty($billingAddress)) {
  637. $billingAddressObj = new \Magento\Framework\DataObject($billingAddress);
  638. }
  639. if (!empty($shippingAddress)) {
  640. $shippingAddressObj = new \Magento\Framework\DataObject($shippingAddress);
  641. }
  642. $rateRequest = $this->getRateRequest($shippingAddressObj, $billingAddressObj, $customerTaxClassId);
  643. $searchCriteria = $this->searchCriteriaBuilder->addFilters(
  644. [$this->filterBuilder->setField(ClassModel::KEY_TYPE)
  645. ->setValue(\Magento\Tax\Api\TaxClassManagementInterface::TYPE_PRODUCT)
  646. ->create()]
  647. )->create();
  648. $ids = $this->taxClassRepository->getList($searchCriteria)->getItems();
  649. $productRates = [];
  650. $idKeys = array_keys($ids);
  651. foreach ($idKeys as $idKey) {
  652. $rateRequest->setProductClassId($idKey);
  653. $rate = $this->getRate($rateRequest);
  654. $productRates[$idKey] = $rate;
  655. }
  656. return $productRates;
  657. }
  658. }