We are using a custom payment provider that sends user to external site to enter their credit card details and on success redirects to the receipt page.
If user cancels or credit card is declined we want to redirect them to either the credit card payment form or the payment method page. The redirect is working, but how do we display the Order Summary and address details again?
Redirecting to payment method page displays Invalid Checkout Stage where the Apply Discount and Order Summary details should be.
Redirecting to payment page displays Invalid Checkout Stage where the Payment Method and Order Summary details should be.
The checkout manager's job is essentially done since the invoice has been generated and saved so that the payment (attempt) can be made against the invoice.
The redirecting providers are slightly trickier than the providers local to the application ...
In a local setup, you can simply do the retry directly against the invoice with one of the invoice extensions.
e.g.
if (!paymentResult.Payment.Success)
{
... redirect to a retry form
}
Then something like:
var retry = invoice.AuthorizeCapture(...
In the redirect scenario you are faced with the choice of working out a workflow to do the same as above OR if you've not cleared the basket, simply deleting the previously created invoice and redirecting to the beginning of the Checkout process to create a new CheckoutManager from the basket.
The good news is this is pretty configurable (see https://merchello.readme.io/docs/checkoutcontext) - in which there are options to retain the information the customer previously entered into the checkout forms between checkout manager resets (which happens every time there is a changed detected in the basket or the information is transferred and saved to an invoice).
Thanks for the info. Our site is based on FastTrack, and I still can't figure out how to redirect to the payment method page and have it show the Discount and Order Summary partial views with the correct invoice items data.
It just shows "Invalid Checkout Stage" but I don't know how to set the checkout stage...
I've tried looking at the PayPal example in the Merchello solution but it's still not clear.
The checkout stage is not something required by Merchello. It's just the way the FastTrack starter keeps track of where in the checkout workflow the customer is at any particular point in time.
The invalid checkout stage indicates that you are hitting a page where the CheckoutManager does not have enough information (or a parameter was not passed) to do the specific operation that needs to be performed. Most often this is due to either a change in the basket, or as described above, an invoice being saved and the checkout cleared.
Got a bit further, however, when the external payment page redirects back to the site with Cancel/Decline, the customer ExtendedData no longer contains merchBillingAddress, merchPaymentMethod and merchShippingDestinationAddress.
The CheckoutManager is directed to not empty the basket before the redirect and if I redirect to the Basket page then I can see the basket items are still there. However, the shipping and payment method details have gone.
However, it sounds like CheckoutManager.Context.SettingsResetCustomerManagerDataOnVersionChange == true. That was the default setting in early versions ... however it was later changed to have a default of false on install.
Check your merchello.config to ensure this setting is indeed false and that you are not overriding the setting if you are using a custom context.
Checked the config and CheckoutManager.Context.SettingsResetCustomerManagerDataOnVersionChange is set to false and i can't see anywhere where we are overriding the setting.
After stepping through the code and checking the extendedData values in merchAnonymousCustomer, it seems that something in the following method on CheckoutPaymentManagerBase is causing the extendedData to 'lose' the address and payment method details:
If the result is successful the CheckoutManager will reset since the checkout has been completed and it's job is done.
However, this event should not be raised in the event of a cancel. If the payment was declined, the result of the payment attempt should have a success value of false which would prevent the reset in the event handler.
We have a two step payment process (AuthorizePayment and CapturePayment) as we are using non-inline payment provider.
The AuthorizePayment step is returning a successful payment result to indicate that the AuthorizePayment was successful - this is causing the CheckoutManager to reset before we have attempted to capture the payment.
I tried to sub-class the BasketCheckoutPaymentManager but was unable to as it is an internal class.
I then tried to create my own version by taking a copy of the BasketCheckoutPaymentManager code, but found that some of the other forms (from memory I think it was the Discount form) expected a BasketCheckoutPaymentManager.
I ended up creating my own AuthorizePayment method in my payment method controller and based it on the BasketCheckoutPaymentManager's code
public IPaymentResult AuthorizePayment(Guid paymentMethodKey, ProcessorArgumentCollection args)
{
var paymentManager = this.CheckoutManager.Payment;
var paymentGatewayMethod = this.CheckoutManager.Context.Gateways.Payment.GetPaymentGatewayMethods().FirstOrDefault(x => x.PaymentMethod.Key.Equals(paymentMethodKey));
if (!paymentManager.IsReadyToInvoice()) return new PaymentResult(Attempt<IPayment>.Fail(new InvalidOperationException("SalesPreparation is not ready to invoice")), null, false);
// invoice
var invoice = paymentManager.PrepareInvoice();
paymentManager.Context.Services.InvoiceService.Save(invoice);
var result = invoice.AuthorizePayment(paymentGatewayMethod, args);
// Removed steps that emptied basket and finalized payment
return result;
}
Noninline payment provider - handle cancel/decline
We are using a custom payment provider that sends user to external site to enter their credit card details and on success redirects to the receipt page.
If user cancels or credit card is declined we want to redirect them to either the credit card payment form or the payment method page. The redirect is working, but how do we display the Order Summary and address details again?
Redirecting to payment method page displays Invalid Checkout Stage where the Apply Discount and Order Summary details should be.
Redirecting to payment page displays Invalid Checkout Stage where the Payment Method and Order Summary details should be.
What is happening -
The checkout manager's job is essentially done since the invoice has been generated and saved so that the payment (attempt) can be made against the invoice.
The redirecting providers are slightly trickier than the providers local to the application ...
In a local setup, you can simply do the retry directly against the invoice with one of the invoice extensions.
e.g.
Then something like:
In the redirect scenario you are faced with the choice of working out a workflow to do the same as above OR if you've not cleared the basket, simply deleting the previously created invoice and redirecting to the beginning of the Checkout process to create a new CheckoutManager from the basket.
The good news is this is pretty configurable (see https://merchello.readme.io/docs/checkoutcontext) - in which there are options to retain the information the customer previously entered into the checkout forms between checkout manager resets (which happens every time there is a changed detected in the basket or the information is transferred and saved to an invoice).
Thanks for the info. Our site is based on FastTrack, and I still can't figure out how to redirect to the payment method page and have it show the Discount and Order Summary partial views with the correct invoice items data.
It just shows "Invalid Checkout Stage" but I don't know how to set the checkout stage...
I've tried looking at the PayPal example in the Merchello solution but it's still not clear.
The checkout stage is not something required by Merchello. It's just the way the FastTrack starter keeps track of where in the checkout workflow the customer is at any particular point in time.
The invalid checkout stage indicates that you are hitting a page where the CheckoutManager does not have enough information (or a parameter was not passed) to do the specific operation that needs to be performed. Most often this is due to either a change in the basket, or as described above, an invoice being saved and the checkout cleared.
One thing that is done in the PayPal express implementation is the CheckoutManager is directed to not empty the basket before the redirect even though the payment method will save the created invoice befor the redirect: https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web.Store/Controllers/Payment/PayPalExpressPaymentController.cs#L57
This allows for the checkout to be started over in the event of a cancellation or failed payment. https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web.Store/Controllers/Payment/PayPalExpressPaymentController.cs#L169
Note: This technique does have the consequence that in the event of a failure or cancellation, invoice numbers get skipped (because of the deletion).
Got a bit further, however, when the external payment page redirects back to the site with Cancel/Decline, the customer ExtendedData no longer contains merchBillingAddress, merchPaymentMethod and merchShippingDestinationAddress.
The CheckoutManager is directed to not empty the basket before the redirect and if I redirect to the Basket page then I can see the basket items are still there. However, the shipping and payment method details have gone.
There are a bunch of settings that can be configured in the CheckoutContext: https://merchello.readme.io/docs/checkoutcontext
However, it sounds like
CheckoutManager.Context.SettingsResetCustomerManagerDataOnVersionChange == true
. That was the default setting in early versions ... however it was later changed to have a default offalse
on install.Check your merchello.config to ensure this setting is indeed false and that you are not overriding the setting if you are using a custom context.
Checked the config and CheckoutManager.Context.SettingsResetCustomerManagerDataOnVersionChange is set to false and i can't see anywhere where we are overriding the setting.
After stepping through the code and checking the extendedData values in merchAnonymousCustomer, it seems that something in the following method on CheckoutPaymentManagerBase is causing the extendedData to 'lose' the address and payment method details:
I haven't been able to determine what it is though
The OnFinalizing event is handled here:
https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web/UmbracoApplicationEventHandler.cs#L439
If the result is successful the CheckoutManager will reset since the checkout has been completed and it's job is done.
However, this event should not be raised in the event of a cancel. If the payment was declined, the result of the payment attempt should have a success value of false which would prevent the reset in the event handler.
We have a two step payment process (AuthorizePayment and CapturePayment) as we are using non-inline payment provider.
The AuthorizePayment step is returning a successful payment result to indicate that the AuthorizePayment was successful - this is causing the CheckoutManager to reset before we have attempted to capture the payment.
I was able to resolve the issue by creating a custom version of the Basket's AuthorizePayment method that does not finalize the payment.
Hey Lesley
I'd love to see your solution - did you just sub-class the BasketCheckoutPaymentManager ... or did you do it some other way?
I tried to sub-class the BasketCheckoutPaymentManager but was unable to as it is an internal class.
I then tried to create my own version by taking a copy of the BasketCheckoutPaymentManager code, but found that some of the other forms (from memory I think it was the Discount form) expected a BasketCheckoutPaymentManager.
I ended up creating my own AuthorizePayment method in my payment method controller and based it on the BasketCheckoutPaymentManager's code
is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.