Reputation: 12358
I am creating a web app using PHP/Laravel and Braintree for payments. I am using the Braintree dropin.
A simplified flow of the web app:
Braintree_Transaction::sale()
Regarding the above, I would like to get some advice on best practice for setting the amount in the Braintree_Transaction::sale()
method call in step 4.
In the Braintree PHP example on github the amount used in the Braintree_Transaction::sale()
method call is taken from a text input in the form, this can be edited by the user, I assume for example purposes.
In my web app flow described above, after step 1, would I be correct to set the quote/price of the selected service in the session then show this value from the session to the user in step 2 and finally pass the value from the session as the amount
to Braintree_Transaction::sale()
? Or is there a different recommended approach to take? My main concern is charging the customer the correct amount.
As the quote/price is calculated in PHP by taking the uploaded file's word count and multiplying it with the service a customer has selected this will at times involve floating point numbers. E.g. Word count is 1000, selected service is proof-reading which is x1.5, so quote would be 1500 => £15.00.
If my memory serves me correctly Stripe represents, for example, one pound (£) in pennies 100
. This is nice as it helps avoid rounding errors. Braintree on the other hand I believe expects one pound (£) to be represented with the decimal point 1.00
.
What would be my best approach to avoid any rounding errors in such a scenario?
Thanks for any suggestions and please ask for more details if required I've tried to make this as brief and general as possible.
Upvotes: 1
Views: 461
Reputation: 15374
would I be correct to set the quote/price of the selected service in the session then show this value from the session to the user in step 2 and finally pass the value from the session as the amount to Braintree_Transaction::sale()?
Yes, that's one valid approach. Session values are stored server side, so they can't be manipulated directly by the user, and are intended for carrying information across page requests.
Another solution is to store something like a shopping cart in a database. This has the advantages of long term storage so a user could potentially come back to finish the process later, you could easily run reports against it, and you can track things like drop-out rates.
Don't trust the browser with anything except displaying values. Meaning don't store the quote in the browser or perform any calculations there because they can be altered by the user.
What would be my best approach to avoid any rounding errors in such a scenario?
Not enough developers think about this before they get started on a project. If you're not working with integers you need to use fixed point math.
If you are using a relational database, store monetary values as DECIMAL.
Within PHP calculate everything using the bcmath library which properly handles fixed position decimals. It's very simple and keeps numbers in strings. Following your example:
$quote = bcmul('1000', '1.5', 2);
// '1500.0'
// Get 2 decimal places for Braintree
$sale = number_format((float)$quote, 2, '.', '');
Upvotes: 2