![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-tax/Helper/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Tax\Helper; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Store\Model\Store; use Magento\Customer\Model\Address; use Magento\Tax\Model\Config; use Magento\Tax\Api\OrderTaxManagementInterface; use Magento\Sales\Model\Order\Invoice; use Magento\Sales\Model\Order\Creditmemo; use Magento\Tax\Api\Data\OrderTaxDetailsItemInterface; use Magento\Sales\Model\EntityInterface; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\App\ObjectManager; /** * Tax helper * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @api * @since 100.0.2 */ class Data extends \Magento\Framework\App\Helper\AbstractHelper { /** * Default tax class for customers */ const CONFIG_DEFAULT_CUSTOMER_TAX_CLASS = 'tax/classes/default_customer_tax_class'; /** * Default tax class for products */ const CONFIG_DEFAULT_PRODUCT_TAX_CLASS = 'tax/classes/default_product_tax_class'; /** * Tax configuration object * * @var Config */ protected $_config; /** * Postcode cut to this length when creating search templates * * @var integer */ protected $_postCodeSubStringLength = 10; /** * Json Helper * * @var \Magento\Framework\Json\Helper\Data */ protected $jsonHelper; /** * @var \Magento\Store\Model\StoreManagerInterface */ protected $_storeManager; /** * @var \Magento\Framework\Locale\FormatInterface */ protected $_localeFormat; /** * @var \Magento\Tax\Model\ResourceModel\Sales\Order\Tax\CollectionFactory */ protected $_orderTaxCollectionFactory; /** * @var \Magento\Framework\Locale\ResolverInterface */ protected $_localeResolver; /** * @var \Magento\Catalog\Helper\Data */ protected $catalogHelper; /** * @var OrderTaxManagementInterface */ protected $orderTaxManagement; /** * @var PriceCurrencyInterface */ protected $priceCurrency; /** * @var Json */ private $serializer; /** * Constructor * * @param \Magento\Framework\App\Helper\Context $context * @param \Magento\Framework\Json\Helper\Data $jsonHelper * @param Config $taxConfig * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\Locale\FormatInterface $localeFormat * @param \Magento\Tax\Model\ResourceModel\Sales\Order\Tax\CollectionFactory $orderTaxCollectionFactory * @param \Magento\Framework\Locale\ResolverInterface $localeResolver * @param \Magento\Catalog\Helper\Data $catalogHelper * @param OrderTaxManagementInterface $orderTaxManagement * @param PriceCurrencyInterface $priceCurrency * @param Json $serializer * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\App\Helper\Context $context, \Magento\Framework\Json\Helper\Data $jsonHelper, Config $taxConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\Locale\FormatInterface $localeFormat, \Magento\Tax\Model\ResourceModel\Sales\Order\Tax\CollectionFactory $orderTaxCollectionFactory, \Magento\Framework\Locale\ResolverInterface $localeResolver, \Magento\Catalog\Helper\Data $catalogHelper, OrderTaxManagementInterface $orderTaxManagement, PriceCurrencyInterface $priceCurrency, Json $serializer = null ) { parent::__construct($context); $this->priceCurrency = $priceCurrency; $this->_config = $taxConfig; $this->jsonHelper = $jsonHelper; $this->_storeManager = $storeManager; $this->_localeFormat = $localeFormat; $this->_orderTaxCollectionFactory = $orderTaxCollectionFactory; $this->_localeResolver = $localeResolver; $this->catalogHelper = $catalogHelper; $this->orderTaxManagement = $orderTaxManagement; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); } /** * Return max postcode length to create search templates * * @return int $len */ public function getPostCodeSubStringLength() { $len = (int) $this->_postCodeSubStringLength; if ($len <= 0) { $len = 10; } return $len; } /** * Get tax configuration object * * @return Config */ public function getConfig() { return $this->_config; } /** * Check if product prices inputed include tax * * @param null|int|string|Store $store * @return bool */ public function priceIncludesTax($store = null) { return $this->_config->priceIncludesTax($store) || $this->_config->getNeedUseShippingExcludeTax(); } /** * Check what taxes should be applied after discount * * @param null|int|string|Store $store * @return bool */ public function applyTaxAfterDiscount($store = null) { return $this->_config->applyTaxAfterDiscount($store); } /** * Get product price display type * 1 - Excluding tax * 2 - Including tax * 3 - Both * * @param null|int|string|Store $store * @return int */ public function getPriceDisplayType($store = null) { return $this->_config->getPriceDisplayType($store); } /** * Check if necessary do product price conversion * If it necessary will be returned conversion type (minus or plus) * * @param null|int|string|Store $store * @return bool */ public function needPriceConversion($store = null) { return $this->_config->needPriceConversion($store); } /** * Check if need display full tax summary information in totals block * * @param null|int|string|Store $store * @return bool */ public function displayFullSummary($store = null) { return $this->_config->displayCartFullSummary($store); } /** * Check if need display zero tax in subtotal * * @param null|int|string|Store $store * @return bool */ public function displayZeroTax($store = null) { return $this->_config->displayCartZeroTax($store); } /** * Check if need display cart prices included tax * * @param null|int|string|Store $store * @return bool */ public function displayCartPriceInclTax($store = null) { return $this->_config->displayCartPricesInclTax($store); } /** * Check if need display cart prices excluding price * * @param null|int|string|Store $store * @return bool */ public function displayCartPriceExclTax($store = null) { return $this->_config->displayCartPricesExclTax($store); } /** * Check if need display cart prices excluding and including tax * * @param null|int|string|Store $store * @return bool */ public function displayCartBothPrices($store = null) { return $this->_config->displayCartPricesBoth($store); } /** * Check if need display order prices included tax * * @param null|int|string|Store $store * @return bool */ public function displaySalesPriceInclTax($store = null) { return $this->_config->displaySalesPricesInclTax($store); } /** * Check if need display order prices excluding price * * @param null|int|string|Store $store * @return bool */ public function displaySalesPriceExclTax($store = null) { return $this->_config->displaySalesPricesExclTax($store); } /** * Check if need display order prices excluding and including tax * * @param null|int|string|Store $store * @return bool */ public function displaySalesBothPrices($store = null) { return $this->_config->displaySalesPricesBoth($store); } /** * Check if we need display price include and exclude tax for order/invoice subtotal * * @param null|int|string|Store $store * @return bool */ public function displaySalesSubtotalBoth($store = null) { return $this->_config->displaySalesSubtotalBoth($store); } /** * Check if we need display price include tax for order/invoice subtotal * * @param null|int|string|Store $store * @return bool */ public function displaySalesSubtotalInclTax($store = null) { return $this->_config->displaySalesSubtotalInclTax($store); } /** * Check if we need display price exclude tax for order/invoice subtotal * * @param null|int|string|Store $store * @return bool */ public function displaySalesSubtotalExclTax($store = null) { return $this->_config->displaySalesSubtotalExclTax($store); } /** * Get prices javascript format json * * @param null|int|string|Store $store * @return string */ public function getPriceFormat($store = null) { $this->_localeResolver->emulate($store); $priceFormat = $this->_localeFormat->getPriceFormat(); $this->_localeResolver->revert(); if ($store) { $priceFormat['pattern'] = $this->_storeManager->getStore($store)->getCurrentCurrency()->getOutputFormat(); } return $this->jsonHelper->jsonEncode($priceFormat); } /** * Check if we have display in catalog prices including tax * * @return bool */ public function displayPriceIncludingTax() { return $this->getPriceDisplayType() == Config::DISPLAY_TYPE_INCLUDING_TAX; } /** * Check if we have display in catalog prices excluding tax * * @return bool */ public function displayPriceExcludingTax() { return $this->getPriceDisplayType() == Config::DISPLAY_TYPE_EXCLUDING_TAX; } /** * Check if we have display in catalog prices including and excluding tax * * @param null|int|string|Store $store * @return bool */ public function displayBothPrices($store = null) { return $this->getPriceDisplayType($store) == Config::DISPLAY_TYPE_BOTH; } /** * Check if shipping prices include tax * * @param null|string|bool|int|Store $store * @return bool */ public function shippingPriceIncludesTax($store = null) { return $this->_config->shippingPriceIncludesTax($store); } /** * Get shipping price display type * * @param null|string|bool|int|Store $store * @return int */ public function getShippingPriceDisplayType($store = null) { return $this->_config->getShippingPriceDisplayType($store); } /** * Returns whether the shipping price should display with taxes included * * @return bool */ public function displayShippingPriceIncludingTax() { return $this->getShippingPriceDisplayType() == Config::DISPLAY_TYPE_INCLUDING_TAX; } /** * Returns whether the shipping price should display without taxes * * @return bool */ public function displayShippingPriceExcludingTax() { return $this->getShippingPriceDisplayType() == Config::DISPLAY_TYPE_EXCLUDING_TAX; } /** * Returns whether the shipping price should display both with and without taxes * * @return bool */ public function displayShippingBothPrices() { return $this->getShippingPriceDisplayType() == Config::DISPLAY_TYPE_BOTH; } /** * Get tax class id specified for shipping tax estimation * * @param null|string|bool|int|Store $store * @return int */ public function getShippingTaxClass($store) { return $this->_config->getShippingTaxClass($store); } /** * Get shipping price * * @param float $price * @param bool|null $includingTax * @param Address|null $shippingAddress * @param int|null $ctc * @param null|string|bool|int|Store $store * @return float */ public function getShippingPrice($price, $includingTax = null, $shippingAddress = null, $ctc = null, $store = null) { $pseudoProduct = new \Magento\Framework\DataObject(); $pseudoProduct->setTaxClassId($this->getShippingTaxClass($store)); $billingAddress = false; if ($shippingAddress && $shippingAddress->getQuote() && $shippingAddress->getQuote()->getBillingAddress()) { $billingAddress = $shippingAddress->getQuote()->getBillingAddress(); } $price = $this->catalogHelper->getTaxPrice( $pseudoProduct, $price, $includingTax, $shippingAddress, $billingAddress, $ctc, $store, $this->shippingPriceIncludesTax($store) ); return $price; } /** * Get configuration setting "Apply Discount On Prices Including Tax" value * * @param null|string|bool|int|Store $store * @return bool */ public function discountTax($store = null) { return $this->_config->discountTax($store); } /** * Get value of "Apply Tax On" custom/original price configuration settings * * @param null|string|bool|int|Store $store * @return string|null */ public function getTaxBasedOn($store = null) { return $this->scopeConfig->getValue( Config::CONFIG_XML_PATH_BASED_ON, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store ); } /** * Check if tax can be applied to custom price * * @param null|string|bool|int|Store $store * @return bool */ public function applyTaxOnCustomPrice($store = null) { return (int) $this->scopeConfig->getValue( Config::CONFIG_XML_PATH_APPLY_ON, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store ) == 0; } /** * Check if tax should be applied just to original price * * @param null|string|bool|int|Store $store * @return bool */ public function applyTaxOnOriginalPrice($store = null) { return (int) $this->scopeConfig->getValue( Config::CONFIG_XML_PATH_APPLY_ON, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store ) == 1; } /** * Get taxes/discounts calculation sequence * * This sequence depends on "Catalog price include tax", "Apply Tax After Discount" * and "Apply Discount On Prices Including Tax" configuration options. * * @param null|int|string|Store $store * @return string */ public function getCalculationSequence($store = null) { return $this->_config->getCalculationSequence($store); } /** * Get tax calculation algorithm code * * @param null|string|bool|int|Store $store * @return string */ public function getCalculationAlgorithm($store = null) { return $this->_config->getAlgorithm($store); } /** * 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); } /** * Accumulates the pre-calculated taxes for each tax class * * This method accepts and returns the 'taxClassAmount' array with format: * array( * $index => array( * 'tax_amount' => $taxAmount, * 'base_tax_amount' => $baseTaxAmount, * 'title' => $title, * 'percent' => $percent * ) * ) * * @param array $taxClassAmount * @param OrderTaxDetailsItemInterface $itemTaxDetail * @param float $ratio * @return array */ private function _aggregateTaxes($taxClassAmount, OrderTaxDetailsItemInterface $itemTaxDetail, $ratio) { $itemAppliedTaxes = $itemTaxDetail->getAppliedTaxes(); foreach ($itemAppliedTaxes as $itemAppliedTax) { $taxAmount = $itemAppliedTax->getAmount() * $ratio; $baseTaxAmount = $itemAppliedTax->getBaseAmount() * $ratio; if (0 == $taxAmount && 0 == $baseTaxAmount) { continue; } $taxCode = $itemAppliedTax->getCode(); if (!isset($taxClassAmount[$taxCode])) { $taxClassAmount[$taxCode]['title'] = $itemAppliedTax->getTitle(); $taxClassAmount[$taxCode]['percent'] = $itemAppliedTax->getPercent(); $taxClassAmount[$taxCode]['tax_amount'] = $taxAmount; $taxClassAmount[$taxCode]['base_tax_amount'] = $baseTaxAmount; } else { $taxClassAmount[$taxCode]['tax_amount'] += $taxAmount; $taxClassAmount[$taxCode]['base_tax_amount'] += $baseTaxAmount; } } return $taxClassAmount; } /** * Returns the array of tax rates for the order * * @param \Magento\Sales\Model\Order $order * @return array */ protected function _getTaxRateSubtotals($order) { return $this->_orderTaxCollectionFactory->create()->loadByOrder($order)->toArray(); } /** * Retrieve default customer tax class from config * * @return string|null */ public function getDefaultCustomerTaxClass() { return $this->scopeConfig->getValue( self::CONFIG_DEFAULT_CUSTOMER_TAX_CLASS, \Magento\Store\Model\ScopeInterface::SCOPE_STORE ); } /** * Retrieve default product tax class from config * * @return string|null */ public function getDefaultProductTaxClass() { return $this->scopeConfig->getValue( self::CONFIG_DEFAULT_PRODUCT_TAX_CLASS, \Magento\Store\Model\ScopeInterface::SCOPE_STORE ); } /** * Return whether cross border trade is enabled or not * * @param null|int|string|Store $store * @return bool */ public function isCrossBorderTradeEnabled($store = null) { return (bool) $this->_config->crossBorderTradeEnabled($store); } /** * @param EntityInterface $current * @return array */ protected function calculateTaxForOrder(EntityInterface $current) { $taxClassAmount = []; $orderTaxDetails = $this->orderTaxManagement->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(); } return $taxClassAmount; } /** * @param EntityInterface $order * @param EntityInterface $salesItem * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function calculateTaxForItems(EntityInterface $order, EntityInterface $salesItem) { $taxClassAmount = []; $orderTaxDetails = $this->orderTaxManagement->getOrderTaxDetails($order->getId()); // Apply any taxes for the items /** @var $item \Magento\Sales\Model\Order\Invoice\Item|\Magento\Sales\Model\Order\Creditmemo\Item */ foreach ($salesItem->getItems() as $item) { $orderItem = $item->getOrderItem(); $orderItemId = $orderItem->getId(); $orderItemTax = $orderItem->getTaxAmount(); $itemTax = $item->getTaxAmount(); if (!$itemTax || !(float)$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) { $taxClassAmount = $this->_aggregateTaxes($taxClassAmount, $itemTaxDetail, $itemRatio); } elseif ($itemTaxDetail->getAssociatedItemId() == $orderItemId) { $taxableItemType = $itemTaxDetail->getType(); $ratio = $itemRatio; if ($item->getTaxRatio()) { $taxRatio = $this->serializer->unserialize($item->getTaxRatio()); if (isset($taxRatio[$taxableItemType])) { $ratio = $taxRatio[$taxableItemType]; } } $taxClassAmount = $this->_aggregateTaxes($taxClassAmount, $itemTaxDetail, $ratio); } } } // Apply any taxes for shipping $shippingTaxAmount = $salesItem->getShippingTaxAmount(); $originalShippingTaxAmount = $order->getShippingTaxAmount(); if ($shippingTaxAmount && $originalShippingTaxAmount && $shippingTaxAmount != 0 && (float)$originalShippingTaxAmount ) { //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\Quote\Model\Quote\Address::TYPE_SHIPPING) { $taxClassAmount = $this->_aggregateTaxes($taxClassAmount, $itemTaxDetail, $shippingRatio); } } } return $taxClassAmount; } /** * Check whether display price is affected by different tax rates * * @param null|int|string|Store $store * @return bool */ public function isCatalogPriceDisplayAffectedByTax($store = null) { if ($this->displayBothPrices($store)) { return true; } $priceInclTax = $this->priceIncludesTax($store); if ($priceInclTax) { return ($this->isCrossBorderTradeEnabled($store) xor $this->displayPriceIncludingTax()); } else { return $this->displayPriceIncludingTax(); } } }