I am using a custom checkout flow with a custom payment provider. When I get redirected to the Order confirmation page I use this to get the finalized order:
var currentOrder = VendrApi.Instance.GetCurrentFinalizedOrder(store.Id);
But currentOrder becomes null at first. But if I then refresh the page currentOrder becomes the finalized order. I am thinking It could maybe be a delay before the order becomes finalized and that's why it's null at first? I tried doing this:
if (currentOrder == null)
{
Response.Redirect(Model.Url(mode: UrlMode.Absolute));
}
Which work but it feel real yank and prone to error. But other from that I am unsure to make a "proper" fix for this.
What payment provider are you using? And are you going via Vendr's own Continue URL are are you bypassing this with your own logic. It's part of Vendr's Continue URL that sets the current finalized order so if you are bypassing this, you'd need to set it yourself.
This is fine, it's more where you are redirected to from the payment gateway. It need to be to Vendr's Continue URL that it provides you as part of the GenerateForm method. Can you see what URL you are passing to the gateway to perform the continue redirect?
Right now we only render the form but we don't use it. Since our payment provider renders an IFrame where they then redirect us to the payment gateway. Which then redirects to the confirmation page.
Yea, Vendr creates a continue URL like /umbraco/vendr/payment/continue/payment-provider-alias/order-id/order-number/url-hash. It's when you hit this URL that the current order is moved to the finalized order state and then it internally redirects to your payment providers configured continue URL.
If you are going directly to the continue URL without hitting Vendr's continue handler then you are skipping this part of the process and this will be why the order isn't intially there.
The form doesn't have to be submitted, but it's the GenerateForm method that is the only thing that is passed the continueUrl parameter that is the pre-configured URL Vendr needs you to use.
Without seeing your setup, the ideal scenario would be that you render the form somewhere and set it to point to the continue URL, then when your iframe is done, maybe trigger the form to post.
If that's a bit too convoluted, you can either redirect to the URL as per the format above (which should just work) or, you'll have to replicate what Vendr's continue URL actually does (moving the current order to the finalized order in the session manager).
I think just hitting Vendr's Continue URL should be the simplest option.
PS You can resolve an IPaymentProviderUriResolver from the DI container and use that to generate the continue URL manually outside of a payment provider so this would probably be the best way to get Vendr's continue URL
Thank you for the reply! Ah! Okay then should be it!
I am unsure if I am able to do a post on the form since the IFrame redirects to the payment gateway right away.
I just wanted to clarify. Do you mean that I should have /umbraco/vendr/payment/continue/payment-provider-alias/order-id/order-number/url-hash as the continue URL instead of /kassa/orderbekraftelse/?
Yes, you should be using our URL to continue to, and not directly to the actual confirmation page. As mentioned above, this is what is bypassing our functionality.
RE your code, that should be correct, but hard to say what could be wrong with a stack trace for the exception.
And it worked the first time. But that was only because I already had an existing order number (from old order). When I then tried again with a new order I got an null exception error since the order number is null. I though I could use the IOrderNumberGenerator and set the order number within the UpdateOrderInformation surface controller. But the order number field is readonly.
So I am a bit stuck here on how I should proceed. Any ideas on how I could proceed?
//Johannes
System.NullReferenceException: Object reference not set to an instance of an object.
at Vendr.Extensions.HtmlHelperExtensions.RenderPaymentForm(HtmlHelper htmlHelper, OrderReadOnly order, IDictionary`2 htmlAttributes, IOrderService orderService, IPaymentMethodService paymentMethodService, IPaymentProviderService paymentProviderService, PaymentProviderContextFactory paymentProviderContextFactory, IOrderNumberGenerator orderNumberGenerator, IUnitOfWorkProvider uowProvider, IMembershipHelper membershipHelper)
at Vendr.Extensions.HtmlHelperExtensions.BeginPaymentForm(HtmlHelper htmlHelper, OrderReadOnly order, IDictionary`2 htmlAttributes)
at Vendr.Extensions.HtmlHelperExtensions.BeginPaymentForm(HtmlHelper htmlHelper, OrderReadOnly order)
at ASP._Page_Views_PaymentMethod_cshtml.Execute() in C:\Users\------\Desktop\umb\umb.Web\Views\PaymentMethod.cshtml:line 22
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
at Umbraco.Web.Mvc.ProfilingView.Render(ViewContext viewContext, TextWriter writer) in D:\a\1\s\src\Umbraco.Web\Mvc\ProfilingView.cs:line 25
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_6.<BeginInvokeAction>b__4()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<>c.<BeginExecute>b__151_2(IAsyncResult asyncResult, Controller controller)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.<>c.<BeginProcessRequest>b__20_1(IAsyncResult asyncResult, ProcessRequestState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
If you are bypassing Vendr's other URL's you'll need to initalize the transaction before moving to the payment gateway by calling order.InitializeTransaction();. This will setup the order ready to taken payment and generate a new order number.
Thank you! That did the trick! Now I am being redirected to the umbraco/vendr/payment/continue/ URL!
But I just have one last question. The umbraco/vendr/payment/continue/ URL just shows a blank page. But I want it to show the content of /kassa/orderbekraftelse/ in which all the "Thank you for you order" stuff is located.
How do I go about doing that?
So the umbraco/vendr/payment/continue/ will look up the payment provider that maches the alias on the continue URL, and that payment provider should implement the GetContinueUrl method wherby Vendr does it's thing and then does an internal redirect to that URL.
Most providers expose this as a payment provider setting.
Have you debugged this? do you hit that GetContinueUrl method? If not I'd double check your generator method and make sure it's using the same payment method alias as your payment method that uses your provider.
The trailing SetPaymentCountryRegion() nulled the order number when it was saved. So the GetContinueUrl() generate an incorrect URL. Then when I went to generate the form in the next step the order got a new order number. That's why I didn't get redirected.
Removing the SetPaymentCountryRegion() did the trick here.
Basically anything that has the potential to effect the price of an order that is changed AFTER InitializeTransaction is called will force the order to re-initialize and re-generate a new order number.
As youv'e found, you basically need to make sure you have completely finished editing the order before you call InitializeTransaction
GetCurrentFinalizedOrder null first time
Hi!
I am using a custom checkout flow with a custom payment provider. When I get redirected to the Order confirmation page I use this to get the finalized order:
But
currentOrder
becomesnull
at first. But if I then refresh the pagecurrentOrder
becomes the finalized order. I am thinking It could maybe be a delay before the order becomes finalized and that's why it'snull
at first? I tried doing this:Which work but it feel real yank and prone to error. But other from that I am unsure to make a "proper" fix for this.
Any ideas?
//Johannes
What payment provider are you using? And are you going via Vendr's own Continue URL are are you bypassing this with your own logic. It's part of Vendr's Continue URL that sets the current finalized order so if you are bypassing this, you'd need to set it yourself.
Matt
Let's see. I am using:
And then in the
ProcessCallbackAsync
//Johannes
Hey Johannes,
This is fine, it's more where you are redirected to from the payment gateway. It need to be to Vendr's Continue URL that it provides you as part of the GenerateForm method. Can you see what URL you are passing to the gateway to perform the continue redirect?
Matt
Ah okay, I see. They are the same URL.
Does the form has to be submitted for it to work?
Right now we only render the form but we don't use it. Since our payment provider renders an IFrame where they then redirect us to the payment gateway. Which then redirects to the confirmation page.
//Johannes
Hi Johannes,
Yea, Vendr creates a continue URL like
/umbraco/vendr/payment/continue/payment-provider-alias/order-id/order-number/url-hash
. It's when you hit this URL that the current order is moved to the finalized order state and then it internally redirects to your payment providers configured continue URL.If you are going directly to the continue URL without hitting Vendr's continue handler then you are skipping this part of the process and this will be why the order isn't intially there.
The form doesn't have to be submitted, but it's the
GenerateForm
method that is the only thing that is passed thecontinueUrl
parameter that is the pre-configured URL Vendr needs you to use.Without seeing your setup, the ideal scenario would be that you render the form somewhere and set it to point to the continue URL, then when your iframe is done, maybe trigger the form to post.
If that's a bit too convoluted, you can either redirect to the URL as per the format above (which should just work) or, you'll have to replicate what Vendr's continue URL actually does (moving the current order to the finalized order in the session manager).
I think just hitting Vendr's Continue URL should be the simplest option.
PS You can resolve an
IPaymentProviderUriResolver
from the DI container and use that to generate the continue URL manually outside of a payment provider so this would probably be the best way to get Vendr's continue URLHi Matt!
Thank you for the reply! Ah! Okay then should be it!
I am unsure if I am able to do a post on the form since the IFrame redirects to the payment gateway right away.
I just wanted to clarify. Do you mean that I should have
/umbraco/vendr/payment/continue/payment-provider-alias/order-id/order-number/url-hash
as the continue URL instead of/kassa/orderbekraftelse/
?I tried using the
IPaymentProviderUriResolver
But I get an null exception error. Unsure why.
//Johannes
Hi Johannes,
Yes, you should be using our URL to continue to, and not directly to the actual confirmation page. As mentioned above, this is what is bypassing our functionality.
RE your code, that should be correct, but hard to say what could be wrong with a stack trace for the exception.
Matt
Hi Matt!
I have done some research. It thought I could generate the continue URL inside the payment provider. But then I would get the error below.
I then tried generating the continue URL inside the
UpdateOrderInformation
surface controller. I did something like this:And it worked the first time. But that was only because I already had an existing order number (from old order). When I then tried again with a new order I got an null exception error since the order number is null. I though I could use the
IOrderNumberGenerator
and set the order number within theUpdateOrderInformation
surface controller. But the order number field is readonly.So I am a bit stuck here on how I should proceed. Any ideas on how I could proceed?
//Johannes
Hi Johannes,
If you are bypassing Vendr's other URL's you'll need to initalize the transaction before moving to the payment gateway by calling
order.InitializeTransaction();
. This will setup the order ready to taken payment and generate a new order number.Thank you! That did the trick! Now I am being redirected to the
umbraco/vendr/payment/continue/
URL!But I just have one last question. The
umbraco/vendr/payment/continue/
URL just shows a blank page. But I want it to show the content of/kassa/orderbekraftelse/
in which all the "Thank you for you order" stuff is located. How do I go about doing that?//Johannes
So the
umbraco/vendr/payment/continue/
will look up the payment provider that maches the alias on the continue URL, and that payment provider should implement theGetContinueUrl
method wherby Vendr does it's thing and then does an internal redirect to that URL.Most providers expose this as a payment provider setting.
Hmm I see. I am not getting redirected though. The order becomes finalized. But I am stuck on the
/umbraco/vendr/payment/continue/
URL.I implement my payment provider like this:
Unsure if the payment form matters. But It looks like this.
Have you debugged this? do you hit that
GetContinueUrl
method? If not I'd double check your generator method and make sure it's using the same payment method alias as your payment method that uses your provider.Hi Matt!
I finally figured it out. So I did this:
The trailing
SetPaymentCountryRegion()
nulled the order number when it was saved. So the GetContinueUrl() generate an incorrect URL. Then when I went to generate the form in the next step the order got a new order number. That's why I didn't get redirected.Removing the
SetPaymentCountryRegion()
did the trick here.Thank you for all your help Matt!
//Johannes
Ahh yes,
Basically anything that has the potential to effect the price of an order that is changed AFTER
InitializeTransaction
is called will force the order to re-initialize and re-generate a new order number.As youv'e found, you basically need to make sure you have completely finished editing the order before you call
InitializeTransaction
Glad you got it working 👍
is working on a reply...