I have a case right now where the call to _orderRepository.SaveAsPurchaseOrder() has succeeded, but where a call to _orderRepository.Save() later has failed, leaving me with an order that is missing important information, including billing info.
The checkout process so far has been to convert the cart into a purchase order first, and then adding the relevant order information afterwards, finishing off with a Save(). Since this is clearly not a safe approach, I thought I'd try doing it the other way, where I'd set all the important information on the cart first, and then convert the cart to an order as the last step. For a lot of the information, this worked okay, but certain things did not get copied over, such as values in the Properties and the Notes properties.
Since that didn't work either, I want to ask: Is there some way to ensure that I either atomically create a complete order or fail entirely without leaving half-completed orders behind?
" where a call to _orderRepository.Save() later has failed"
What did you do to the order after "SaveAsPurchaseOrder", and what failed?
What gets done to the order after SaveAsPurchaseOrder is
Unfortunately, I do not know what went wrong, because the log has nothing useful in it. But something clearly went wrong between the two save events, which I can tell because the orders are PO-orders, not R-orders, and they are missing all the expected information added in steps 2-5.
It does't matter all that much to me what exactly went wrong, I'm mostly concerned with how to deal with the situation where it does go wrong. Having this operation be atomic, for instance, where either everything succeeds or nothing succeeds, would be perfect.
A few lines code would help here :). Your idea sounds about right, but we need to look into the code.
Only way I know is to catch the exception and attempt to cancel the order and restore the cart.
A way to convert an ICart to an IPurchaseOrder in memory without saving it to the database would enable a better handling if the use cases allow it. (If the client demands that all orders should have an unbroken serie of tracking numbers it won't help. :P)
I don't think there's anything especially relevant about the code. It does exactly what I explained; there's nothing particularly unusual about it. It doesn't fail much either. I'd say it works just fine in over 99.99% of cases.
But I think it's unfortunate that it can go wrong. I was just asking for/hoping for there being a way to make the whole operation atomic. That's all. I guess the takeaway is that it's not possible, at least not at the moment.
I saw that the Cart.SaveAsPurchaseOrder() method (decompiled) does its work inside a TransactionScope. It would be really nice if we could be allowed to do our additional order actions within that TransactionScope through a callback or similar.
I'm not sure I fully understand the problem, but it does sound like you can wrap the entire operation in a big TransactionScope. Either everything succeeds, or they will revert back (except for the payments which might need some extra operations)