Copied to clipboard

Flag this post as spam?

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


  • Gustav Malmström 4 posts 84 karma points
    1 week ago
    Gustav Malmström
    0

    Invoice items missing in second order

    Hi!

    I'm setting up a simple webshop using Umbraco and Merchello for the first time. For now, the checkout is made in one step where the anonymous customer enters shipping- and billing information in a form and just confirms the order.

    Everything works great the first time I complete the checkout process. However, if I then go back to the products page, add a few items to the basket and then try to checkout again the items are never added to the invoice. Only shipment rate and a tax item with value 0 is added. Is this something related to caching or am I just missing something in the checkout-process?

    Here is my Checkout action:

    [HttpPost]
        public ActionResult Checkout(CustomerInfoViewModel model)
        {
            if (!ModelState.IsValid)
                return CurrentUmbracoPage();
    
            var checkoutManager = Basket.GetCheckoutManager();
    
            //Create adresses
            var billingAddress = new Address
            {
                Name = model.BillingName,
                Address1 = model.BillingAddress,
                PostalCode = model.BillingZipCode,
                Locality = model.BillingCity,
            };
    
            var shippingAddress = new Address
            {
                Name = model.Name,
                Email = model.Email,
                Address1 = model.Street,
                PostalCode = model.ZipCode,
                Locality = model.City
    
            };
    
            //Set billingadress
            if (!string.IsNullOrEmpty(billingAddress.Address1) &&
                !string.IsNullOrEmpty(billingAddress.PostalCode) &&
                !string.IsNullOrEmpty(billingAddress.Locality))
            {
                checkoutManager.Customer.SaveBillToAddress(billingAddress);
            }
            else
            {
                checkoutManager.Customer.SaveBillToAddress(shippingAddress);
            }
    
            //Set shippingaddress
            checkoutManager.Customer.SaveShipToAddress(shippingAddress);
    
            var shipment = Basket.PackageBasket(shippingAddress).FirstOrDefault();
            if (shipment != null)
            {
                //Create invoice
                var invoice = checkoutManager.Payment.PrepareInvoice();
    
                //Add shipment to invoice
                var shipmentRateQuotes = shipment.ShipmentRateQuotes().ToList();
                if (shipmentRateQuotes.Count > 0 )
                {                
                    checkoutManager.Shipping.SaveShipmentRateQuote(shipmentRateQuotes.First());
                }
            }
    
            //Payment
            var paymentMethod = MerchelloContext.Current.Gateways.Payment.GetPaymentGatewayMethods().FirstOrDefault(p => p.PaymentMethod?.Name == _paymentMethod);
            if (paymentMethod != null)
            {
                var payment = checkoutManager.Payment.AuthorizePayment(paymentMethod);
                //var payment = invoice.AuthorizePayment(paymentMethod);
                if (payment.Payment.Success)
                {
                    //Add note to invoice if anything to add
                    if (!string.IsNullOrEmpty(model.Message))
                    {
                        var invoiceAgain = MerchelloServices.InvoiceService.GetByKey(payment.Invoice.Key);
                        if (invoiceAgain != null)
                        {
                            var note = MerchelloServices.NoteService.CreateNote(invoiceAgain.Key, EntityType.Invoice, model.Message);
                            note.CreateDate = DateTime.Now;
                            note.InternalOnly = false;
                            note.Author = shippingAddress.Name;
    
                            invoiceAgain.Notes = new List<INote> { note };
    
                            MerchelloServices.NoteService.Save(note);
    
                            //Must re-save the invoice to add the note
                            MerchelloServices.InvoiceService.Save(invoiceAgain);
                        }
                    }
    
                    Notification.Trigger("OrderConfirmation", payment, new List<string>{ model.Email });
    
                    //Store invoiceKey on Customer for reciept generation
                    CustomerContext.SetValue("invoiceKey", payment.Invoice.Key.ToString());
                }
            }
    
            return RedirectToCurrentUmbracoPage();
        }
    

    Any help would be very appreciated! :)

  • Rusty Swayne 1627 posts 4839 karma points c-trib
    1 week ago
    Rusty Swayne
    0

    Hey Gustav,

    There should not be any caching issues in the checkout process. The cache keys is generated using a "version key" (generated GUID) each time the basket is saved - so if you have started a checkout, or modify the basket in any way (quantity, new line item, remove a line item ... etc.) a new version key is generated which invalidates any current checkout. The CheckoutContextSettings are used when the CheckoutManager resets when the version key check fails or a checkout has been completed - in otherwords the process should be starting over completely.

    I don't see anything in the code snippet that immediately jumps out that would affect this behavior - but there are a couple of areas you could put break points and figure out what is going on.

    In the following snippet you could put a break point on the line where you are preparing the invoice and check if the items have been added.

    Note: Preparing the invoice here is not necessary. PrepareInvoice is typically used to show the customer a preview of what is going to be billed. This call is done internally in the AuthorizePayment process.

      var shipment = Basket.PackageBasket(shippingAddress).FirstOrDefault();
        if (shipment != null)
        {
            //Create invoice
            var invoice = checkoutManager.Payment.PrepareInvoice();
    
            //Add shipment to invoice
            var shipmentRateQuotes = shipment.ShipmentRateQuotes().ToList();
            if (shipmentRateQuotes.Count > 0 )
            {                
                checkoutManager.Shipping.SaveShipmentRateQuote(shipmentRateQuotes.First());
            }
        }
    

    You should not need to add the notes after the invoice is created. This can be done through the CheckoutManager directly.

    Before you Authorize the payment try:

       checkoutManager.Extended.AddNote(model.Message);
    

    The only difference should be that the BillingAddress email address value would be used as the note.Author.

    -- back to the issue --

    Can you confirm that your basket page implementation is working after the first checkout? e.g. You can adjust quantities and add/remove items.

    Are there any errors in the logs when you try to checkout a second time?

  • Gustav Malmström 4 posts 84 karma points
    1 week ago
    Gustav Malmström
    0

    Hi Rusty,

    Thanks for your reply! I've done some debugging of the Checkout action and it seems like the products are never added to the checkoutManager.Context.ItemCache.Items list in the second order. Here's some more info on what's going on:

    When checking out the first time the checkoutManager.Context is flagged as IsNew = true, VersionKey = {8d3a35d9-92a5-4a8c-b2e7-bafd0953e2f8}. The ItemCache.Items contains the products.

    After the call to PackageBasket the shipment.Items contains the products. When the Payment is authorized the paymen.Invoice.Items contains the products, 1 Tax item and 1 shipment rate item.

    The confirmation email is sent and the basket is cleared. A sales-item is generated and contains all expected info.

    If I go back to the products page now I can add new products to the basket. When checking out again out after this the checkoutManager.Context is not flagged as new, IsNew = false, VersionKey = {e18a0923-2183-48c8-b999-298150e63d1a}. The Context.ItemChache.Items contains 0 items.

    After the call to PackageBasket the shipment.Items contains the products. When the payment is authorized the payment.Invoice.Items only contains 1 Tax item (amount 0) and 1 shipment rate item.

    The confirmation email is sent and the basket is cleared. A sales-item is generated and contains all info except the products.

    There are no errors in the logs. Any idea what's happening? Is everything related to a "shopping-session" cleared internally when the payment is authorized or am I supposed to do anything to mark the checkout process as complete?

  • Rusty Swayne 1627 posts 4839 karma points c-trib
    1 week ago
    Rusty Swayne
    0

    Everything should be cleared internally - but maybe that's the issue in your workflow, just trying to figure out how that would be possible....

    The context is actually created here:
    https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Core/Checkout/CheckoutContext.cs#L228

    It may be that an ItemCache object is found in the runtime cache and the method is returning early with an instance of the CheckoutContext based on the cached version. This would explain the IsNewVersion being false, but would not explain no product line items as I'd expect it would contain the items from the previous order ...

    The CheckoutManager is reset after a successful payment: https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web/UmbracoApplicationEventHandler.cs#L441

    Depending on your context settings, this will clear things like the addresses, notes, ship rate quotes, etc.

    I've verified the event is getting raised for AuthorizePayment:
    https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Web/CheckoutManagers/BasketCheckoutPaymentManager.cs#L90

    And you mentioned that your notification was sending so the payment result is returning a success - this is checked when clearing the CheckoutManager as well so that is unlikely causing the issue.

    Things to try

    Verify that the Basket version key is equal to the ItemCache version key AND that the version key has changed from the first order to the second (should never be the same).

    Verify that the ItemCache has items immediately after the
    var checkoutManager = Basket.GetCheckoutManager();

    What base class are you using for your controller? Are you using one of Merchello's or a custom implementation? Thinking about the Basket property here ...

  • Gustav Malmström 4 posts 84 karma points
    6 days ago
    Gustav Malmström
    0

    The Basket version key is equal to the ItemCache version key in both orders and changes between the orders. So far so good. However, the ItemCache has 0 items in the second order. The Basket contains the items but the checkoutManager.Context.ItemCache does not.

    I use Merchello's base classes for my controllers. MerchelloRenderMvcController for the Checkout page controller and MerchelloSurfaceController for the checkout form controller where the Checkout action i posted earlier is implemented.

    This is how the items are added to the basket:

    public class ShopController : MerchelloSurfaceController
    {
        [HttpPost]
        public ActionResult AddToCart(ProductViewModel product, string buyProduct)
        {
            try
            {
                Guid productId;
    
                if (Guid.TryParse(buyProduct, out productId))
                {
                    var helper = new MerchelloHelper(false);
    
                    var item = helper.Query.Product.GetByKey(productId);
                    if (item != null)
                    {
                        Basket.AddItem(item, item.Name, 1);
                    }
                }
            }
            catch (Exception e)
            {
                //TODO: Log
                throw;
            }
    
            return RedirectToCurrentUmbracoPage();
        }
    }
    
  • Rusty Swayne 1627 posts 4839 karma points c-trib
    5 days ago
    Rusty Swayne
    100

    Try adding Basket.Save() after adding the item.

  • Gustav Malmström 4 posts 84 karma points
    5 days ago
    Gustav Malmström
    0

    Yes, saving the basket dit the trick! Now every order contains the expected items.

    How come it worked for the first order but not the following ones when I just added to the basket without saving?

    Thank you so much for helping me out!

  • Rusty Swayne 1627 posts 4839 karma points c-trib
    4 days ago
    Rusty Swayne
    0

    It's probably technically an error - what I think was probably happening is the items were being persisted in the runtime cache and not the database (until save is called).

Please Sign in or register to post replies

Write your reply to:

Draft