OrderItem total price rounding issue

Created on 27 June 2023, over 1 year ago
Updated 10 October 2023, about 1 year ago

Problem/Motivation

Adding multiple products, where prices are rounded to whole numbers, to cart results in wrong rounding when the product prices are stored without tax, and when multiplied by the tax, we get a non-whole number.

Given a product variation with the following properties:
- Price: 1714.6
- Tax: 5%

Total price calculation results in 1714.6 * 1.05 = 1800.33
The unit price is displayed as 1800. The expected price of two would be 3600.
When purchasing two items from this product the total price is 3601.

Steps to reproduce

1. Set the rounding to whole numbers.
2. Create a product with a non-whole total price (possibly with a tax adjustment).
3. Add the product to cart and increase the quantity.
4. The total price of OrderItem is does not equal to the displayed unit price multipled by the quantity.

Proposed solution

Change the order of operations when calculating total price of `OrderItem` entity in `recalculateTotalPrice()`.

Before:
```php
$total_price = $unit_price->multiply($this->getQuantity());
$this->total_price = $rounder->round($total_price);
```

After:
```php
$this->total_price = $rounder->round($unit_price)->multiply($this->getQuantity());
```

🐛 Bug report
Status

Closed: won't fix

Version

2.35

Component

Order

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 8.0 & MySQL 5.7
    last update over 1 year ago
    785 pass
  • Issue created by @bpstr
  • 🇪🇸Spain dcraig91

    Hello, thanks you very much for the patch is working perfectly for me

  • Status changed to Closed: won't fix about 1 year ago
  • 🇷🇸Serbia bojanz

    This is by design.

    There are two equally legal ways of calculating tax: per-unit (where you apply the percentage to the unit price, then round) and per-total (where you apply the percentage to the total price, then round). Commerce 2.x (and most ERPs) use the second way. The upside of this approach is much better promotion logic, especially when prices include tax (this never worked right in 7.x-1.x). The downside is that there is no guarantee that the rounded unit price times quantity will be equal to the rounded total price..

    Your approach tries to reset the approach back to the first way, as used in 7.x-1.x. We can't do that, as that would break promotions, and many other parts of the system built with the same assumption.

Production build 0.71.5 2024