Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 02, 2022 @ 08:57
    Johannes Lantz
    0

    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:

    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.

    Any ideas?

    //Johannes

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 02, 2022 @ 09:00
    Matt Brailsford
    0

    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

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 02, 2022 @ 09:27
    Johannes Lantz
    0

    Let's see. I am using:

    public override bool FinalizeAtContinueUrl => true;
    

    And then in the ProcessCallbackAsync

                return CallbackResult.Ok(new TransactionInfo
                {
                    AmountAuthorized = payment.totalAmount,
                    TransactionFee = 0m,
                    TransactionId = payment.id,
                    PaymentStatus = PaymentStatus.Authorized
                },
                new Dictionary<string, string>
                {
                    { "paymentMethod", payment.paymentMethodId },
                    { "paymentName", payment.paymentMethodName },
                });
    

    //Johannes

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 02, 2022 @ 09:50
    Matt Brailsford
    0

    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

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 02, 2022 @ 10:55
    Johannes Lantz
    0

    Ah okay, I see. They are the same URL.

    /kassa/orderbekraftelse/
    /kassa/orderbekraftelse/
    

    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

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 02, 2022 @ 12:54
    Matt Brailsford
    100

    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 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

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 03, 2022 @ 13:37
    Johannes Lantz
    0

    Hi 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

    _uriResolver.GetContinueUrl("alias", ctx.Order.GenerateOrderReference(), _hashProvider);
    

    But I get an null exception error. Unsure why.

    //Johannes

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 03, 2022 @ 13:57
    Matt Brailsford
    0

    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

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 07, 2022 @ 10:10
    Johannes Lantz
    0

    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:

     orde.SetProperties(new Dictionary<string, string>
     {
      { "continueUrl", _uriResolver.GetContinueUrl("alias", order.GenerateOrderReference(), _hashProvider) },
     });
    

    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)
    
  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 07, 2022 @ 10:23
    Matt Brailsford
    1

    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.

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 07, 2022 @ 11:45
    Johannes Lantz
    0

    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

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 07, 2022 @ 12:50
    Matt Brailsford
    0

    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.

    enter image description here

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 07, 2022 @ 15:33
    Johannes Lantz
    0

    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:

        public override string GetContinueUrl(PaymentProviderContext<TSettings> ctx)
        {
            ctx.Settings.MustNotBeNull("ctx.Settings");
            ctx.Settings.ContinueUrl.MustNotBeNull("ctx.Settings.ContinueUrl");
    
            return ctx.Settings.ContinueUrl;
        }
    

    Unsure if the payment form matters. But It looks like this.

    return new PaymentFormResult()
    {
         Form = new PaymentForm(ctx.Urls.ContinueUrl, PaymentFormMethod.Post)
    };
    
  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 07, 2022 @ 15:46
    Matt Brailsford
    1

    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.

  • Johannes Lantz 156 posts 839 karma points c-trib
    Jun 08, 2022 @ 12:44
    Johannes Lantz
    0

    Hi Matt!

    I finally figured it out. So I did this:

                    order.InitializeTransaction();
    
                    order.SetProperties(new Dictionary<string, string>
                        {
                            { "shippingFirstName", model.ShippingAddress.FirstName },
                            { "shippingLastName", model.ShippingAddress.LastName },
                            { "shippingAddressLine1", model.ShippingAddress.Line1 },
                            { "shippingAddressLine2", model.ShippingAddress.Line2 },
                            { "shippingCity", model.ShippingAddress.City },
                            { "shippingDeliveryDate", model.DeliveryDate },
                            { "comments", model.Comments },
                            { "continueUrl", _service.GetContinueUrlForOrder(order.GenerateOrderReference()) },
                        })
                        .SetPaymentCountryRegion();
    

    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

  • Matt Brailsford 4125 posts 22223 karma points MVP 9x c-trib
    Jun 08, 2022 @ 13:24
    Matt Brailsford
    1

    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 👍

Please Sign in or register to post replies

Write your reply to:

Draft