-
1 Attachment(s)
Discount coupon value
On ZC v2.0.0-rc2, discount coupons are displayed /calculated wrong values in checkout pages.
There is a unique tax class with rate of 10%.
There are two items in cart, one at $48.34 and the other at $35.00 gross price.
Flat rate shipping ($5) is used as shipping method and is set to same tax class as items (10%).
'ot_coupon' settings are default.
Coupon value is wrong when displaying prices with tax (orange color), which makes although tax and total wrong. But tax and total calculations appear to be good.
In table below, 'ZC' column is what is displayed in ZC v2.0.0-rc2, 'Good' column is what I think it should be and just for information and to identify lost penny, I included a 'no rounding' column. There is actually a penny loss in tax calculation when displaying prices with tax.
Attachment 20529
My understanding of discount coupons is that the discount should be applied to final total ($97.17 including tax) to get the new total and that tax should be re-calculate to fit this new total.
-
Re: Discount coupon value
I forgot to write it, but discount coupon is fixed at $8.
Then, if you look at total when displaying with no tax ($89.17) for what is considered good, it should be $89.18 so that numbers in the column above add correctly. In Excel sheet calculation for coupon value and tax are done without rounding which gives a total of $89.174 rounded at the end to $89.17.
Which result should be displayed in ZC, I am not sure. I would probably go for the mathematically more precise one of $89.17. It then equals the total when displaying tax.
To come back to coupons calculation, I will try to locate code that gives this weird 8.73 number in ot_coupon.php file.
-
Re: Discount coupon value
I got it fixed.
There were 3 problems:
1- Getting rid of all zen_round function calls fixed or at list minimized penny loss problem
2- Code to display coupon value was adding the tax difference when displaying prices with tax and doing nothing when displaying prices without tax. It should be the opposite, just display coupon value when prices with tax are displayed and remove tax difference when prices without tax are displayed.
Lines 597 and 598:
PHP Code:
if (DISPLAY_PRICE_WITH_TAX == 'true' && $coupon_details['coupon_type'] == 'F') {
$od_amount['total'] += $od_amount['tax'];
are replaced with this:
PHP Code:
if (DISPLAY_PRICE_WITH_TAX == 'false' && $coupon_details['coupon_type'] == 'F') {
$od_amount['total'] -= $od_amount['tax'];
3- Tax calculation after discount uses a ratio between discount and total of taxable products. It worked ok when displaying prices with tax, but when displaying prices without tax, it was using total without tax, which is wrong. It should always be total including taxes.
To fix this, line 50:
PHP Code:
$orderAmountTotal = (string)$orderTotalDetails['orderTotal']; // coupon is applied against value of only qualifying/restricted products in cart
was replaced by this:
PHP Code:
$orderAmountTotal = (DISPLAY_PRICE_WITH_TAX == 'true') ? (string)$orderTotalDetails['orderTotal'] : (string)($orderTotalDetails['orderTotal'] + $orderTotalDetails['orderTax']); // coupon is applied against value of only qualifying/restricted products in cart
Now everything looks good, but some testing is still needed with other settings.
-
2 Attachment(s)
Re: Discount coupon value
-
Re: Discount coupon value
For Discount coupon by percentage, a modification was necessary too.
Line 545 was changed from:
PHP Code:
$od_amount['total'] = zen_round($orderAmountTotal * ($coupon_details['coupon_amount'] / 100), $currencyDecimalPlaces);
To this:
PHP Code:
$od_amount['total'] = (DISPLAY_PRICE_WITH_TAX == 'true') ? $orderAmountTotal * ($coupon_details['coupon_amount'] / 100) : ($orderTotalDetails['orderTotal'] + $orderTotalDetails['orderTax'] - $orderTotalDetails['shippingTax']) * ($coupon_details['coupon_amount'] / 100);
And lines 597-598 from:
PHP Code:
if (DISPLAY_PRICE_WITH_TAX == 'true' && $coupon_details['coupon_type'] == 'F') {
$od_amount['total'] += $od_amount['tax'];
To this:
PHP Code:
if (DISPLAY_PRICE_WITH_TAX == 'false' && ($coupon_details['coupon_type'] == 'F' || $coupon_details['coupon_type'] == 'P')) {
$od_amount['total'] -= $od_amount['tax'];
-
Re: Discount coupon value
Thanks for this, @pilou2! In going through the other rounding errors, I had a feeling that these calculation issues would arise in ot_coupon as well.
Since that's going to be a fairly major change to that module, I'm suggesting that we defer these corrections to Zen Cart 2.0.1 so that we can get some testing time in on that and all the other rounding-related changes.
-
Re: Discount coupon value
For tracking purposes, I've opened this GitHub issue: https://github.com/zencart/zencart/issues/6339
-
Re: Discount coupon value
Quote:
Originally Posted by
lat9
Thanks for this, @pilou2! In going through the other rounding errors, I had a feeling that these calculation issues would arise in ot_coupon as well.
Since that's going to be a fairly major change to that module, I'm suggesting that we defer these corrections to Zen Cart 2.0.1 so that we can get some testing time in on that and all the other rounding-related changes.
Yes, we need time... Although I have made good progresses. Different discount options are now all working: fixed, %, free shipping and combination with tax displayed or not.
I need to put this code on GitHub so you can easily look at it.
-
Re: Discount coupon value
Quote:
Originally Posted by
pilou2
Yes, we need time... Although I have made good progresses. Different discount options are now all working: fixed, %, free shipping and combination with tax displayed or not.
I need to put this code on GitHub so you can easily look at it.
Sounds great, I/we truly appreciate your help on this.
-
Re: Discount coupon value
I set a new branch on GitHub:
https://www.zen-cart.com/showthread....t-coupon-value
I am not sure how to give you right to comment, modify it...
-
Re: Discount coupon value
I updated ot_coupon.php file. Calculations for both 'Discount coupon' and 'Credit note' are supported for different type of coupons.
'Discount coupon' are discounts applied on customer order, which mean they are calculated on net prices.
'Credit note' are generally used for refunds and are calculated on products or order gross price.
'Penny loss' problem appeared but was solved by applying a rounding on coupon value just before it is included in order total.
There are still lots of testing/fixing with discount per item option, multiple tax class items in cart, coupon validation in general...
-
Re: Discount coupon value
Quote:
Originally Posted by
pilou2
I updated ot_coupon.php file. Calculations for both 'Discount coupon' and 'Credit note' are supported for different type of coupons.
'Discount coupon' are discounts applied on customer order, which mean they are calculated on net prices.
'Credit note' are generally used for refunds and are calculated on products or order gross price.
'Penny loss' problem appeared but was solved by applying a rounding on coupon value just before it is included in order total.
There are still lots of testing/fixing with discount per item option, multiple tax class items in cart, coupon validation in general...
Thanks, @pilou2. I'll check it out early next week.
-
Re: Discount coupon value
Quote:
Originally Posted by
lat9
Thanks, @pilou2. I'll check it out early next week.
Wait until next update, I realized there were some mistakes. I did not upload the right version and anyway, now that I am testing with multiple tax rates, I need to rewrite part of the code.
-
Re: Discount coupon value
Last update uploaded to GitHub.
Results look very good. ;)
Discount coupons should be ok with all coupons options.
Credit notes (refund) too with all usable options. When using credit notes, setting in admin for ot_coupon are important. Some settings should not be used, like setting tax class to 'none'. Always choose a tax class, or total tax won't be right.
I did some testing with products in cart using two different tax classes and all numbers added well, although calculation to check numbers can get pretty complicated.
-
Re: Discount coupon value
Well... I did all my testing, modifications using a shipping module with tax class set and when I removed this tax class, problems appeared.
I have to rethink everything as I made two assumptions that were wrong:
I thought option 'include shipping' and 'include tax' were here just to choose the limit for discount, which was true for fixed discount, but I realized that it modified how percentage discount are calculated.
And most important, I thought the actual calculation for tax was good... It is if you use free shipping or shipping has a tax class defined, but when tax class is not defined (default in all shipping modules), shipping tax is missing from final tax. Whatever you display prices with or without tax, shipping has always the same value.
I checked and as far as I know, shipping is always taxable. Basic rule for sale tax calculation is:
Taxable amount = Sales - discount + charges
Sales include goods and service provided.
Discount includes sale discount, refunds, non-taxable items...
Charges are shipping fees, handling fees and any other indirect cost incurred to provide goods or services.
Before going further with discount module, this needs to be fixed.
In 'ot_coupon.php', the variable
PHP Code:
$order->info['shipping_tax']
is 0 when no tax class has been defined. In this case, it should be populated by calculating tax (using shop's tax class) from shipping cost considered as a tax included value.
I don't know how to do that...
-
Re: Discount coupon value
After more research on the topic, it seems that shipping with no tax is necessary in some situations, especially in the United States.
Now that I understand more about taxes and ZC, I was able to write some new code that provides correct calculations. I did a lot of testing, considering all the possibilities with different options in coupon and ot_coupon settings...
There is still one option that has some mystery left, 'Per Qualifying Items'. I did not find where/what are criteria for qualifying or not a product.
New file is available on GitHub.
https://github.com/piloujp/zencart/tree/Coupons
-
Re: Discount coupon value
This week I did more testing than writing code, and discount coupons should now be usable with most of the options available in Zen Cart.
By the way, I did same kind of work on GV module as it is related.
Here is a quick summary of how discount coupon module work.
In Admin->Modules->Order Total->Discount Coupon, there are few options:
'Include Shipping' will include shipping cost when tax is recalculated and in maximum possible discount amount calculation.
'Include Tax' will include tax amount when tax is recalculated and in maximum possible discount amount calculation. This option should not be used when tax is recalculated, as it does not make sense to do that. A message will pop up if you try anyway.
'Re-calculate Tax' is probably the most important one. It has 3 options:
'None' as it says, no re-calculation is done.
'Standard' does calculate new tax after discount has been made on net total amount. It is for standard discount given to customers on their order total.
'Credit note' will calculate new tax for refund type discounts that are made on gross price. It is useful to correct some mistake in precedent order, like item missing or defective.
'Tax Class' will assign a tax class to discount. It is important to set this when doing tax recalculation. Not setting it will give wrong tax if recalculation is done.
Then, in Discounts->Coupons Admin page, you can set coupons' value, date limit, number of use, if it applies by item or on order total, to all items or only those with no restrictions...
By the way, the button to set restrictions is on the bottom right of the screen and can be easily missed on small screens where it is not visible...
Gift Certificate module has similar options, but it is a discount manageable by customers. Considering tax recalculation, it is exactly the same as discount coupons.
-
Re: Discount coupon value
Thanks for your hard work on this, @pilou2! It'll take me a couple of weeks, but I will review and provide the testing feedback for these corrections.
-
Re: Discount coupon value
+1. Thank you @pilou2 for your contributions.
-
Re: Discount coupon value
Thanks are always welcome. ;)
I really need someone else looking at it. The file was definitely a work in progress with lots of debug comments, and it is complicated. Although most of the calculations were right, I think their base was wrong. For example, when shipping has no taxes but cart has, then depending on displaying option of tax, you get two different results.
I think an invoice whether using numbers including tax or without tax should always have the same final total and tax. This is the first important difference with actual ZC calculations, and because of this my code won't pass ZC validation tests.
Another difference is, as I already wrote, the definition of standard discount and credit note discount.
Standard customer level discount is done on total price (tax incl.) and credit note is product level refund and should be done on gross prices.
My results are (or should be) consistent with these principles.
There should not be important updates from now, but it is always better to download last GitHub file before testing.
I have some nice fix for the lost penny problem, but I will explain in another thread.
-
Re: Discount coupon value
I did more testings and found few small bugs. I went through all ot modules and three of them are modified.
Discount coupons had a lot to do. For any reason, the tax re-calculation modes were kind of reversed. I had some doubt at the beginning, but other modules code (GV and group discount) confirmed that.
Other discount modules, GV and Group Pricing needed few corrections too but lighter than coupons module.
I am ready to make new PRs (lost penny and coupon), it might be easier for others to review or modify. Although now that V2.0.0 is released, I am not sure anybody will still have some energy left...
-
Re: Discount coupon value
Quote:
Originally Posted by
pilou2
Although now that V2.0.0 is released, I am not sure anybody will still have some energy left...
Please proceed! There's always another release around the corner. We appreciate the hard work you have put into fixing this problem.
-
Re: Discount coupon value
Quote:
Originally Posted by
pilou2
I acknowledge that you've made many updates to proposed coding changes since posting these screenshots, so I'm posting to ask whether the latest code still works as shown in these images?
... because in the US (tax-included-pricing is 'false'), if a person redeems a coupon worth $8.00, they'll want to see that coupon being worth $8.00 not $7.28 in the subtotals.
-
Re: Discount coupon value
Quote:
Originally Posted by
DrByte
I acknowledge that you've made many updates to proposed coding changes since posting these screenshots, so I'm posting to ask whether the latest code still works as shown in these images?
... because in the US (tax-included-pricing is 'false'), if a person redeems a coupon worth $8.00, they'll want to see that coupon being worth $8.00 not $7.28 in the subtotals.
Well, yes and no... In countries I know, there is always a sale tax to apply and when a shop gives you a discount it is always on final prices (tax included). It seems that in US, even at consumer level, tax excluded is the base. In ZC the option to recalculate tax allows both, hopefully. Problem is that in original code 'Credit Note' option was used for tax included discount (I think it was depending on the module), but credit note are in fact an accounting tool (negative invoice) used between company that trade tax excluded and do their adjustments (discounts) tax excluded too.
Because of this and my own experience of discounts, I interpreted the 'Credit Note' option as tax excluded discount and 'Standard' option as tax included.
Actual code follows this interpretation which might be opposite of original code.
Shop owners have to be careful how they set these options or it might end up like you said with an invoice different that what was said.
If you display prices without tax, then discount re-calculate tax should be set to 'Credit Note' with new code. If prices are displayed tax included, 'standard' option would be the best choice. Although in some case, like trade between professionals, you can have a mix of these.
-
Re: Discount coupon value
Hi Guys,
We just run into the same problem where the tax(VAT) in not calculated in the discount coupons. We use a coupon for percentage discount and it calculates the discount without the tax.
The settings in order total Modules have no effect. This make the module unusable.
If you give 1% discount on an amount 100euro incl tax(19%) the result is .84 instead of being 1 euro
-
Re: Discount coupon value
Quote:
Originally Posted by
Georgecy
Hi Guys,
We just run into the same problem where the tax(VAT) in not calculated in the discount coupons. We use a coupon for percentage discount and it calculates the discount without the tax.
The settings in order total Modules have no effect. This make the module unusable.
If you give 1% discount on an amount 100euro incl tax(19%) the result is .84 instead of being 1 euro
In Zencart 2.01 the coupon % discounts are working ok. Is there a temporary fix for the Zencart 1.5.7d? Our ZC 2.01 will need some time to go in production stage.
-
Re: Discount coupon value
Quote:
Originally Posted by
Georgecy
In Zencart 2.01 the coupon % discounts are working ok. Is there a temporary fix for the Zencart 1.5.7d? Our ZC 2.01 will need some time to go in production stage.
There was some major rework done in zc200/zc201 regarding pricing calculations, none of which are easily portable back to a zc157d installation.