diff --git a/Model/Config/CurrencyRoundingConfig.php b/Model/Config/CurrencyRoundingConfig.php index 21261df..4052200 100644 --- a/Model/Config/CurrencyRoundingConfig.php +++ b/Model/Config/CurrencyRoundingConfig.php @@ -7,8 +7,8 @@ namespace Opengento\CurrencyPrecision\Model\Config; -use Magento\Store\Model\ScopeInterface; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Store\Model\ScopeInterface; /** * System configuration of currencies rounding. diff --git a/Observer/AdjustCurrencyPrecision.php b/Observer/AdjustCurrencyPrecision.php index 9ae4ffe..3731a6a 100644 --- a/Observer/AdjustCurrencyPrecision.php +++ b/Observer/AdjustCurrencyPrecision.php @@ -8,8 +8,8 @@ namespace Opengento\CurrencyPrecision\Observer; use Magento\Framework\DataObject; -use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Event\Observer; +use Magento\Framework\Event\ObserverInterface; use Opengento\CurrencyPrecision\Model\CurrencyRounding; /** diff --git a/Plugin/CatalogRule/Model/Indexer/ProductPriceCalculatorRound.php b/Plugin/CatalogRule/Model/Indexer/ProductPriceCalculatorRound.php new file mode 100644 index 0000000..4d559a2 --- /dev/null +++ b/Plugin/CatalogRule/Model/Indexer/ProductPriceCalculatorRound.php @@ -0,0 +1,61 @@ +storeManager = $storeManager; + $this->priceCurrency = $priceCurrency; + } + + /** + * Extract currency object and pass to CurrencyRoundingForAdmin + * + * @param ProductPriceCalculator $calculator + * @param $ruleData + * @param null $productData + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + * @see \Opengento\CurrencyPrecision\Plugin\Directory\Model\CurrencyRoundingForAdmin + */ + public function beforeCalculate( + ProductPriceCalculator $calculator, + $ruleData, + $productData = null + ) { + $website = $this->storeManager->getWebsite($ruleData['website_id']); + $currency = $this->priceCurrency->getCurrency($website->getDefaultStore()->getId()); + return [$ruleData, $productData]; + } +} diff --git a/Plugin/Directory/Model/CurrencyRoundingForAdmin.php b/Plugin/Directory/Model/CurrencyRoundingForAdmin.php new file mode 100644 index 0000000..9f5a5f1 --- /dev/null +++ b/Plugin/Directory/Model/CurrencyRoundingForAdmin.php @@ -0,0 +1,133 @@ +model = $model; + $this->storeManager = $storeManager; + } + + /** + * Override original method to apply correct rounding logic. + * + * @param PriceCurrency $priceCurrency + * @param \Closure $proceed + * @param float $amount + * @param string $scope + * @param string $currency + * @param int $precision + * @return float + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundConvertAndRound( + PriceCurrency $priceCurrency, + \Closure $proceed, + $amount, + $scope = null, + $currency = null, + $precision = PriceCurrency::DEFAULT_PRECISION + ) { + $targetCurrency = $priceCurrency->getCurrency($scope, $currency); + $convertedAmount = $this->storeManager->getStore($scope)->getBaseCurrency()->convert($amount, $targetCurrency); + if ($targetCurrency->getCode() === null) { + return $convertedAmount; + } + + $roundedAmount = $this->round($targetCurrency->getCode(), (float)$convertedAmount); + return $roundedAmount; + } + + /** + * Override original method to apply correct rounding logic. + * + * @param PriceCurrency $priceCurrency + * @param \Closure $proceed + * @param float $amount + * @return float + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundRound( + PriceCurrency $priceCurrency, + \Closure $proceed, + $amount + ) { + $currency = $this->currency; + $currencyCode = null; + if ($currency !== null) { + $currencyCode = $currency->getCode(); + } + + if ($currencyCode === null) { + return (float)$amount; + } + + return $this->round($currencyCode, (float)$amount); + } + + /** + * Set currency object when getCurrency called. + * + * @param \Magento\Directory\Model\PriceCurrency $subject + * @param $result + * @param bool|int|ScopeInterface|string|null $scope + * @param AbstractModel|string|null $currency + */ + public function afterGetCurrency( + PriceCurrency $subject, + $result, + $scope = null, + $currency = null + ) { + $this->currency = $result; + return $result; + } + + + + /** + * Round currency using rounding service. + */ + private function round(string $currencyCode, float $amount): float + { + return $this->model->round($currencyCode, $amount); + } + +} diff --git a/Plugin/PayPal/Api/RoundAmount.php b/Plugin/PayPal/Api/RoundAmount.php new file mode 100644 index 0000000..41debca --- /dev/null +++ b/Plugin/PayPal/Api/RoundAmount.php @@ -0,0 +1,39 @@ +model = $model; + } + + /** + * @param Nvp $nvp + * @param \Closure $proceed + * @param $price + * @return string + */ + public function aroundFormatPrice( + Nvp $nvp, + \Closure $proceed, + $price + ) { + $currencyCode = $nvp->getCurrencyCode(); + $price = $this->model->round($currencyCode, $price); + return sprintf('%.2F', $price); + } +} diff --git a/Plugin/SalesRule/RoundDiscount.php b/Plugin/SalesRule/RoundDiscount.php new file mode 100644 index 0000000..77a6f4e --- /dev/null +++ b/Plugin/SalesRule/RoundDiscount.php @@ -0,0 +1,48 @@ +currencyRounding = $currencyRounding; + } + + /** + * @param DiscountInterface $subject + * @param Data $result + * @param Rule $rule + * @param AbstractItem $item + * @param float $qty + * @return Data $result + */ + public function afterCalculate(DiscountInterface $subject, $result, $rule, $item, $qty) + { + $quote = $item->getQuote(); + $baseCurrency = $quote->getBaseCurrencyCode(); + $quoteCurrency = $quote->getQuoteCurrencyCode(); + + $result->setAmount($this->currencyRounding->round($quoteCurrency, $result->getAmount())); + $result->setBaseAmount($this->currencyRounding->round($baseCurrency, $result->getBaseAmount())); + $result->setBaseOriginalAmount($this->currencyRounding->round($baseCurrency, $result->getBaseOriginalAmount())); + $result->setOriginalAmount($this->currencyRounding->round($quoteCurrency, $result->getOriginalAmount())); + + return $result; + } +} diff --git a/Plugin/Tax/Pricing/ModifyAdjustment.php b/Plugin/Tax/Pricing/ModifyAdjustment.php new file mode 100644 index 0000000..f370de4 --- /dev/null +++ b/Plugin/Tax/Pricing/ModifyAdjustment.php @@ -0,0 +1,132 @@ +taxHelper = $taxHelper; + $this->catalogHelper = $catalogHelper; + $this->priceCurrency = $priceCurrency; + $this->currencyRounding = $currencyRounding; + } + + /** + * @param Adjustment $subject + * @param \Closure $proceed + * @param $amount + * @param SaleableInterface $saleableItem + * @param array $context + * @return float + */ + public function aroundExtractAdjustment( + Adjustment $subject, + \Closure $proceed, + $amount, + SaleableInterface $saleableItem, + $context = [] + ) { + if ($this->taxHelper->priceIncludesTax()) { + $adjustedAmount = $this->catalogHelper->getTaxPrice( + $saleableItem, + $amount, + false, + null, + null, + null, + null, + null, + $this->shouldRound() + ); + $result = $amount - $adjustedAmount; + } else { + $result = 0.; + } + return $result; + } + + /** + * @param Adjustment $subject + * @param \Closure $proceed + * @param $amount + * @param SaleableInterface $saleableItem + * @param array $context + * @return float + */ + public function aroundApplyAdjustment( + Adjustment $subject, + \Closure $proceed, + $amount, + SaleableInterface $saleableItem, + $context = [] + ) { + return $this->catalogHelper->getTaxPrice( + $saleableItem, + $amount, + true, + null, + null, + null, + null, + null, + $this->shouldRound() + ); + } + + /** + * Retrieve should rounding or not. + * + * @return bool + */ + private function shouldRound() + { + $currency = $this->priceCurrency->getCurrency(); + $precision = $this->currencyRounding->getPrecision($currency->getCode()); + if ($precision === 0) { + return true; + } + return false; + } +} diff --git a/Plugin/Tax/RoundQuoteItemPrice.php b/Plugin/Tax/RoundQuoteItemPrice.php new file mode 100644 index 0000000..56f7924 --- /dev/null +++ b/Plugin/Tax/RoundQuoteItemPrice.php @@ -0,0 +1,64 @@ +currencyRounding = $currencyRounding; + } + + /** + * @param CommonTaxCollector $subject + * @param CommonTaxCollector $result + * @param AbstractItem $quoteItem + * @param TaxDetailsItemInterface $itemTaxDetails + * @param TaxDetailsItemInterface $baseItemTaxDetails + * @param Store $store + */ + public function afterUpdateItemTaxInfo( + CommonTaxCollector $subject, + CommonTaxCollector $result, + AbstractItem $quoteItem, + TaxDetailsItemInterface $itemTaxDetails, + TaxDetailsItemInterface $baseItemTaxDetails, + Store $store + ) { + $quote = $quoteItem->getQuote(); + $baseCurrency = $quote->getBaseCurrencyCode(); + if ($baseCurrency === null) { + $baseCurrency = $quote->getStore()->getBaseCurrencyCode(); + } + + $quoteItem->setBasePrice($this->round($quoteItem->getBasePrice(), $baseCurrency)); + $quoteItem->setBasePriceInclTax($this->round($quoteItem->getBasePriceInclTax(), $baseCurrency)); + $quoteItem->setBaseRowTotal($this->round($quoteItem->getBaseRowTotal(), $baseCurrency)); + $quoteItem->setBaseRowTotalInclTax($this->round($quoteItem->getBaseRowTotalInclTax(), $baseCurrency)); + $quoteItem->setBaseTaxAmount($this->round($quoteItem->getBaseTaxAmount(), $baseCurrency)); + $quoteItem->setTaxPercent($baseItemTaxDetails->getTaxPercent()); + //$quoteItem->setBaseDiscountTaxCompensationAmount($baseItemTaxDetails->getDiscountTaxCompensationAmount()); + + return $result; + } + + private function round($amount, $currency) + { + return $this->currencyRounding->round($currency, $amount); + } +} diff --git a/Plugin/Tax/RoundSubtotal.php b/Plugin/Tax/RoundSubtotal.php new file mode 100644 index 0000000..4eb564d --- /dev/null +++ b/Plugin/Tax/RoundSubtotal.php @@ -0,0 +1,66 @@ +currencyRounding = $currencyRounding; + } + + /** + * @param \Magento\Tax\Model\Sales\Total\Quote\Subtotal $subject + * @param $result + * @param Quote $quote + * @param ShippingAssignmentInterface $shippingAssignment + * @param Total $total + */ + public function afterCollect( + \Magento\Tax\Model\Sales\Total\Quote\Subtotal $subject, + $result, + Quote $quote, + ShippingAssignmentInterface $shippingAssignment, + Total $total + ) { + $baseCurrency = $quote->getBaseCurrencyCode(); + if ($baseCurrency === null) { + $baseCurrency = $quote->getStore()->getBaseCurrencyCode(); + } + + $total->setBaseTotalAmount('subtotal', $this->round($baseCurrency, $total->getTotalAmount('subtotal'))); + $total->setBaseTotalAmount('tax', $this->round($baseCurrency, $total->getTotalAmount('tax'))); + $total->setBaseTotalAmount('discount_tax_compensation', $this->round($baseCurrency, $total->getTotalAmount('discount_tax_compensation'))); + + $total->setBaseTaxAmount($this->round($baseCurrency, $total->getBaseTaxAmount())); + $total->setBaseSubtotalTotalInclTax( + $this->round($baseCurrency, $total->getBaseSubtotalTotalInclTax()) + ); + $total->setBaseSubtotalInclTax($this->round($baseCurrency, $total->getBaseSubtotalInclTax())); + + $address = $shippingAssignment->getShipping()->getAddress(); + $address->setBaseSubtotalTotalInclTax($total->getBaseSubtotalInclTax()); + $address->setBaseSubtotal($total->getBaseSubtotal()); + $address->setBaseTaxAmount($total->getBaseTaxAmount()); + return $result; + } + + private function round($code, $amount) + { + return $this->currencyRounding->round($code, (float)$amount); + } +} diff --git a/Plugin/Tax/RoundTaxAmount.php b/Plugin/Tax/RoundTaxAmount.php new file mode 100644 index 0000000..a000b4d --- /dev/null +++ b/Plugin/Tax/RoundTaxAmount.php @@ -0,0 +1,69 @@ +currencyRounding = $currencyRounding; + } + + /** + * @param \Magento\Tax\Model\Sales\Total\Quote\Tax $subject + * @param $result + * @param Quote $quote + * @param ShippingAssignmentInterface $shippingAssignment + * @param Total $total + */ + public function afterCollect( + \Magento\Tax\Model\Sales\Total\Quote\Tax $subject, + $result, + Quote $quote, + ShippingAssignmentInterface $shippingAssignment, + Total $total + ) { + $baseCurrency = $quote->getBaseCurrencyCode(); + if ($baseCurrency === null) { + $baseCurrency = $quote->getStore()->getBaseCurrencyCode(); + } + + $total->setBaseTotalAmount('subtotal', $this->round($baseCurrency, $total->getBaseTotalAmount('subtotal'))); + $total->setBaseTotalAmount('tax', $this->round($baseCurrency, $total->getBaseTotalAmount('tax'))); + $total->setBaseTotalAmount('discount_tax_compensation', $this->round($baseCurrency, $total->getBaseTotalAmount('discount_tax_compensation'))); + + $total->setBaseTaxAmount($this->round($baseCurrency, $total->getBaseTaxAmount())); + $total->setBaseSubtotalTotalInclTax( + $this->round($baseCurrency, $total->getBaseSubtotalTotalInclTax()) + ); + $total->setBaseSubtotalInclTax($this->round($baseCurrency, $total->getBaseSubtotalInclTax())); + + $address = $shippingAssignment->getShipping()->getAddress(); + $address->setBaseSubtotalTotalInclTax($total->getBaseSubtotalTotalInclTax()); + $address->setBaseSubtotal($total->getBaseSubtotal()); + $address->setBaseTaxAmount($total->getBaseTaxAmount()); + + $total->getAppliedTaxes(); + + return $result; + } + + private function round($code, $amount) + { + return $this->currencyRounding->round($code, (float)$amount); + } +} diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml new file mode 100644 index 0000000..2a35ccd --- /dev/null +++ b/etc/adminhtml/di.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/etc/di.xml b/etc/di.xml index 306cc32..8c9380a 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -15,4 +15,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml new file mode 100644 index 0000000..17d8b0b --- /dev/null +++ b/etc/frontend/di.xml @@ -0,0 +1,12 @@ + + + + + + +