A bug in the checkout flow creates errornous copies of orders
Hi...
It looks like there's something fishy going on with orders during the checkout flow in the starter kit (1.2.0.0).
I am doing a dynamic calculation of shipping cost and other calculations to orders during the checkout (e.g. discount handling). Under specific circumstances, Tea Commerce adds new entries in the Order table, causing the current order to change.
The problem is easy to recreate:
Create an event handler using the code below
Open the starter kit webshop, add an item to the basket and go through the checkout flow - stop at the "Accept" page. Notice that the shipping cost for the order is shown as the value calculated by the UpdateShippingFee() method in the event handler.
Access the database from SQL Management Studio and execute "SELECT TOP 10 o.Id, o.ManipulatedShippingFeeWithoutVAT, o.CreatedDate FROM TeaCommerce_Order o ORDER BY o.Id DESC". Note the Id of the order (the first result). Also notice that the colunm ManipulatedShippingFeeWithoutVAT has the correct value set by the UpdateShippingFee() method in the event handler.
In the webshop, flip backwards through the checkout flow until you reach "Customer information" (Click "< Back to Shipping and Payment", then "< Back to Customer information")
Change country for the order.
In SQL Management Studio, refresh the query. For some reason what looks like a copy of the order has been added to the Order table. Why that happens is beyond me, but at least it does contain a correct, updated value in the ManipulatedShippingFeeWithoutVAT column - so far so good.
In the webshop, go to the next step in the checkout flow (click "Shipping and Payment >")
In SQL Management Studio, refresh the query. Yet another order has been added to the Order table - this time with a NULL value in the ManipulatedShippingFeeWithoutVAT column.
In the webshop, go to the next step in the checkout flow (click "Next >")
As one might expect, the shipping cost for the order is now listed as the default shipping price for the chosen provider.
I'm not entirely certain why Tea Commerce would create a copy of the order in step 5. It might be a feature, it might be a bug - I don't know.
The order copy created in step 7 seems most definitively to be a bug. It happens when the OriginalUnitPriceWithoutVAT property on the orderlines is read by the GetOriginalPriceWithoutVAT() method in the event handler. Read - not written to. Comment out the line and the order is not copied in step 7. And what's even more weird; if you attach a debugger, you'll see that the GetOriginalPriceWithoutVAT() method is not even invoked in step 7!
Any ideas?
~Kenn
publicclassTestEventHandler : ITeaCommerceExtension {
publicvoid Initialize() {
WebshopEvents.OrderLineChanged += WebshopEvents_OrderLineChanged;
WebshopEvents.ShippingMethodChanged += WebshopEvents_ShippingMethodChanged;
WebshopEvents.CountryChanged += WebshopEvents_CountryChanged;
}
privatebool UpdateShippingFee(Order order) {
// get the shipping fee per country per currency (simplified...)var shippingFees = newDictionary<string, Dictionary<string, decimal>> {
{"dk", newDictionary<string, decimal> {{"dkk", 10.00m}, {"eur", 1.33m}, {"usd", 1.80m}}},
{"de", newDictionary<string, decimal> {{"dkk", 20.00m}, {"eur", 2.66m}, {"usd", 3.60m}}},
{"us", newDictionary<string, decimal> {{"dkk", 50.00m}, {"eur", 6.65m}, {"usd", 9.00m}}}
};
var fee = shippingFees[order.Country.CountryCode.ToLowerInvariant()][order.CurrencyISOCode.ToLowerInvariant()];
// update the shipping fee as applicableif(order.ShippingFee == fee) {
returnfalse;
}
order.ShippingFee = fee;
returntrue;
}
privatedecimal GetOriginalPriceWithoutVAT(Order order) {
// this code also triggers the error... but the code below is better for showing where the error occurs :-)//return order.OrderLines.Sum(o => o.OriginalUnitPriceWithoutVAT);// sum the total price without VATvar total = 0m;
foreach(var item in order.OrderLines) {
// access the OriginalUnitPriceWithoutVAT property to trigger the error// (the original code uses OriginalUnitPriceWithoutVAT for something else, this code is just for triggering the error)
total += item.OriginalUnitPriceWithoutVAT;
// accessing other properties instead - e.g. Quantity - does not seem to trigger the error//total += item.Quantity;
}
return total;
}
privatevoid WebshopEvents_OrderLineChanged(Order order, OrderLine orderLine) {
// trigger the error// note: the code does not change anything in the order, and we don't even call order.Save() - but still the error occursvar priceWithoutVAT = GetOriginalPriceWithoutVAT(order);
}
privatevoid WebshopEvents_CountryChanged(Order order, Country country) {
if(UpdateShippingFee(order)) {
order.Save();
}
}
privatevoid WebshopEvents_ShippingMethodChanged(Order order, ShippingMethod shippingMethod) {
if(UpdateShippingFee(order)) {
order.Save();
}
}
}
The reason we clone the orders is the payment provider model we are using. When a user is going to payment we mark the order as "Initial" which means that this specific order number may no longer be manipulated. If the order is being manipulated by the Tea Commerce base it will be cloned and the old order is no longer ind the Current order session. This is done as most Payment providers will not allow the same order number to be pay twice.
It does look like we are not cloning the manipulated values, which would be a bug ofcause. We will have a look at that, but have a slow turn around time at the moment due to the holidays, as you might already have noticed. Until then you might want to recalc your value, which you could do in your OrderChanged event, which is fired all the time.
It looks like Tea Commerce is cloning the manipulated values correctly when changing country on the order, but when the 2nd copy is created out of the blue, the values are not cloned.
I've tested it with the original event handler, that does discounts on order lines, and those discount manipulations seem to be cloned correctly on both occasions.
I have also tried the OrderChanged event, but apparently the ShippingFee for the order is not loaded correctly from the database when using this event, causing the code to be stuck in an infinite loop (code below). Also, moving the logic to the OrderChanged event does not stop Tea Commerce from creating the 2nd clone.
~Kenn
publicclassTestEventHandler : ITeaCommerceExtension {
publicvoid Initialize() {
WebshopEvents.OrderChanged += WebshopEvents_OrderChanged;
}
void WebshopEvents_OrderChanged(Order order) {
// trigger the error// note: the code does not change anything in the order, and we don't even call order.Save() - but still the error occursvar priceWithoutVAT = GetOriginalPriceWithoutVAT(order);
if(UpdateShippingFee(order)) {
// WARNING: // the code is stuck in an infinite loop here since it believes to have changed // the shipping fee because it is not loaded correctly from the DB (?)
order.Save();
}
}
privatebool UpdateShippingFee(Order order) {
// get the shipping fee per country per currency (simplified...)var shippingFees = newDictionary<string, Dictionary<string, decimal>> {
{"dk", newDictionary<string, decimal> {{"dkk", 10.00m}, {"eur", 1.33m}, {"usd", 1.80m}}},
{"de", newDictionary<string, decimal> {{"dkk", 20.00m}, {"eur", 2.66m}, {"usd", 3.60m}}},
{"us", newDictionary<string, decimal> {{"dkk", 50.00m}, {"eur", 6.65m}, {"usd", 9.00m}}}
};
var fee = shippingFees[order.Country.CountryCode.ToLowerInvariant()][order.CurrencyISOCode.ToLowerInvariant()];
// update the shipping fee as applicableif(order.ShippingFee == fee) {
returnfalse;
}
order.ShippingFee = fee;
returntrue;
}
privatedecimal GetOriginalPriceWithoutVAT(Order order) {
// this code also triggers the error... but the code below is better for showing where the error occurs :-)//return order.OrderLines.Sum(o => o.OriginalUnitPriceWithoutVAT);// sum the total price without VATvar total = 0m;
foreach(var item in order.OrderLines) {
// access the OriginalUnitPriceWithoutVAT property to trigger the error// (the original code uses OriginalUnitPriceWithoutVAT for something else, this code is just for triggering the error)
total += item.OriginalUnitPriceWithoutVAT;
// accessing other properties instead - e.g. Quantity - does not seem to trigger the error//total += item.Quantity;
}
return total;
}
}
I have tried testing it here, but it will have to wait until next week. I just can't get anything to work properly here. Hope you can wait, and we will find a solution.
I'll be on vacation myself the next two weeks, so I won't be here to test any solutions until mid August. But I hope you can reproduce it with the posted code... it happens without fail on my solution.
A bug in the checkout flow creates errornous copies of orders
Hi...
It looks like there's something fishy going on with orders during the checkout flow in the starter kit (1.2.0.0).
I am doing a dynamic calculation of shipping cost and other calculations to orders during the checkout (e.g. discount handling). Under specific circumstances, Tea Commerce adds new entries in the Order table, causing the current order to change.
The problem is easy to recreate:
I'm not entirely certain why Tea Commerce would create a copy of the order in step 5. It might be a feature, it might be a bug - I don't know.
The order copy created in step 7 seems most definitively to be a bug. It happens when the OriginalUnitPriceWithoutVAT property on the orderlines is read by the GetOriginalPriceWithoutVAT() method in the event handler. Read - not written to. Comment out the line and the order is not copied in step 7. And what's even more weird; if you attach a debugger, you'll see that the GetOriginalPriceWithoutVAT() method is not even invoked in step 7!
Any ideas?
~Kenn
Hi Kenn,
The reason we clone the orders is the payment provider model we are using. When a user is going to payment we mark the order as "Initial" which means that this specific order number may no longer be manipulated. If the order is being manipulated by the Tea Commerce base it will be cloned and the old order is no longer ind the Current order session. This is done as most Payment providers will not allow the same order number to be pay twice.
It does look like we are not cloning the manipulated values, which would be a bug ofcause. We will have a look at that, but have a slow turn around time at the moment due to the holidays, as you might already have noticed. Until then you might want to recalc your value, which you could do in your OrderChanged event, which is fired all the time.
/Rune
Hi Rune,
I totally understand with the holidays :-)
It looks like Tea Commerce is cloning the manipulated values correctly when changing country on the order, but when the 2nd copy is created out of the blue, the values are not cloned.
I've tested it with the original event handler, that does discounts on order lines, and those discount manipulations seem to be cloned correctly on both occasions.
I have also tried the OrderChanged event, but apparently the ShippingFee for the order is not loaded correctly from the database when using this event, causing the code to be stuck in an infinite loop (code below). Also, moving the logic to the OrderChanged event does not stop Tea Commerce from creating the 2nd clone.
~Kenn
Hi Kenn,
I have tried testing it here, but it will have to wait until next week. I just can't get anything to work properly here. Hope you can wait, and we will find a solution.
/Rune
Hi again,
That's OK.
I'll be on vacation myself the next two weeks, so I won't be here to test any solutions until mid August. But I hope you can reproduce it with the posted code... it happens without fail on my solution.
~Kenn
Hi Kenn,
Finally I found the problem, which was a bug in our cloning method. I have uploaded a new beta package for you with a fix.
/Rune
Hi Rune,
The new beta seems to solve the problem. I'll test it more thoroughly tomorrow and mark the issue as solved :-)
~Kenn
It works :-)
Thank you for your help...!
Great. The fix will be public with our next release.
/Rune
is working on a reply...