Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unitprice precision incorrect due ommited numbers in one-time charges #89

Closed
KumaVolt opened this issue May 27, 2022 · 8 comments · Fixed by #128
Closed

Unitprice precision incorrect due ommited numbers in one-time charges #89

KumaVolt opened this issue May 27, 2022 · 8 comments · Fixed by #128

Comments

@KumaVolt
Copy link

An incorrect amount is shown in some edge cases when checking out.

For example
A product is €1.00 with 21% tax. Without the tax this will results 0,8264462809917355. When applying the required formula * 100 for cashier results in 82,64462809917355. Adding this result in ChargeItemBuilder will ommit every number after the comma resulting in the price €0,99 when checking out.

Is there a reason why mollie only includes 2 numbers after the comma?

@sandervanhooft
Copy link
Collaborator

Hi @KumaVolt ,

Can you share a code sample so we can reproduce this issue?

Note that cashier mollie performs all calculations locally.

@KumaVolt
Copy link
Author

    public function __invoke(Request $request)  
    {
        $user = User::orderBy('id', 'desc')->first();
        
        $product_price = 1.00;
        $tax_rate = 0.21; // 21% tax rate

        // create a new charge item
        $item = new ChargeItemBuilder($user);
        $item->unitPrice(money($this->priceWithoutTax($product_price, $tax_rate) * 100, 'EUR'));
        $item->description('Product description');
        $item->quantity(1);
        $item->taxPercentage($tax_rate * 100);
        $chargeItem = $item->make();

        // dd($chargeItem); // charge item object omitted numbers that are after the comma

        // generate checkout link and navigate to it
        $charge = $user->newFirstPaymentChargeThroughCheckout();
        $charge->addItem($chargeItem);
        $result = $charge->create();

        // expecting to pay 1 euro
        if(is_a($result, \Laravel\Cashier\Http\RedirectToCheckoutResponse::class)) {
            return $result;
        }
    }

    private function priceWithoutTax($price, $tax_rate)
    {
        return $price / (1 + ($tax_rate));
    }

I made a demo repository for this as wel.
https://github.com/KumaVolt/mollieissue

@KumaVolt
Copy link
Author

@sandervanhooft Did you had the time to look into this yet?

@KumaVolt
Copy link
Author

On further inspection i found an open pull request in the moneyphp/money library which addresses the issues i am currently facing with calculating the precision in this library.

@sandervanhooft
Copy link
Collaborator

Hi @KumaVolt,

We have this on the radar, but since it's an edge case / related to MoneyPHP it's not high on the backlog. I am happy to accept a PR if you see a way to fix this sooner.

@Master-Minder
Copy link

@sandervanhooft It's not an edge case, we noticed a similar issue and it has nothing to do with MoneyPHP but your helper on line 34 force typecasting every value to integer and thereby hiding the error which the built in MoneyPHP type checking would otherwise throw if you give it something which is not an integer. And how can a servious rounding issue be an edge case in the first place for a payment provider? It's your main purpose that the numbers match.
This is a one line fix and got not addresse for months as I can see now. Just remove the int typecasting and let MoneyPHP throw and error if you don't give it an integer value.
@KumaVolt The workaround we used for now, is a simple round() call before passing the value, since the round() call actually rounds and not just cuts of everything after the "." what the typecasting does.

@sandervanhooft
Copy link
Collaborator

@Master-Minder as mentioned, I am happy to accept a PR.

@Master-Minder
Copy link

@sandervanhooft I can offer you a PR which is absolutly untested, or just tested for this scenario, or do you expect me to do full regression testing? Since the money() helper is used all over the place in your code and I have no idea if this will impact anywhere else.
With a quick look at some of your automated test scripts I also didn't find any test cases covering the scenario that the value passed to the money() helper is not an int, so those tests won't find possible impacts anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants