Skip to content

PercentageDiscountHandler behavior is unexpected #307

Description

@GRardB

Prior art:

I recently added some coupons to my app, and when using the PercentageDiscountHandler , I ran into problems when it came to the calculation of the order total as well as the invoice that was generated. It's easiest to explain with examples:

Order without coupon

Item subtotal: €150
Subtotal: €150
VAT 21%: €31.50
Total: €181.50

Order with 50% coupon (expectation)

Item subtotal: €150
Coupon: -€75
Subtotal: €75
VAT 21%: €15.75
Total: €90.75

Order with 50% coupon (actual, with no_tax = true)

Item subtotal: €150
Coupon: -€90.75
Subtotal: €59.25
VAT 21%: €31.50
Total: €90.75

In this example, we can see that the total is correct, but the subtotal and VAT calculation are incorrect. With no_tax set to true, the PercentageDiscountHandler is calculating the value of the coupon including VAT (90.75) and subtracting it from the subtotal excluding VAT (150). It then calculates the total VAT (31.50) not by using the resulting [incorrect] subtotal (59.25), but by using the item subtotal (150). This results in the correct total, but we'd then need to pay 34.7% VAT instead of 21%.

Order with 50% coupon (actual, with no_tax = false)

Item subtotal: €150
Coupon: -€90.75
Subtotal: €59.25
VAT 21%: €12.44
Total: €71.69

In this example, the total and the VAT calculation are incorrect. Like in the previous example, the value of the coupon includes VAT (90.75) and is being subtracted from the item subtotal excluding VAT (150), resulting in the wrong overall subtotal (59.25). However, with no_tax set to false, it does properly use the resulting subtotal (59.25) to calculate the VAT, which ends up being 12.44. However, because the calculated subtotal was incorrect, the VAT is also incorrect.

I don't understand the logic behind either of these behaviors, and I can't imagine that they're working as intended. For now, I've created a custom PercentageDiscountHandler which undoes the addition of VAT to the coupon:

class PercentageDiscountHandler extends CashierPercentageDiscountHandler
{
    protected function unitPrice(Money $base)
    {
        return parent::unitPrice($base)->divide('1.21');
    }
}

However, this feels a bit hacky, and I would prefer if the library was fixed. I know it's a breaking change, so perhaps it could be done for the next major version or something. At the very least, there should be an option that we can set to calculate the coupon value correctly. There was a PR to address this years ago (linked above), but it went ignored.

Out of curiosity, is this actually working as intended? If so, what's the logic? I can't imagine that this is the behavior that most people want or expect, given that they would result in either reporting a higher percentage of VAT to the government or increasing the value of coupons (thus decreasing revenue).

It's worth noting that the FixedDiscountHandler does not behave like this. With no_tax set to false, everything is calculated correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions