Control the rounding level of currencies
Promotion engine rounds the discount value to the known decimal digits of the order currency. The official decimal digits of currencies are defined by ISO 4217 standard, however as a business, you might have different requirements. For example, normally, you will only see $12.34 , but it's not very uncommon for you to have a price of $12.3456. This might cause some problem where something that should be free, is not, or even worse, the actual cost of something (like shipping cost) will be negative, causing validation error.
That is, however can be worked around by controlling the number of decimal digits for a currency. In the example above, it might make senses to set CurrencyDecimalDigits of USD to 4. This can be done by this snippet code added to an initialization module, which has side-wide affect:
var f = Currency.USD.Format;
f.CurrencyDecimalDigits = 4;
Currency.SetFormat(Currency.USD.CurrencyCode, f);
This is, however, not without drawback. Any amount in USD will have 4 decimal digits, so they might not be displayed nicely to end user. I would suspect most end users would like to see USD 12.34, instead of USD 12.3456 in their cart page. That is something you might to think about.
We have some changes that will fix the rounding issues completely (I hope!), but that requires breaking changes so it will have to wait until Commerce 13.
For now, the workaround above should work.
Cool to hear that a fix is on the way! :D
When looking at this issue a few days back I came up with another temporary solution that is a bit more verbose, but doesn't affect the presentation of the entire site.
It involves overriding the Run method on the Promotion Engine and looks like this:
But I haven't tried it in a real project, so I'm not sure if it could cause an issue further down the line if some values get rounded in one way but discounts get rounded in another. But I assume so.
Thanks @Quan Mai and @Jafet Valdez.
@Jafet Valdez: each approach has its pros and cons, but I would suggest to go with interceptor pattern instead of inheriting directly from PromotionEngine (I don't even know why we made that public)
@Quan, yeah. That makes a lot more sense. Thanks!
At the risk of spamming the comments with code, this would be the new version:
SiteInitialization (IConfigurableModule.ConfigureContainer)
MyPromotionEngine
Keep bringing your sample code. That' good work, not spamming :)
Cool to hear that a fix is on the way! :D
When looking at this issue a few days back I came up with another temporary solution that is a bit more verbose, but doesn't affect the presentation of the entire site.
It involves overriding the Run method on the Promotion Engine and looks like this:
But I haven't tried it in a real project, so I'm not sure if it could cause an issue further down the line if some values get rounded in one way but discounts get rounded in another. But I assume so.
I would not call implementation you receive in interceptor as "default" :) as there might be other friends of yours to do the same thing. I usually refer to them as "inner".
Thanks for this workaround! I see still one place after implementing this workaround where it is not working properly. On OrderForm level there is a promotion list. The SavedAmount properties per promotion are not stored with respecting the decimals.
For example I have logic, where I determine per promotion type the saved amount, as we have an external order system which needs to know that information to process promotions properly. Therefore we process per lineitem in the order the promotions like this, such that we later can do some calculations with it:
What we currently see is that SavedAmount is only using max 3 decimal digits (still some rounding is taking place there). On LineItem level in the Order, the SavedAmount of all promotions is indeed correctly saved, but not on individual promotion level. Is there a way how to retrieve this info with the decimal places respected according to the workaround?
Our code:
Since there is a bug in the promotion engine causing campaigns to be rounded with to few decimals and then in turn causing issues with payments (e.g. we send a total amount with 1 cent to much or to little). This in turn causes the order to be stopped in the warehouse since the payment doesn't match the amount in the ERP system (that doesn't have any rounding error).
We are in a dire need of a workaround until the promotion engine is fixed in v13.