tl;dr: use proper rounding rather than multiplying and casting floats, and switch to the new Bridge parameter
amount_int (see Bridge docs).
When we introduced 3-D Secure, a change to the Paymill Bridge was added so the amount and currency of the purchase is displayed within the 3-D Secure window. It is important to know that the amount and currency you‘re passing to the Bridge has to be the same as within the first transaction for the new payment. This is, in most cases, not an issue, but what happens if you pass a different amount? The transaction will fail. Sad Tim.
However, recently we‘ve noticed that some Merchants are sending a slightly different amount to the Bridge than they try to charge later. It‘s a discrepancy of only 1 cent. After taking a look at the transactions and the Merchants code we found that some Merchants are counting on their software doing the right thing; which isn‘t something software does very often ;-).
Rounding floating point numbers
Huh, already got it? For those who don‘t, let me explain a bit… Floating point numbers, such as
8.37, are not representing numbers exactly. In fact, such a value internally is something like
1.13 is always shown as
1.13, calculating with this number can lead to wrong result. Let‘s see, what happens when I multiply
100in Google Chrome Developer Tools:
> 1.13 * 100 112.99999999999999
This also happens when dealing with other languages like PHP, Ruby or Perl and may not occur on all your systems. To get this right, don‘t cast the resulting float to an integer but round:
> Math.round(1.13 * 100) 113
We‘ve got something for you…
As an enhancement and to prevent future errors, we‘re removing the parameter
amount from our documentation and are adding an extra parameter called
amount_int, which takes the amount as integer. We encourage you to save your goods‘ amount in integer and pass them to the Bridge as you pass them to our API. This way you don‘t have to run into roundoff errors.