Skip to content
Snippets Groups Projects
Commit 24776b80 authored by Youri van Koppen's avatar Youri van Koppen Committed by Bojan Živanović
Browse files

Issue #2897190 by MegaChriz, jonnyeom, bojanz, sagesolutions, edurenye, Hubbs,...

Issue #2897190 by MegaChriz, jonnyeom, bojanz, sagesolutions, edurenye, Hubbs, dev.tim: Tax calculations do not take discounts (promotions) into account
parent e1ca6fed
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,7 @@ services:
class: Drupal\commerce_promotion\PromotionOrderProcessor
arguments: ['@entity_type.manager']
tags:
- { name: commerce_order.order_processor, priority: 50, adjustment_type: promotion }
- { name: commerce_order.order_processor, priority: 100, adjustment_type: promotion }
commerce_promotion.usage:
class: Drupal\commerce_promotion\PromotionUsage
......
......@@ -17,4 +17,4 @@ services:
class: Drupal\commerce_tax\TaxOrderProcessor
arguments: ['@entity_type.manager']
tags:
- { name: commerce_order.order_processor, priority: 100, adjustment_type: tax }
- { name: commerce_order.order_processor, priority: 50, adjustment_type: tax }
......@@ -145,8 +145,10 @@ abstract class LocalTaxTypeBase extends TaxTypeBase implements LocalTaxTypeInter
foreach ($rates as $zone_id => $rate) {
$zone = $zones[$zone_id];
$unit_price = $order_item->getUnitPrice();
$percentage = $rate->getPercentage();
// Determine the final unit price.
// This calculation must be done with a non-adjusted unit price.
$unit_price = $order_item->getUnitPrice();
$tax_amount = $percentage->calculateTaxAmount($unit_price, $prices_include_tax);
if ($this->shouldRound()) {
$tax_amount = $this->rounder->round($tax_amount);
......@@ -159,6 +161,14 @@ abstract class LocalTaxTypeBase extends TaxTypeBase implements LocalTaxTypeInter
$unit_price = $unit_price->add($tax_amount);
$order_item->setUnitPrice($unit_price);
}
// Now determine the actual tax amount, with the adjustments applied.
$adjusted_unit_price = $order_item->getAdjustedUnitPrice(['promotion', 'fee']);
if (!$adjusted_unit_price->equals($unit_price)) {
$tax_amount = $percentage->calculateTaxAmount($adjusted_unit_price, $prices_include_tax);
if ($this->shouldRound()) {
$tax_amount = $this->rounder->round($tax_amount);
}
}
$order_item->addAdjustment(new Adjustment([
'type' => 'tax',
......
......@@ -2,6 +2,7 @@
namespace Drupal\Tests\commerce_tax\Kernel\Plugin\Commerce\TaxType;
use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_order\Entity\OrderItemType;
......@@ -188,6 +189,116 @@ class CustomTest extends CommerceKernelTestBase {
$this->assertEquals(new Price('8.61', 'USD'), $order_item->getUnitPrice());
}
/**
* @covers ::apply
*/
public function testDiscountedPrices() {
// Tax-inclusive prices + display-inclusive taxes.
// A 10.33 USD price with a 1.00 USD discount should have a 9.33 USD total.
$order = $this->buildOrder('RS', 'RS', [], TRUE);
$order_items = $order->getItems();
$order_item = reset($order_items);
$order_item->addAdjustment(new Adjustment([
'type' => 'promotion',
'label' => t('Discount'),
'amount' => new Price('-1', 'USD'),
]));
$this->plugin->apply($order);
$order_items = $order->getItems();
$order_item = reset($order_items);
$adjustments = $order->collectAdjustments();
$tax_adjustment = end($adjustments);
$this->assertCount(2, $adjustments);
$this->assertEquals('tax', $tax_adjustment->getType());
$this->assertEquals(t('VAT'), $tax_adjustment->getLabel());
$this->assertEquals(new Price('1.56', 'USD'), $tax_adjustment->getAmount());
$this->assertEquals('0.2', $tax_adjustment->getPercentage());
$this->assertEquals(new Price('10.33', 'USD'), $order_item->getUnitPrice());
$this->assertEquals(new Price('9.33', 'USD'), $order_item->getAdjustedUnitPrice());
// Non-tax-inclusive prices + display-inclusive taxes.
// A 10.33 USD price is 12.40 USD with 20% tax included.
// A 1.00 USD discount should result in a 11.40 USD total.
$order = $this->buildOrder('RS', 'RS', []);
$order_items = $order->getItems();
$order_item = reset($order_items);
$order_item->addAdjustment(new Adjustment([
'type' => 'promotion',
'label' => t('Discount'),
'amount' => new Price('-1', 'USD'),
]));
$this->plugin->apply($order);
$order_items = $order->getItems();
$order_item = reset($order_items);
$adjustments = $order->collectAdjustments();
$tax_adjustment = end($adjustments);
$this->assertCount(2, $adjustments);
$this->assertEquals('tax', $tax_adjustment->getType());
$this->assertEquals(t('VAT'), $tax_adjustment->getLabel());
$this->assertEquals(new Price('2.28', 'USD'), $tax_adjustment->getAmount());
$this->assertEquals('0.2', $tax_adjustment->getPercentage());
$this->assertEquals(new Price('12.40', 'USD'), $order_item->getUnitPrice());
$this->assertEquals(new Price('11.40', 'USD'), $order_item->getAdjustedUnitPrice());
// Non-tax-inclusive prices + non-display-inclusive taxes.
// A 10.33 USD price with a 1.00 USD discount is 9.33 USD.
// And 9.33 USD plus 20% tax is 11.20 USD.
$configuration = $this->plugin->getConfiguration();
$configuration['display_inclusive'] = FALSE;
$this->plugin->setConfiguration($configuration);
$order = $this->buildOrder('RS', 'RS', []);
$order_items = $order->getItems();
$order_item = reset($order_items);
$order_item->addAdjustment(new Adjustment([
'type' => 'promotion',
'label' => t('Discount'),
'amount' => new Price('-1', 'USD'),
]));
$this->plugin->apply($order);
$order_items = $order->getItems();
$order_item = reset($order_items);
$adjustments = $order->collectAdjustments();
$tax_adjustment = end($adjustments);
$this->assertCount(2, $adjustments);
$this->assertEquals('tax', $tax_adjustment->getType());
$this->assertEquals(t('VAT'), $tax_adjustment->getLabel());
$this->assertEquals(new Price('1.87', 'USD'), $tax_adjustment->getAmount());
$this->assertEquals('0.2', $tax_adjustment->getPercentage());
$this->assertEquals(new Price('10.33', 'USD'), $order_item->getUnitPrice());
$this->assertEquals(new Price('11.20', 'USD'), $order_item->getAdjustedUnitPrice());
// Tax-inclusive prices + non-display-inclusive taxes.
// A 10.33 USD price is 8.61 USD once the 20% tax is removed.
// A 1.00 USD discount gives 7.61 USD + 20% VAT -> 8.88 USD.
$configuration = $this->plugin->getConfiguration();
$configuration['display_inclusive'] = FALSE;
$this->plugin->setConfiguration($configuration);
$order = $this->buildOrder('RS', 'RS', [], TRUE);
$order_items = $order->getItems();
$order_item = reset($order_items);
$order_item->addAdjustment(new Adjustment([
'type' => 'promotion',
'label' => t('Discount'),
'amount' => new Price('-1', 'USD'),
]));
$this->plugin->apply($order);
$order_items = $order->getItems();
$order_item = reset($order_items);
$adjustments = $order->collectAdjustments();
$tax_adjustment = end($adjustments);
$this->assertCount(2, $adjustments);
$this->assertEquals('tax', $tax_adjustment->getType());
$this->assertEquals(t('VAT'), $tax_adjustment->getLabel());
$this->assertEquals(new Price('1.27', 'USD'), $tax_adjustment->getAmount());
$this->assertEquals('0.2', $tax_adjustment->getPercentage());
$this->assertEquals(new Price('8.61', 'USD'), $order_item->getUnitPrice());
$this->assertEquals(new Price('8.88', 'USD'), $order_item->getAdjustedUnitPrice());
}
/**
* @covers ::apply
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment