Price calculations (tax and discount) - orocommerce

What is the correct way of calculating product (and order) prices when a coupon is applied (considering the product is taxable). I've noticed that the taxes and discounts are disconnected. They are both applied on product's row price (and then summed up for the total price). I need to apply the tax on discounted product price:
(price - discount) + tax(discounted price)
What is the best approach to implement such calculation?

This behavior is not customizable from UI.
But you can change it in customization:
Decorate OrderLineItemMapper or OrderMapper, depending on your requirements
Use there a price with an applied discount that you can fetch from oro_promotion.promotion_executor service.

Related

Correct way to calculate prices including tax in foreign currencies

I'm trying to upgrade an application so that I can sell to multiple countries. I store all of my prices in the database in GBP excluding tax up to 4dp and I need to calculate the prices in the country's currency including tax.
Do I multiply the price by the exchange rate against the price excluding tax (option 1) or do I calculate the amount including tax and then multiple by the exchange rate (option 2)? I have also added an option 3 after looking at how OpenCart calculates it which is similar to option 2 but only ever rounds when displaying it. Here are the formula's for all 3 options:
Option 1:
Round((Price * Exchange Rate) / 100 * (100 + Tax Rate))
Option 2:
Round(Round(Price / 100 * (100 + Tax Rate)) * Exchange Rate)
Option 3:
Round((Price / 100 * (100 + Tax Rate)) * Exchange Rate)
For example say I have a product with a price of 89.99. If I wanted to display that in a currency with an exchange rate of 1.5 and a tax rate of 20%. Would I say:
Option 1:
Round((89.99 * 1.5) / 100 * (100 + 20)) = 161.98
Option 2:
Round(Round(89.99 / 100 * (100 + 20)) * 1.5) = 161.99
Option 3:
Round((89.99 / 100 * (100 + 20)) * 1.5) = 161.98
I've found that OpenCart always multiplies the unrounded figures by the exchange rate at the end. For example their formula for calculating the line total is:
Round((Price / 100 * (100 + Tax Rate)) * Quantity * Exchange Rate)
So if I was to order 3 of my product's it would give:
Round((89.99 / 100 * (100 + 20)) * 3 * 1.5) = 485.95
The problem I find doing it OpenCart's way is the user will see an item price (including tax) of 161.98 and a line total of 485.95. However if I say 161.98 * 3 I get 485.94, so it doesn't sum up correctly.
It's important I get this right as you can see I'll end up with penny issues. I'd appreciate it if someone could let me know which way is correct or suggest an alternative if none are right. Thanks
Since all variables are rounded except Exchange Rate, which I would expect to usually look something like this 1.3462, we can write a test like this:
// I'm guessing you need it in PHP
$price = 89.99;
$quantity = 1;
$tax = 20;
$tax = $tax/100.0 + 1;
// $tax = 1.2
$exchangeRate = 1.5;
$totalPrice = $price*$quantity*$tax; // Test #1
$totalPriceRounded = round($price*$quantity*$tax,2); // Test #2
echo $totalPrice.'<br/>'.$totalPriceRounded;
Which would have this output:
107.988 // Test #1 <--- This is amount that needs to be paid to you and Great Britain
107.99 // Test #2 <--- rounded
Now, it's obvious there is a difference in amount, so which to choose? Since you are charging an item from Great Britain, you expect to get paid the full amount you are asking for, in GBP, so lets rely on that factor. In the end, if I understood correctly, the tax the customer has to pay is tax to Great Britain.
Lets check the final prices in foreign currency:
$totalPrice = round($totalPrice * $exchangeRate,2);
$totalPriceRounded = round($totalPriceRounded * $exchangeRate,2);
echo $totalPrice.'<br/>'.$totalPriceRounded;
Which would have this output:
// Amount in foreign currency
161.98 // Test #1
161.99 // Test #2
With all that said, lets check which one of these would return you a value closest to 107.988 GBP when calculated back to GBP from foreign currency.
// To calculate the totalPrice back to price*tax*quantity in GBP
$totalPrice /= $exchangeRate;
$totalPriceRounded /= $exchangeRate;
echo $totalPrice.'<br/>'.$totalPriceRounded;
Output of which is:
// totalPrice in GBP currency
107.98666666667 // Test #1
107.99333333333 // Test #2
And when we divide by tax:
$totalPrice /= $tax;
$totalPriceRounded /= $tax;
echo $totalPrice.'<br/>'.$totalPriceRounded;
Output is:
// the amount you get in GBP currency
89.988888888889 // End result of Test #1
89.994444444444 // End result of Test #2
So as you can see, in this case, by using the bare amount of round($price*$quantity*$tax*$exchangeRate, 2) you are getting less, but by using round(round($price*$quantity*$tax,2)*$exchangeRate, 2) you get a little more which again, rounded both give the same value. In some other scenario the difference will likely be different from what we got here and might be the other way around.
CONCLUSION
If you have a fixed number of products each with fixed prices then you will be either loosing money (an insignificant amount) or earning more than you should (also an insignificant amount) over time. The outcome depends on the popularity and price of each product (i.e. will the round function round up or down), and on the way of calculation you chose. You could, depending on product popularity, manually adjust the prices of each product to minimize the loss/gain over time.
If you have products with random prices like lets say you are renting web servers and the price is $0.01/second. Then the expectation value for your loss/gain is close to zero. And the more purchases are made the closer to zero it gets. So you are not loosing anything here regardless of the approach. One time you win some one time you loose some.
In my opinion I would standardize it to round everything:
$price = 4.47;
$quantity = 1.2 // lets say liters
// Even round the price before applying tax
$totalPrice = round($price * $quantity, 2);
because if you are forced to show all the different stages of calculation then you will have to round every step.
But the most precise would be to use this as the least information is lost:
// Round once at end
$totalPrice = round($price*$quantity*$tax*$exchangeRate, 2);
In the end it all depends on how you set up your product prices or how your pricing works to be able to choose which method to go with. I'd say it doesn't really matter, I think every company simply chooses what suits them best.
Legally, some countries/cities/etc. have laws on how to calculate this, you should be looking at Great Britain laws to check on the valid procedure for your problem.
I can't tell you what the correct option is or even if there is one correct option. But from experience I can say, if there are multiple options to do one thing, make it configurable in your software. In this case you can easily use the strategy pattern and make the strategy for calculating prices configurable. Customers can choose how they want it calculated.
The correct solution depends on your business. When you sell items in different countries, you most likely have branches in those countries - and you need a net price in those country's currency. This results in the net price per item "translated" to the foreign currency, and this net price is then multiplied with the amount and multiplied with the tax factor/percentage).
The EU MOSS (which is charged when you offer services in other countries, or e.g. software as download) is somehow different. You can sell products with GBP pricing, but have to consider your consumer's local tax factor. See e.g. https://ec.europa.eu/taxation_customs/sites/taxation/files/resources/documents/taxation/vat/how_vat_works/telecom/one-stop-shop-guidelines_en.pdf
For MOSS, I didn't check in detail, but I expect that you then have a different formula, using your local GBP net price per item, multiply with amount, multiply with consumer's tax percentage. This tax amount, still in GBP, should then be multiplied with currency exchange rate, I'd expect.

Prestashop 1.6.1.4 not stacking discounts and showing wrong price

I have a problem with my Prestashop: If a product only have quantity discounts the total price shown in the cart is correct, but when I also apply a category general discount (from Price Rules) that involves a product that also had a quantity discount, the last one overrides the category discount.
In the product template (product.tpl) price is correct (I mean, both discounts are applied, firstly the category discount and then the quantity discount) but in the shopping cart only quantity discount is applied.
Is there a way to achieve stacking of these discounts?
Thank you in advanced!

How do I perform math in SQL query on certain conditions?

I have a few tables I am querying, Item movement, and price. There are three price levels, regular price, reduced price, and sale price. I am attempting to get a markdown (price that item sold at when on sale minus either the regular or reduced price). My item movement table contains only the price the unit sold at and the price type of that sale. I am currently selecting only the items that sold on the sale price type. Next I have to find out whether the item was on a regular or reduced price, which I determine by looking at my price table. The price table has my regular price and reduced price and if the reduced price is null then it is not currently reduced.
How do I tell SQL that I want a column named "markdown" that is essentially (IF price.tprprice not null AND price.tprenddate > #StartDate give me column (price.baseprice - price.tprprice) * itemmovement.qtysold AS markdown ELSE give me column (price.baseprice - itemmovement.price) * itemmovement.qtysold AS markdown)
I need to return the result of each calculation performed on each row into the same column titled Markdown.
Can anyone tell me how this query should be structured?
case when price.tprprice is not null AND price.tprenddate > #StartDate
then (price.baseprice - price.tprprice) * itemmovement.qtysold
else (price.baseprice - itemmovement.price) * itemmovement.qtysold
end as markdown
You would do it with a case statement which works in most databases.

Calculate price using percentage from product field

I'm using drupal commerce module and drive with pricing rule problem. User and product have percentage fields, which are discount values separately. Final discount gathered from sum of this fields. How can I calculate line item price with discount fields?

how to set discount price for multiple products in prestashop

I am using prestashop version 1.5.4.1
I am need to set clearance sale offer to my shopping site (particular date).
In particular date i need to set discount price for all products in my products by common.
EXAMPLE : I have 250 products in my catalog. I need to discount price $100 for all products from june-24 to june 30. How to set in a one click
You can easily set a "Catalog price rule" in your PrestaShop Back-office.
Go to "Price rules > Catalog price rule" and create a new rule.
It will allow you to select various criteria and the amount or percentage of reduction you would like to apply to all the related products.
You can also cumulate the criteria, example:
For all products in the "T-shirts" category
With "XXXXX" as a Manufacturer
and with the color "Blue"
=> Apply a discount of 30%
Regards,