I have a setup, where I need to be able to "lock" a customer cart (customer is not logged in) after payment has taken place in webshop. The cart is processed asynchronously by a scehduled job, which takes care of creating the order, and hence the cart must not change after payment.
The issue is if a customer, after completing payment, goes back to webshop again. Then the same cart - which I want to lock - is reused.
Hence I need to forcefully create a new cart, so old cart is not touched.
What I tried so far is to create a new cart setting customerId to Guid.NewGuid. Afterwards I removed the Commerce cache key for the old cart ("EP:DOR:..."). However reloading the existing cart I still get the old "locked" cart with old customerId.
Any ideas how this can be done?
Commerce version is 13.
Will it work if you create an order and put in in certain state the job will consider as locked cart (e.g. OrderStatus.OnHold)? Alternative is to rename the cart you want to lock to something like "Locked" and make the job pick up carts with only that name.
Thanks for your reply :-)
If possible, I would prefer not to create an order beforehand - but that could be a workaround, if I'm not able to create a new cart.
About renaming the cart, I'm not sure that would solve my issue. Problem is that the "old" cart is reused by Commerce when customer reenters the webshop flow (regardless of the cart's name) - and thus cart may be changed when the job picks it up.
That depends on how you work with the cart on the site. For example, IOrderRepository.LoadOrCreateCart<ICart>(customerId, "MyOpenedCartName") will only pick the cart "MyOpenedCartName", not any other carts. If you pick up the first customer's cart, however, you will always hit the same cart regardless of its name.
If the customer has already paid for the cart, and maybe even got inventory allocated, then I would definitely considered it an order. Even if it requires further processing. You can always use an OrderStatus that signals "further processing needed".
Is there any particular reason you need to keep it as a cart until the job has run?
I agree, but the thing is, that we don't always know when the customer has paid for a cart, until the Episerver scheduled job runs. This is because of the setup with the payment service provider, where the psp uses asynchronous callback to indicate to us that a payment has taken place (which then eventually triggers the scheduled job). We should get the callback immediately after the payment, but you never know.
The customer could start the webshop flow again, and if the cart has not been "grabbed" by the job yet, the cart could unfortunately risk being changed.
That's why I would like to be able to create a new cart for the customers, if they start the flow again.
In this case could you convert the cart to an order (while capturing all the payment transaction data) and set the status to OnHold. Then your job will pick up all orders in that status for processing.
If the payment callback never comes, then your job will cancel the order after N attempts or Y hours. So no order will ever be delivered without it having an authorization payment. And meanwhile, the customer can continue shopping.
Would that work?
Could be that would work, but I would need to rewrite some logic around the flow then.
I was hoping I could create a new cart (based on the same cart name).
You can change the name of the cart. Maybe by cloning it to a new cart and clearing the default one. But you need to ensure you are loading by the specific cart name (typically "Default"). Not just the FirstOrDefault() cart, which the parameter-less Load method is loading. So your new cart is sort of "hidden".
That seems to work. Thankyou both!