Wednesday, December 20, 2017

Find a Penny, Pick It Up...

A coworker of mine was working on a TypeScript/JavaScript application that ran in a web browser. The application would display a dollar amount that was about to be charged to a customer's credit card. When the customer acknowledged the amount, the customer would be taken to a page hosted by the payment processor to actually perform the transaction. This seemed to be working correctly, but our QA tester found that certain dollar amounts, like $8.95, would show in our application as $8.95, but would be displayed as $8.94 on the payment processor's page.

The payment processors required monetary amounts to be sent in as cents, rather than dollars. For example, $54.12 would be sent as 5412. The developer had written something similar to the following to do this value conversion:

1
2
const amount: number = 8.95;
const paymentProcessorValue: number = amount * 100;

The problem ended up being caused by the way JavaScript does math. JavaScript uses floating-point arithmetic to do calculations. In this particular case, 8.95 * 100 was not returning the expected 895, but instead was returning 894.9999999999999. The payment processor truncated the value at the decimal point, therefore it interpreted this value as $8.94, not $8.95.

The issue was corrected by rounding the value before sending it on to the payment processor.

1
2
const amount: number = 8.95;
const paymentProcessorValue: number = Math.round(amount * 100);

Example