I am having the darndest time trying to auto calculate taxes in php. This is what I have so far :
<?php
// Formats a number so it appears as such : 55.12, instead of 55.12354
function invoiceNumFormat($number){
return number_format($number, 2);
}
$tax_rate = 7.5; //Sets Tax Rate
// Retrieves Subtotal, utilitzes NumFormat function to round to hundredths place
$invoice_subtotal = isset($invoice['invoice_subtotal']) ? invoiceNumFormat( $invoice['invoice_subtotal'] ): 0;
//Multiplies subtotal against tax rate to retrieve $tax_amount
$tax_amount = invoiceNumFormat( $invoice_subtotal*$tax_rate/100 );
// Shows Grand Total(subtotal + tax)
$invoice_totalled = $invoice_subtotal + $tax_amount;
//Displays Totals
<span>'.$invoice_subtotal.'</span>
<span>'.$tax_amount.'</span>
<span>'.$invoice_totalled.'</span>
?>
I have an output of a subtotal showing "3116.88" which is correct, but the tax showing for that amount is ".32" and the grand total is "3.23". Can anyone tell where I have gone wrong?
yup got it!
$invoice_subtotal = isset($invoice['invoice_subtotal']) ? invoiceNumFormat( $invoice['invoice_subtotal'] ): 0;
the problem is in the above line.
what happens here is, you utilized the function invoiceNumFormat when the subtotal value is set, when you pass 3116.88 then it returns 3,116.88 which is not an integer.
so change the line to
$invoice_subtotal = isset($invoice['invoice_subtotal']) ? $invoice['invoice_subtotal'] : 0;
You first format numbers, then calculate $tax_amount and $invoice_totalled. But by this way you perform operations on string values, so you can obtain undesired values.
You have to perform all math operations with float values and to format variables only at the output.
$invoice_subtotal = $invoice['invoice_subtotal'];
$tax_amount = $invoice_subtotal * $tax_rate / 100;
$invoice_totalled = $invoice_subtotal + $tax_amount;
echo '<span>'.invoiceNumFormat( $invoice_subtotal ).'</span>
<span>'.invoiceNumFormat( $tax_amount ).'</span>
<span>'.invoiceNumFormat( $invoice_totalled ).'</span>
';
Related
I have a shop where the client enters the product price with the tax in his country. When i save it i need to remove the tax and keep only the base.
When i calculate the tax back for the clients from the same country in some cases the total price will be different with 0.01 , 0.03 then the original price.
I tried to calculate with 2 to 4 digits but it never works on all cases.
Ex: price with tax = 157, tax is 7.7% => base = 145.78 and tax amount 11.22
When i calculate the tax to the previous price base i get this:
Base: 145.78 , tax is 7.7% => 11.23 = price is 157.01
Php code i use:
$baseprice = round($fullprice / (1+($taxperc/100)),2);
On the frontend:
$tax = round($baseprice * ( $taxperc / 100 ),2);
$total = $tax + $baseprice;
Anyone have a suggestion about how to fix this ?
Thanks!
Update: after some research I found a solution is to use round with PHP_ROUND_HALF_EVEN
Update2: first solution doesnt work. 1-9 works fine, 10 -tax + tax =10.01
Today's solution would be to work on the back with full number of digits ( for base price, tax and total ) and only when display for user to round it. :)
Seems ( not 100% sure yet, i need to test more ) a solution is to use the banker's rounding PHP_ROUND_HALF_EVEN
$baseprice = round($fullprice / (1+($taxperc/100)),2 , PHP_ROUND_HALF_EVEN);
$tax = round($baseprice * ( $taxperc / 100 ),2 , PHP_ROUND_HALF_EVEN);
$total = $tax + $baseprice;
Not sure if I'm being stupid here. Probably something obvious but when you've been staring at the same issue for hours on end it starts to drive you crazy.
I'm doing a few calcuations using PHP, all fairly straight forward.
I have a table called sales, say:
total, costs
424.53, 125
853.91, 125
To get the data I need...
gross = total - cost
vat = gross - ( gross / 1.2 )
profit = gross - vat
I need to generate a report, so for each row in the sales database I need to loop over and run the above calculations to get the data I need.
If I add the sum of total and the sum of costs, and then work out the gross, vat and profit above, and round vat and profit to 2 decimal plates the values are as expected.
The problem I'm having is where I'm looping over each row and calculating gross, vat and profit. If I don't round vat and profit on each row, but round the final totals, they match the values where I add sum(total) and sum(costs).
But then in the report I generate, if I don't round vat and profit then they don't show to two decimal places, which I need.
Actual code is below, pretty sure it's more of a logic issue than code.
$sum = 0; // Test variable
foreach( .. as ... )
{
// Assigning $total and $cost
$gross = $total - $cost;
$data['profit'] = $gross;
// If I round this VAT so vat shows to two decimal points, $sum becomes off by some pence.
// If I don't round it but then round $sum after the loop, it matches the echo statement value which is the correct amount
$vat = $this->vat( $gross );
$data['vat'] = $vat;
$profit = $gross - $vat;
$data['net_profit'] = $profit;
$sum += $profit;
$array[] = $data;
}
echo "131547.82<br><br>";
echo $sum;
die;
It's an accuracy problem caused by using floats.
When you do calculations with pure PHP you need to be careful.
You may run into glitches, when comparing two floats.
I would suggest to use some helper function or a currency / money object in order to work with them. It might be better to use a PHP Extension for math stuff, like the PHP Extensions BCMath, which has for instance the function bcadd(). Anyway, here are some helpers, which you might use in your calculation loop.
/**
* turn "string float" into "rounded float with precision 2"
* (string) 123,19124124 = (float) 123.19
*
* #param type $string
*/
function formatNumber($string, $precision = 2)
{
return round((float) str_replace(',', '.', $string), $precision);
}
There is also sprintf: echo sprintf("%.2f", $a);.
These two are based on PHP's NumberFormatter from the Intl Extension.
// 123,19 EUR = 123.19
function parseNumber($string_number)
{
$fmt = numfmt_create('de_DE', \NumberFormatter::DECIMAL);
return numfmt_parse($fmt, $string_number);
}
// 123.19 = 123,19 EUR
function numberFormat($value)
{
$f = \NumberFormatter::create("de_DE", \NumberFormatter::CURRENCY);
return $f->formatCurrency($value, 'EUR');
}
For comparing two floats:
/**
* Do not check, that the numbers are exactly the same,
* but check that their difference is very small!
* A really small rounding error margin (epsilon) is expected.
* It's an equals check within defined precision.
*/
function compareFloats($a, $b)
{
return (abs(($a - $b) / $b) < 0.000001) ? true : false;
}
Im trying to make a calculation with the following values:
Product cost (without VAT) = 12,40 ($product)
The VAT percentage = 21%, what I will store in the database as 0,21 ($vat_perc)
The VAT is 2,604 ($vat)
edit: The VAT is per product
When I try to get the total then I get 15,00 ($total)
What I did is the following:
$total = $product + $vat
This will echo 15.004
Then I use the number_format:
echo(number_format($total,2,',','.'));
This will print 15.00
But then I want to multiply the product with 2
So that will give the following calculation:
$total = $product * 2 + $vat
Then again I use the format:
echo(number_format($total,2,',','.'));
Then the total = 30,01
I tried serveral things like ROUND en INT, but with no succes.
What am I doing wrong in this? In know that the VAT is the evil one here but I have no idea how to fix this.
$tax = round( ($price / 100) * 3.8, 2);
tax is rounded price divided by the 100 to make a clear percentage. Multiplied by the wanted stack
then you do the addition to or from your price table.
Well good to have you on the phone - maybe we can solve this faster by phone. Thank god for phones!
Cheers mate!
Here are some examples of how the numbers are rounded with PHP functions.
$product = 12.40;
$vat = 2.644;
$total = ( $product + $vat ) * 2;
var_dump( $total ); // float(30.088)
var_dump( number_format($total,2,',','.') ); // string(5) "30,09", rounded
var_dump( round( $total, 2 ) ); // float(30.09), rounded
var_dump( sprintf('%0.2f', $total ) ); // string(5) "30.09", rounded
var_dump( floor( $total * 100 ) / 100 ); // float(30.08), not rounded
All three founctions ( number_format, round, sprintf ) will round the result, to avoid the rounding and discard the decimal part after two decimal points you can use the last example.
Your initial total is 15.004 so when you call number_format that gets rounded down to 15.00. Now when you multiply by 2 your total is 15.008 which number_format will round up to 15.01. The issue isn't with the addition it is with the multiplication by 2. number_format rounds to the nearest place which for your case would be 30.01.
If you want the number to be rounded down all the time use floor, like so:
$total = floor(($product * 200)) / 100 + $vat;
echo(number_format($total,2,',','.'));
I'm working with a few financial formulas that involve float's and rates in percentages, and i'm having a little bit of problems trying to represent these values in my PHP code. Should i use BC Math? Should i divide all my percentages by 100? How would you represent the following formulas in PHP?
e.g: Amount has a tax amount of 8% and an interest rate of 1% a day. Given i want to borrow X amount and pay in 15 days, divided in 3 installments, how much per installment and total payback?
totalTax = amount * 0.08
totalAmount = (amount + totalTax)
interest = totalAmount * 0.01 * 15
perInstallment = totalAmount + totalInterest / 3
The crucial PHP function is number_format(). I'm also casting the type to (float) inside my custom function. As always, test this code. I'm curious if you find any edge cases where this math doesn't sync up with your financial calculations. It passed my tests...
function formatCurrency($input){
$result = number_format((float)$input, 2, '.', ',');
return $result;
}
$amount = 6458.56;
$totalTax = $amount * 0.08;
$totalAmount = $amount + $totalTax;
$interest = $totalAmount * 0.01 * 15;
$perInstallment = ($totalAmount + $interest) / 3;
echo 'Principal = $'.formatCurrency($amount).'<br/>';
echo 'Total Tax = $'.formatCurrency($totalTax).'<br/>';
echo 'Total Amount = $'.formatCurrency($totalAmount).'<br/>';
echo 'Total Interest = $'.formatCurrency($interest).'<br/>';
echo 'Each Installment = $'.formatCurrency($perInstallment).'<br/>';
Attention with your financial operations: 15 days with 1% a day
is not 15% but 16.1 %. Better use pow() function instead of multiply operator.
In PHP (run in command line, for example):
<?
$amount = 1000.0 ;
$tax = 1.08 ; // 8%
$interestPerDay = 1.01 ; // 1%/day
$days = 15 ;
$totalAmount = ($amount * $tax);
$totalAmountWithInterest = $totalAmount * pow($interestPerDay, $days) ;
$perInstallment = $totalAmountWithInterest / 3;
printf("Initial amout: %.2f\n", $amount);
printf("Amount tax inc.: %.2f\n", $totalAmount);
printf("Total amount: %.2f\n", $totalAmountWithInterest);
printf("Total interest: %.2f\n", $totalAmountWithInterest - $amount);
printf("Per installment: %.2f\n", $perInstallment );
Gives:
Initial amout: 1000.00
Amount tax inc.: 1080.00
Total amount: 1253.85
Total interest: 253.85
Per installment: 417.95
According to #larsAnders, it now needs currency conversion.
i have a database with the current tax value (it is given in percentages to add like 41, 51 etc lets say it is 41 $tax = 41) The tax comes from the database the price is a post variable.
What i want to do is calcutate the new price when the tax is added.
Currently i have.
$price = 120;
$tax = 41;
$total = (($price *100 + $price * $percentage)/100);
Is there any way to make it easyer? like:
$total = $price * 1.$tax
i know the last one wont work but its just what i had in mind.
What is the best solution?
You can calculate the percentage when querying database or go for
$total = $price * (1 + $tax/100);