Virtuemart Coupon Error with Discount Before Tax
Introduction
Ok, so here you are. You have just finished installing your spanking new copy of Virtuemart 1.1.4 stable into your joomla website. You know you are going to be dealing alot with coupons, so you decide to run your first test. You want to create coupons where the discount is taken out before taxes are calculated. Never fear, Virtuemart has just the thing you need. So you go to the configuration screen and tick the correct box "Subtract payment discount before tax/shipping".
Then you go to the coupon components and create a coupon to give the customers 15% off.
Now its time to test. So you go to the front end and add a product to your shopping cart
So far so good. You are now sitting back in your chair, dreaming about all the pina coladas you are going to have from the massive amount of sales. Virtuemart is so easy to setup, and you are kicking yourself for not thinking about using it sooner. Ehm, ok, back to reality. You enter your coupon code to get your 15% off. And now this is what your shopping cart looks like:
That does not look right? Man, time to snap out of that daydreaming and back to reality. Ok, so the total amount for the product including tax is 243.54. Now you take 15% off that and you get 36.53. So far so good. Now you subtract that from the total and you get 207.01. But the total in the shopping cart is showing 166.92. That is not even close to correct. To make matters worse, the discount was supposed to be taken out of the net price not the gross. You are now realizing you are in over your head, where did you go wrong......
Never fear. Before you close down shop, take a look at the solution below.
Background
One thing to understand is when taking a discount in percentage, the net result is always the same, whether the discount is before tax or after tax. The only thing that changes is the proportion between the tax and product price. Be sure to select the one that fits your business and regulations. Lets take a simple example:
Product: $100
Tax: 10%
Discount of 15%
Product Price w/ Tax | Discount | New Tax | New Product Price | Total | Net Discount | |
---|---|---|---|---|---|---|
Discount before Tax | 100*1.1=110 | 100*.15=15 | (100-15)*.1=8.50 | 100-15=85.00 | 85+8.50=93.50 | 110-93.50=16.50 |
Discount After Tax | 100*1.1=110 | 110*.15=16.50 | 100*.1=10.00 | 110-10-16.50=83.50 | 83.50+10=93.50 | 110-93.50=16.50 |
The Problem
In www/administrator/components/com_virtuemart/html/basket.php
On or around line 208 is this
<?php
if( PSHOP_COUPONS_ENABLE=='1' && @$_SESSION['coupon_redeemed']=="1" && PAYMENT_DISCOUNT_BEFORE=='1') {
$total -= $_SESSION['coupon_discount'];
?>
On or around line 255 is this
<?php
else if( PSHOP_COUPONS_ENABLE=='1' && @$_SESSION['coupon_redeemed']=="1" && PAYMENT_DISCOUNT_BEFORE == '1') {
$discount_after=false;
$total -= $_SESSION['coupon_discount'];
$total -= ($_SESSION['coupon_discount'] * $my_taxrate);
?>
If you take a close look, you will see that the coupon_discount is being subtracted from the total in two different places. This was probably an oversite by Virtuemart. The second problem is this line:
<?php
$total -= ($_SESSION['coupon_discount'] * $my_taxrate);
?>
Since the discount is before tax, Virtuemart is trying to compensate for that by subtracting it from the total. The problem is it does not need to do that. As proven above, the total and the total discount is going to be the same in either case.
In www/administrator/components/com_virtuemart/classes/ps_checkout.php on or around line 1312
<?php
$d['order_total'] = $totals['order_total'] = $tmp_subtotal
+ $totals['order_tax']
+ $totals['order_shipping']
+ $totals['order_shipping_tax']
- $totals['coupon_discount']
- $totals['payment_discount'];
?>
This returns the order total by adding and subtracting the necessary fields. Within this equation all the totals are broken down to show their value and tax separately, except for the coupon_discount. To get the correct value, the coupon_discount needs to be recalculated and not reflect the tax.
The Solution
Simply comment out the lines of extra code
In www/administrator/components/com_virtuemart/html/basket.php
On or around line 208 is this
<?php
if( PSHOP_COUPONS_ENABLE=='1' && @$_SESSION['coupon_redeemed']=="1" && PAYMENT_DISCOUNT_BEFORE=='1') {
//$total -= $_SESSION['coupon_discount'];
?>
On or around line 255 is this
<?php
else if( PSHOP_COUPONS_ENABLE=='1' && @$_SESSION['coupon_redeemed']=="1" && PAYMENT_DISCOUNT_BEFORE == '1') {
$discount_after=false;
$total -= $_SESSION['coupon_discount'];
//$total -= ($_SESSION['coupon_discount'] * $my_taxrate);
?>
In www/administrator/components/com_virtuemart/classes/ps_checkout.php on or around line 1313, replace the equation with this:
<?php
$tmp_coupon_discount = $totals['coupon_discount'];
if(!empty($totals['coupon_discount']) && PAYMENT_DISCOUNT_BEFORE == '1') {
// coupon includes tax, we need to remove tax from coupon
$tax_before_discount = $d['order_subtotal_withtax'] - $totals['order_taxable'];
$tmp_coupon_discount = ($d['order_subtotal_withtax']-$tax_before_discount)/$d['order_subtotal_withtax']*$totals['coupon_discount'];
}
$d['order_total'] = $totals['order_total'] = $tmp_subtotal
+ $totals['order_tax']
+ $totals['order_shipping']
+ $totals['order_shipping_tax']
- $tmp_coupon_discount
- $totals['payment_discount'];
?>
[Edit] If you are using paypal, the total passed into paypal is incorrect. To fix, you should log into the admin panel, go to store->"List Payment Methods"->Paypal. Click on the "Configuration" tab and within the "Payment Extra info" section replace this:
<?php
"amount" => round( $db->f("order_subtotal")+$tax_total-$discount_total, 2),
?>
with this:
<?php
//"amount" => round( $db->f("order_subtotal")+$tax_total-$discount_total, 2),
"amount" => round( $db->f("order_total")-$db->f("order_shipping"), 2),
?>
With this change, we are simply telling paypal that the product cost is the total cost minus the shipping charge.
Now test away, everything should be back to normal.
If you are lazy, like me, or not good with editing code, you can download the source : http://awocoupon.googlecode.com/files/virtuemart-coupon-error-fix-1.0.4.zip
Comments (58)
Thanks for the information about the wrong calculation.
I followed your guidelines and indeed mij basket gives the right calculation.
But....... unfortunatly the conformation email after ordering still gives the wrong total amount and also the payment processor ( in my case Ideal ) uses the wrong total amount.
Do you have any idea where else i have to change some templates in order to get this wright?
with regards,
Blaauw
Thanks for reporting this. Yes, after some testing I was able to reproduce the problem. Again, it is a calculation error within virtuemart. I have updated the article to reflect the findings. You will need to make changes to the ps_checkout.php file, which inserts the order into the database. Once that is fixed, the payment modules and the email confirmation should work fine, since they are pulling directly from the database.
So far as i can see your solution works great.
Blaauw
I replaced ps_checkout.php with your fix, and it works within Virtuemart but I'm still getting the wrong total for the amount passed on to the payment processor (Paypal). I got this with Virtuemart's own coupon system, then installed awocoupon 1.0.1 but still get the problem.
For example:
This is correct during all the checkout process: [tax is 17.5%]:
Subtotal $58
Coupon discount [15%] -8.70
Shipping $3.94
Total $53.24
Tax $7.93
but the data sent to Paypal is this:
Order total: $48.59
Shipping $3.35
Total: $51.94
What's going on here? And any ideas how can I fix it?! The amounts passed on to Paypal are correct if no discount applied.
Many thanks!
Simon
<?php
"amount" => round( $db->f("order_subtotal")+$tax_total-$discount_total, 2),
?>
with this
<?php
//"amount" => round( $db->f("order_subtotal")+$tax_total-$discount_total, 2),
"amount" => round( $db->f("order_total")-$db->f("order_shipping"), 2),
?>
With this change, we are simply telling paypal that the product cost is the total cost minus the shipping charge. It also seems that the shipping tax is intentionally put into the product total ($tax_total). Not sure why, but im sure you can alter the code above to behave as you like.
Mysteriously, if a coupon code is entered, everything displays correctly on checkout within the site, but the amount sent on to Paypal (and the total displayed on the confirmation email) has an extra 14.9% of the discount amount taken off in addition. I think it's this:
When a coupon is used, the amount $db->f("order_total") suddenly seems to be based on the order total without tax. The maths are confusing, but if you take 17.5% VAT off 100 (100/1.175), you get 85.1. If you then apply the discount, that's exactly what is shown.
I get perfect amounts sent to Paypal by entering: "amount" => round( $db->f("order_total")-(($db->f("order_shipping")+$db->f("order_shipping_tax")-($db->f("coupon_discount")*.149))), 2)
Crazy, but it gets the correct results. But the confirmation email's total is still wrong. Any idea where the total for that can be fiddled? Or better still a way of getting it to calculate the right amount to begin with!
Product price including tax: 52.09
Coupon discount (25%): 13.02
Shipping and Handling: 5.29
-----------------------------------------------
Total Taxes (8.25%): 3.38
===============================
Total Payment: 44.36
From my calc, this is correct. Your solution gives me 45.90 in paypal.
So there's definitely a gremlin in there somewhere! And it doesn't seem to be on that config. page.
I've given up fiddling around and am hiring someone to take a look.
My solution doesn't work in the end at all in fact, because we also have a 'trade' user group who's prices exclude tax, then tax is added on at the end, so different again. So I've scrubbed that!
But your fixes (basket.php/ps_checkout.php) sorted it within the site. It's just the data sent on to Paypal and in the email that's wrong (when a discount is applied before tax).
In other words "order_total" contains a totally wrong figure when a discount has been applied. Because for Paypal that figure needs to include everything, as you say. And it IS wrong on the email too!
I guess when there's a bug and someone applies a fix in slightly the wrong place, there will be occasions where it goes wrong. I'm surprised that VM developers don't sort such 'known' isuues out and release fixes....!
Many thanks for your help and concern!
Simon
Now I've done that (and removed my bad workaround)....... I get very nearly the correct amounts in Paypal and in the email confirmation - but it's always 0.01 or 0.02 out from the total that was (correctly) shown within VM. Any idea? Rounding errors?
Anyway, getting closer!
Many thanks and sorry for not reading the instructions properly!
I tried but could not replicate the 1, 2 penny problem. could you give exact details of a checkout that produces this? product price, tax, coupon amount, etc?
https://awodev.com/blog/virtuemart-coupon-error-discount-before-tax#comment-167
Thanks for reporting this. Yes, after some testing I was able to reproduce the problem. Again, it is a calculation error within virtuemart. I have updated the article to reflect the findings. You will need to make changes to the ps_checkout.php file, which inserts the order into the database. Once that is fixed, the payment modules and the email confirmation should work fine, since they are pulling directly from the database."
Can you please tell me what I have to change in the ps_checkout.php file ( is it the same file I have altered before?) cause I have the same problem Blaauw has but I am not sure what to do now.
I want to comliment you with your article about this. Without any knowledge about php you have fix this error 'with' me so far!!
Thanks in advance
Sabine
glad i could help.
I have done all the steps in the blogg and during the checkout it is all fine. A stated earlier I have other amounts in the nitifcation email now.
When i order two products
A 20 euro
B 50 euro
Total 70 euro
Coupon 20 euro
Checkout total 50 euro
Email total 49,99 euro
I do not know what to do at all but it can't stay like this. Can you help me out?
Thanks in advance
Sabine
The vat is 19%. Sorry I did not mention.
Sabine
So to get the correct solution, in ps_checkout.php change this:
<?php
$tmp_coupon_discount = round(($d['order_subtotal_withtax']-$tax_before_discount)/$d['order_subtotal_withtax']*$totals['coupon_discount'],2);
?>
to this:
<?php
$tmp_coupon_discount = ($d['order_subtotal_withtax']-$tax_before_discount)/$d['order_subtotal_withtax']*$totals['coupon_discount'];
?>
If this does not solve it, Im at a loss.
I've also updated the blog with the solution.
I really appreciate your help cause for me this is abracadabra! I did make the change you suggest and it solves the fault in the example.
In another fault it didn't work and that is strange I think.
The example is:
Product A 30.00 euro
Coupon 21.00 euro
Total 9.01 euro
Tax is still 19%
I do not understand we (you!) solved it for one and the other is stil fault. Could it really be something else?
Thank you so much for your help so far; if you can and will could you take a look one time?
Thanks in advance
Sabine
Thank you for your explanations although I do not really understand virtuemart's calculations
With your solution, in ps_checkout.php, if a voucher can cover the order amount, you end up with a tax value of 0 which generates an error:
Tax_before_discount $ = $ totals ['order_tax'] / ....
-> Warning: Division by zero
P.
You can delete the test message
In continuation of what I noticed:
an order of 197.92 w/ VAT
a discount of 197.92
shiiping : 26.9 (without VAT)
In the backoffice,inside the order :
Circular Saw: 197.92
Total without tax: 180.34
Discount: 197.92
Tax: 0
shipping: 26.90
Delivery VAT: 0
Total with tax: 9.32
whereas I should pay the shipping 26.90
9.32 = 180.34 - 197.92 + 9.26
instead of
197.92 - 197.92 + 26.90
W.
This:
<?php
$tax_before_discount = $totals['order_tax'] / ( ($d['order_subtotal_withtax']-$totals['coupon_discount'])/$d['order_subtotal_withtax']);
?>
would work in most cases but not all, as in such case of the coupon value is the same as the gross price.
To get it to work replace that line with this:
<?php
$tax_before_discount = $d['order_subtotal_withtax'] - $totals['order_taxable'];
?>
I have updated the blog with the correction.
Is there a way to display the same value as $tmp_coupon_discount on file com_virtuemart/themes/default/templates/basket/basket_b2b.html.php so the coupon discount will display on the basket?
Within
www/components/com_virtuemart/themes/default/templates/basket/basket_b2{b,c}.html.php
somewhere around the top, after
<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
?>
you will need to add this:
<?php
$tax_before_discount = $vars['total'] - $ps_checkout->_subtotal;
$coupon_display = round(($vars['total']-$tax_before_discount)/$vars['total']*$_SESSION['coupon_discount'],2);
?>
in www/components/com_virtuemart/themes/default/templates/basket/ro_basket_b2{b,c}.html.php, around the same place, add this:
<?php
$tax_before_discount = $vars['order_subtotal_withtax'] - $ps_checkout->_subtotal;
$coupon_display = round(($vars['order_subtotal_withtax']-$tax_before_discount)/$vars['order_subtotal_withtax']*$_SESSION['coupon_discount'],2);
?>
that should display the temp coupon discount.
After apply your last code update I got this error:
Warning: Division by zero in /hsphere/local/home/folch/dev.folch.com/components/com_virtuemart/themes/default/templates/basket/basket_b2c.html.php on line 22
It happens after apply the coupon...
Within
www/components/com_virtuemart/themes/default/templates/basket/basket_b2{b,c}.html.php
somewhere around the top, after
<?php
if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
?>
you will need to add this:
<?php
$tax_before_discount = $vars['total'] - $ps_checkout->_subtotal;
$coupon_display = empty($vars['total'])
? $_SESSION['coupon_discount']
: round(($vars['total']-$tax_before_discount)/$vars['total']*$_SESSION['coupon_discount'],2);
?>
in www/components/com_virtuemart/themes/default/templates/basket/ro_basket_b2{b,c}.html.php, around the same place, add this:
<?php
$tax_before_discount = $vars['order_subtotal_withtax'] - $ps_checkout->_subtotal;
$coupon_display = empty($vars['order_subtotal_withtax'])
? $_SESSION['coupon_discount']
: round(($vars['order_subtotal_withtax']-$tax_before_discount)/$vars['order_subtotal_withtax']*$_SESSION['coupon_discount'],2);
?>
Thanks and good night.. or morning.. 04.38 AM here !
NOW I can take vaccation!
THANKS!!!
http://dev.virtuemart.net/redmine/issues/159
Not sure if there are any more dealing with this issue
... Found the bug, its been closed: http://dev.virtuemart.net/redmine/issues/112
https://awodev.com/forum/awocoupon-virtuemart/help-section/coupon-does-not-work-correclty
(BTW, my totals passed to PayPal seem to be okay without having to update my PayPal payment method configuration.)
Do you know wether this problem still exists in VM 1.1.5?
https://awodev.com/forum/awocoupon-virtuemart/help-section/coupon-does-not-work-correclty
I had this problem in VM 1.1.4.
works now excellent and in combination with payment discounts too.
Thank you
Thanks a lot for this! It fixed the problem that the wrong Total was shown on the checkout. However I still got the wrong Total in the confirmation email and the order receipt. I spent some hours trying different stuff and finally I realized that in your code in the field below where you write "In www/administrator/components/com_virtuemart/classes/ps_checkout.php on or around line 1313, replace the equation with this:" then before the if-statement you create a variable "$tmp_coupon_discount" and you use this variable in the if-statement. Then I missed that you exchanged "- $totals['coupon_discount']" for "- $tmp_coupon_discount" when you calculate order_total in the last step. So not realizing that I instead tried my self to store the value of "$tmp_coupon_discount" in "$totals['coupon_discount']" as a last step in the if-statement, which works perfectly. But of course, that is exactly the same as you do =) Too bad I didn't realize that before I spent hours to make it work! Again, thanks for your help with this coupon error! Incredible that Virtuemart haven't fixed this!
So this is how my code looks now:
if(!empty($totals['coupon_discount']) && PAYMENT_DISCOUNT_BEFORE == '1') {
// coupon includes tax, we need to remove tax from coupon
$tax_before_discount = $d['order_subtotal_withtax'] - $totals['order_taxable'];
$tmp_coupon_discount = ($d['order_subtotal_withtax']-$tax_before_discount)/$d['order_subtotal_withtax']*$totals['coupon_discount'];
$totals['coupon_discount'] = $tmp_coupon_discount;
}
With this everyting works just fine.
many thanks
Greets from Holland
thanks for your great solution.
Is this problem meanwhile solved in VM 1.1.8 ?
I have a problem with the discount given for a special payment method.
I would like to give 5 % discount for p.e. PayPal and a discount of 5 % for a special coupon.
In summary the product should be discounted with 10 % of the regular price with tax.
I tried some different settings but the total price never becomes 90 % of the regular price. All products are shipping free.
Any ideas why the discount on payment methods is calculated wrong?
Thanks in advance.
Kai
https://awodev.com/forum/awocoupon-virtuemart/help-section/calculation-error-virtuemart
Joomla 1.5.25
VirtueMart 1.1.19
AwoCoupon for VirtueMart 1.0.10
Subtract payment discount... is checked.
Coupon is $5 total
Product is $17.99, listed in cart at $19.34 with a state tax rate of .075. This math works. $17.99 * .075 = 1.35 + 17.99 = 19.34
Shipping is $2.75.
When I add in the $5 discount, I get a new tax total of $1.00 so my receipt looks like this:
SubTotal : $19.34
Coupon Discount : -$5.00
Shipping : $2.75
Tax Total: $1.00
Total: $16.74
The first three numbers make sense. The tax total and the total do NOT make sense no matter how I do the math. Again, I inserted the code from your solutions (perhaps incorrectly), but nothing is working. Help please.
What are the totals before applying the discount? Is the shipping taxed?
The tax and total seem to be off by the same amount, 3 pennies.
(17.99-5)*.075 = 0.97425
12.99+0.97425+2.75 = 16.71425
These should be the correct totals, they are both off by 0.02575. Might be a rounding issue somewhere.
17.99 * .075 = 19.34
19.34 + 2.75 = 22.09
So, I get what you are saying above and your math is great, but that doesn't at all equal or come close to what I'm seeing when I apply the discount on my system.
I am seeing tax at $1.00 which is off by .02575, but my total is off by .37575 at 17.09, not 16.71425. So my problem is that my customers are seeing this error (if they bother to do the math) and my accountant is having to recalculate the tax on every purchase that's made with a coupon because the receipt is incorrect. Again, if you look at the numbers on the receipt they do not add up. It appears, based on your calculations above that we are charging them too much on tax and somehow also on the total to the tune of .40 or so.
Can we do better?
Total: $16.74
What is this referring to if not the overall total? Or is it that your total changes from screen to screen?
My screen displays it this way: Price $19.34 Quantity 1 Sub-Total $19.34 (this is $17.99 + $1.35 in tax)
Then...
Sub-total: $19.34
Coupon Discount: - $5.00
Shipping & Handling: $2.75
Total: $17.09
Tax Total: $1.00
I am not certain how/why I put $16.74, but that isn't what's there, now. :(
19.34-5+2.75 = 17.09
Are you sure you still have discount before tax checked? Is 17.09 the total you see on ALL screens through checkout? Need to review your basket.php code.
Please make a post in the forum to further pursue the issue.
https://awodev.com/forum/awocoupon-virtuemart/help-section
Thanks,
Steve