-1

I allow users to enter prices of products into an inventory, in either NET or Gross. If they enter the price in Gross, the NET is computed for them before being stored and uses the following code:

var vatrate = 12;
IsuppGross = parseInt(suppGross * 100); // makes it an integer

// calc net
var revVR = parseFloat('1.'+vatrate);
Net = ( ( IsuppGross / revVR) / 100 ).toFixed(2);

I struggled to get that working and am not sure if that is where the problem lies.

If I enter '100.00' as a gross figure and my VAT rate is 12%, it returns Net as '112.00', so it seems to be working.

So I enter a product with a Gross price of $100.00 and the net price is computed to be '$89.29' (which I'm assuming to right).

When creating an invoice for 10 of the above items, the bottom of the invoice looks like this:

Net Subtotal $892.90
VAT $107.15
Grand Total $1000.05

What I am expecting is:

Net Subtotal $892.90
VAT $107.10
Grand Total $1000.00

...especially since, when selling just one of the above, results in:

Net Subtotal $89.29
VAT $10.71
Grand Total $100.00

...which expected. It would therefore be reasonable to assume that purchasing 10 of the same items, would cost exactly ten times as much.

Here is the formula I'm using to add the VAT to the Net subtotal:

quantity x net price x 0.12 (10 x 89.29 x 0.12) = 107.148

The above then rounds to 107.15 which when added to the net subtotal is 1000.05.

What formula do I need to arrive at 1000 when I add the VAT back on please?

To Summarize / Clarify This formula... quantity x net price x 0.12 (10 x 89.29 x 0.12)

Gives me 107.148, but what I think I need it to give me is 107.10 instead.

So what javascript function can I used to make that happen (or how do I need to adjust my formula / convert it to code)?

UPDATE @jakub is on the right track I think. I've found an easy way to test it by doing something like:

alert( (892.90 * 0.12).toFixed(2) );  // should equal 107.10

(still equals 107.15)

The above was based on input from Jakub, below. Notice that I'm not multiplying by 10 separately here, because I noticed that we're working at the subtotal level.

Peter White
  • 1,016
  • 2
  • 14
  • 29
  • 1
    This isn't really a programming question as much as it is a math question. Since you're specifically asking for a formula, you might want to try http://math.stackexchange.com. – Andy E Mar 25 '13 at 13:17
  • I did begin to answer my question there, but then since I wanted to include some code for review, I felt that it might be the wrong audience, so transferred to here before sending. I see where you're coming from though. – Peter White Mar 25 '13 at 13:30
  • I'm sorry, but you're still multiplying Quantity and Price with VAT and **THEN** rounding. You have to first round the product of Price and VAT, round it and then multiply by quantity. It has to be: `alert( ( 10 * (89.29 * 0.12).toFixed(2) ).toFixed(2) );` – Jakub Kotrs Mar 25 '13 at 15:53

3 Answers3

2

One way to do that would be to put rounding at a different place

round(quantity * price) != quantity * round(price)

The same goes for VAT, rounding the result is slightly different from rounding VAT from one product and then multiplying by quantity. Also, you know, that quantity has to be an integer, not a float (if not, it is a different case), so multiplying after rounding should never produce more decimal places.

I hope this helps a little bit.

Ok, to respond to your edit:

You have

(quantity * price * VAT).toFixed(2) = (10 * 89.29 * 0.12).toFixed(2) = (107.148).toFixed(2) = 107.15

You should have

quantity * (price * VAT).toFixed(2) = 10 * (89.29 * 0.12).toFixed(2) = 10 * (10.7148).toFixed(2) = 10 * 10.71 = 107.10
Jakub Kotrs
  • 5,823
  • 1
  • 14
  • 30
  • You're quite right, this does seem to be a 'rounding' issue, not a floating-point error, but I still can't get it to work despite introducing `round()` and playing about with it's location. I've updated my question though since we've narrowed it down a bit. – Peter White Mar 25 '13 at 13:58
  • The rounding function in JS is `Math.round` and it doesn't take the 2nd argument, so I tried the following based on your update: `taxvalue = Math.round((subtotal*0.12)*100)/100;` Subtotal was 892.90. The result was still '107.15' (rather than '107.10'). I guess what I did doesn't quite match your formula? – Peter White Mar 25 '13 at 14:59
  • I've edited my answer to be in JS, I was talking generally, not in any any particular language. – Jakub Kotrs Mar 25 '13 at 15:19
  • Thanks. I get it now. It's not what I wanted to hear, since it means building in some extra loops to get the product breakdown as I only have the subtotals at this point, but I'm now 'unstuck'! – Peter White Mar 25 '13 at 16:16
1

I think I'm correct in saying that the legal position is that the VAT amount invoiced must be the correct percentage of the goods & services invoiced, so one should not sum the VAT-inclusive line-item prices.

One system I worked on which showed VAT per line modified the last line's VAT amount to eliminate rounding errors. They will always be there unless you show your prices with 5 decimal places (assuming you have a VAT rate with 3 significant digits).

grahamj42
  • 2,752
  • 3
  • 25
  • 34
  • I kind of see what you're saying, but as I mentioned above, if the system sells one item for $100 how can I explain that if you buy 10 it's $1000.05 to a customer? I've not encountered such a discrepancy in a commercial system, so I think there must be a coding solution that makes do the right thing. – Peter White Mar 25 '13 at 13:55
  • As I've spent most of my working life in the UK, I will answer from a UK perspective, but I think it's similar throughout the EU. If you're dealing with businesses, you set your prices without VAT and add tax at the end. If you're dealing with private individuals, you set your prices VAT-inclusive and back-calculate the VAT from the invoice total. So in your case I would make a global decision whether to store VAT-inclusive or VAT-exclusive prices and perform rounding at the time the price is entered. – grahamj42 Mar 25 '13 at 14:32
  • I understand that. That's pretty much what I'm doing. I'm storing the net price and adding VAT at the bottom of the invoice on to the subtotal. Appreciate your input. – Peter White Mar 25 '13 at 14:36
0

Basically the reason for this issue is that the computer is not able to represent most base 10 real numbers using floating point numbers, since the computer uses base 2.

Check this thread: Why not use Double or Float to represent currency?

So one first step is to always use integers for the currency, in this case measured in cents instead of dollars, I presume.

Community
  • 1
  • 1
Betamos
  • 26,448
  • 9
  • 23
  • 28