Copied to clipboard

Flag this post as spam?

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


  • Fabian 68 posts 171 karma points
    Sep 29, 2016 @ 16:00
    Fabian
    0

    Created Order status remains unpaid

    Hi Everyone,

    I am using klarna with merchello and when the time comes to create the order in merchello for some reason the status is remaining as unpaid. First I thought because I was just authorizing the payment (AuthorizePayment) and not authorizing and capturing the payment (AuthorizeCapturePayment) but I have fixed that and the behavior still remained the same. Here is my code:

    private bool confirmOrder(IDictionary<string, string> processorArgs, ProcessorArgumentCollection processorArgs2, ICheckoutManagerBase checkoutManager, IEnumerable<string> customInvoiceNotes = null)
            {
                LogHelper.Info(typeof(KlarnaPaymentMethodUiController), "entered in confirm order method");
    
                // Attempt to get a previously saved payment method if no explicit payment method key provided
                var paymentMethod = getPaymentMethod(processorArgs, checkoutManager);
                if (paymentMethod == null)
                {   
                    LogHelper.Error(typeof(KlarnaPaymentMethodUiController), "Payment failed. No payment method was found.", new NotImplementedException());
                    //_log.Error("Payment failed. No payment method was found.");
                    return false;
                }
    
                LogHelper.Info(typeof(KlarnaPaymentMethodUiController), "getPaymentMethod success");
    
                var attempt = checkoutManager.Payment.AuthorizeCapturePayment(paymentMethod.Key, processorArgs2);
    
                if (!attempt.Payment.Success)
                {      
                    //_log.Fatal("Payment failed.", attempt.Payment.Exception);
                    LogHelper.Error(typeof(KlarnaPaymentMethodUiController), "attempt payment success failed", attempt.Payment.Exception);
                    return false;
                }
    
                //_log.DebugFormat("Successful payment with key {0} and ref no {1}.", attempt.Payment.Result.Key, attempt.Payment.Result.ReferenceNumber);
                LogHelper.Info(typeof(KlarnaPaymentMethodUiController), String.Format("Successful payment with key {0} and ref no {1}.", attempt.Payment.Result.Key, attempt.Payment.Result.ReferenceNumber));
    
                // The orders collection on the invoice isn't automatically populated after order creation, so we need to do it manually
                var invoiceOrders = MerchelloServices.OrderService.GetOrdersByInvoiceKey(attempt.Invoice.Key);
                foreach (var io in invoiceOrders)
                {      
                    attempt.Invoice.Orders.Add(io);
                }
    
                foreach (var invoiceOrder in invoiceOrders)
                {         
                    MerchelloServices.OrderService.CreateOrder(invoiceOrder.OrderStatusKey, invoiceOrder.Key);
                }
    
                //_taskSequenceHandler.ExecuteTaskSequence(TaskSequenceTrigger.OnCheckoutComplete, attempt);
    
                // store the invoice key in the CustomerContext for use on the receipt page.
                CustomerContext.SetValue("invoiceKey", attempt.Invoice.Key.ToString());
    
                checkoutManager.Reset();
    
                return true;
            }
    

    Does anyone have a clue why and can point me to the right direction?

    Thanks

  • Rusty Swayne 1655 posts 4987 karma points c-trib
    Sep 29, 2016 @ 16:19
    Rusty Swayne
    0

    Hi Fabian,

    Are you using a custom payment provider for this?

    It should be happening in the underlying code here (if attempt.Payment.Success)

     var attempt = checkoutManager.Payment.AuthorizeCapturePayment(paymentMethod.Key, processorArgs2);
    
  • Fabian 68 posts 171 karma points
    Sep 29, 2016 @ 18:49
    Fabian
    0

    Hi Rusty,

    Yes I am, I have implemented a custom one to integrate with klarna. I am pretty sure that attempt.Payment.Success returns true, since I have personally debugged it. Do you have any clue?

    Thanks

  • Rusty Swayne 1655 posts 4987 karma points c-trib
    Sep 29, 2016 @ 19:20
    Rusty Swayne
    0

    In the AuthorizeCapture method of the payment provider, the invoice should be marked as paid. Can you post the code to your PaymentMethod?

  • Fabian 68 posts 171 karma points
    Sep 30, 2016 @ 08:33
    Fabian
    0

    Hi Rusty what do you mean by the AuthorizeCapture method of the payment provider? Isn't that a method of merchello?

    When you are saying the PaymentMethod, which one you are to refering to exactly?

    Thanks

  • Fabian 68 posts 171 karma points
    Sep 30, 2016 @ 09:06
    Fabian
    0

    Hi Rusty,

    I think you were referring to one of these methods:

    /// <summary>
            /// Does the actual work of creating and processing the payment
            /// </summary>
            /// <param name="invoice">The <see cref="IInvoice"/></param>
            /// <param name="args">Any arguments required to process the payment.</param>
            /// <returns>The <see cref="IPaymentResult"/></returns>
            protected override IPaymentResult PerformAuthorizePayment(IInvoice invoice, ProcessorArgumentCollection args)
            {
                var payment = GatewayProviderService.CreatePayment(PaymentMethodType.PurchaseOrder, invoice.Total, PaymentMethod.Key);
                payment.CustomerKey = invoice.CustomerKey;
                payment.PaymentMethodName = PaymentMethod.Name;
                payment.ReferenceNumber = PaymentMethod.PaymentCode + "-" + invoice.PrefixedInvoiceNumber();
                payment.Collected = false;
                payment.Authorized = true;
    
                foreach (var arg in args)
                {
                    payment.ExtendedData.SetValue(arg.Key, arg.Value);
                }
    
                GatewayProviderService.Save(payment);
    
                // In this case, we want to do our own Apply Payment operation as the amount has not been collected -
                // so we create an applied payment with a 0 amount.  Once the payment has been "collected", another Applied Payment record will
                // be created showing the full amount and the invoice status will be set to Paid.
                var authorizedPaymentMsg = string.Format("Authorized payment of {0}. Klarna reservation number is {1}.", payment.Amount.ToString("C", new CultureInfo("sv-SE")), args["reservationNumber"]);
                GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, authorizedPaymentMsg, 0);
    
                return new PaymentResult(Attempt.Succeed(payment), invoice, true);
            }
    
            /// <summary>
            /// Does the actual work of authorizing and capturing a payment
            /// </summary>
            /// <param name="invoice">The <see cref="IInvoice"/></param>
            /// <param name="amount">The amount to capture</param>
            /// <param name="args">Any arguments required to process the payment.</param>
            /// <returns>The <see cref="IPaymentResult"/></returns>
            protected override IPaymentResult PerformAuthorizeCapturePayment(IInvoice invoice, decimal amount, ProcessorArgumentCollection args)
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// Does the actual work capturing a payment
            /// </summary>
            /// <param name="invoice">The <see cref="IInvoice"/></param>
            /// <param name="payment">The previously Authorize payment to be captured</param>
            /// <param name="amount">The amount to capture</param>
            /// <param name="args">Any arguments required to process the payment.</param>
            /// <returns>The <see cref="IPaymentResult"/></returns>
            protected override IPaymentResult PerformCapturePayment(IInvoice invoice, IPayment payment, decimal amount, ProcessorArgumentCollection args)
            {
                var reservationNumber = payment.ExtendedData.GetValue("reservationNumber");
                if (string.IsNullOrEmpty(reservationNumber))
                {
                    return new PaymentResult(Attempt<IPayment>.Fail(payment, new Exception("Failed to capture payment because no Klarna reservation number was found.")), invoice, false);
                }
    
                var invoiceNumber = _paymentProcessor.ActivateOrder(reservationNumber);
                if (invoiceNumber == null)
                {
                    return new PaymentResult(Attempt<IPayment>.Fail(payment), invoice, false);
                }
    
                payment.ExtendedData.SetValue("invoiceNumber", invoiceNumber);
    
                payment.Collected = true;
                GatewayProviderService.Save(payment);
    
                var capturedPaymentMsg = string.Format("Captured payment of {0}. Klarna invoice number is {1}.", payment.Amount.ToString("C", new CultureInfo("sv-SE")), invoiceNumber);
                GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, capturedPaymentMsg, amount);
    
                return new PaymentResult(Attempt<IPayment>.Succeed(payment), invoice, false);
            }
    

    I think now understand that the issue is because the PerformAuthorizeCapturePayment is not actually implemented. What do you think?

    Also how I can capture the payment only after authorizing it rather doing both at the same time? I couldn't find the right method in ICheckoutPaymentManager where there is the AuthorizePayment method.

    Thanks a lot for your support rusty.

  • Rusty Swayne 1655 posts 4987 karma points c-trib
    Sep 30, 2016 @ 15:48
    Rusty Swayne
    0

    I think your right - PerformAuthorizeCapturePayment would do it in a single shot - but I understand that is not what you're looking for.

    You're also correct that the CheckoutManager does not have a CapturePayment method. This is by design since the checkout manager is intended to do the work of getting the basket through the checkout process. Once an invoice is saved (meaning some sort of sale has occurred - even if it's just authorized) the CheckoutManager's job is done.

    So in your case, you will want to capture the payment directly from the invoice.

      var attempt = CheckoutManager.AuthorizePayment(...);
    
       // ... do whatever
    
      var invoice = attempt.Invoice;
    
       .... do whatever
    
      // This will execute your CapturePayment method in your PaymentProvider
      invoice.CapturePayment( .... );
    

    This is basically the same way it is done for paying later (cash payments, PO Numbers ... etc).

  • Fabian 68 posts 171 karma points
    Oct 03, 2016 @ 12:31
    Fabian
    0

    Thanks a lot for your support Rusty, very helpful.

  • Christian Hansen 14 posts 85 karma points
    Mar 15, 2019 @ 13:50
    Christian Hansen
    0

    I am sorry if I am hijacking this thread, but it seems like Fabian got it solved. But I have kind of the same problem. I made a custom QuickPay integration and creating the invoice before payment window, and after the payment is accepted I run the following code grabbing the invoice, but my order is not set to collected = 1 in the database, but it does get marked as Paid-CreditCard and is authorized = 1:

    var invoice = MerchelloContext.Current.Services.InvoiceService.GetByKey(Guid.Parse(invoiceKey));
            if (invoice == null)
            {
                throw new ApplicationException("Invoice null with order with ID \"" + secureOrderID + "\" ");
            }
            //invoice.InvoiceNumberPrefix = "FT";
            //Mark order as paid in system
    
            //Create payment
            var paymentMethodGateway = MerchelloContext.Current.Gateways.Payment.GetPaymentGatewayMethodByKey(Guid.Parse("D9E42E14-0FDA-4B05-838E-632D91950771"));
    
            Guid paymentMethodKey = Guid.Parse("D9E42E14-0FDA-4B05-838E-632D91950771");
            var paymentMethodName = "QuickPay";
            var payment = MerchelloContext.Current.Services.GatewayProviderService.CreatePayment(PaymentMethodType.CreditCard, 0, paymentMethodKey);
            payment.CustomerKey = invoice.CustomerKey;
            payment.PaymentMethodName = paymentMethodName;
            payment.ReferenceNumber = "QuickPay-" + invoice.PrefixedInvoiceNumber();
            payment.Collected = true;
            payment.Authorized = true;
    
            //Save invoice first
            MerchelloContext.Current.Services.InvoiceService.Save(invoice);
            //Save payment
            MerchelloContext.Current.Services.GatewayProviderService.Save(payment);
    
            var attempt = invoice.CapturePayment(payment, paymentMethodGateway, invoice.Total);
    
            if (attempt.Payment.Success)
            {
                payment.Collected = true;
                payment.Authorized = true;
    
                Merchello.Core.Notification.Trigger("OrderConfirmation", attempt, new[] { invoice.BillToEmail });
                UpdateInsertInDatabase("UPDATE customQuickPayOrderLog SET qpl_success = @qpl_success WHERE qpl_orderid = @QPOrderID",
                new object[,] { { "@qpl_success", true }, { "@QPOrderID", secureOrderID } });
            }
            else
            {
                throw new ApplicationException(attempt.Payment.Exception.ToString());
            }
    

    You have any idea what changes or addition has to be made to get it correctly collected = 1 in the database? Because as it is now in some places in the merchello system this does not count as a paid order and does not create discount codes used in the system as well.

    Best regards, Christian

Please Sign in or register to post replies

Write your reply to:

Draft