Copied to clipboard

Flag this post as spam?

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


  • Anton 135 posts 186 karma points
    Nov 01, 2015 @ 19:16
    Anton
    0

    Shipping address is empty

    I created Checkout controller, evething good, but I always have empty shipment address. Here code

    namespace Controllers
    

    { using System; using System.Web.Mvc; using Merchello.Core; using Merchello.Core.Gateways.Payment; using Merchello.Core.Models; using Merchello.Core.Services; using Merchello.Web; using Models; using Models.ViewModels; using Umbraco.Core; using Umbraco.Web.Mvc;

    /// <summary>
    /// Summary description for CheckoutController
    /// 
    /// Workflow
    /// 1. Display Basket Items http://website/checkout
    /// 2. Get Address information http://website/checkout/address
    /// 3. Get Payment information http://website/checkout/payment
    /// 4. Show Invoice http://website/checkout/invoice?inv=[machineEncryptedKey]
    /// </summary>
    [PluginController("MerchelloProductListExample")]
    public class CheckoutController : MerchelloSurfaceContoller
    {
    
        private const int BasketPageId = 1111;
        private const int PaymentInfoId = 1113;
        private const int ReceiptId = 1117;
    
        /// <summary>
        /// Merchello audit log to capture the error events
        /// 
        /// </summary>
        private AuditLogService _log = new AuditLogService();
    
        /// <summary>
        /// Constructor without current context
        /// </summary>
        public CheckoutController()
            : this(MerchelloContext.Current)
        { }
    
        /// <summary>
        /// Constructor with current context
        /// </summary>
        /// <param name="merchelloContext"></param>
        public CheckoutController(IMerchelloContext merchelloContext)
            : base(merchelloContext)
        { }
    
        /// <summary>
        /// Display address form - for this example shipping and billing are the same
        /// </summary>
        /// <param name="addressType"></param>
        /// <returns></returns>
        [ChildActionOnly]
        public ActionResult RenderAddressForm(AddressType addressType)
        {
            ViewBag.AddressType = addressType;
    
            return PartialView("Address");
        }
    
        /// <summary>
        /// Save address to both billing and shipping
        /// The anonymous customer address is stored in extended column
        /// on merchAnonymousCustomer
        /// 
        /// I save shipping address as an example. It isn't used anywhere since
        /// there isn't anything in the Order which is considered the Shippable
        /// piece of the process.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult SaveAddress(AddressModel model)
        {
            var address = model.ToAddress();
    
            // address saved to extended data on table merchAnonymousCustom
            Basket.SalePreparation().SaveBillToAddress(address);
            Basket.SalePreparation().SaveShipToAddress(address);
    
            return SavePayment();
    
            // go to payment page - only the cash payment is installed
            //return RedirectToUmbracoPage(PaymentInfoId);
        }
    
        /// <summary>
        /// Save payment is really process payment in this cash system. 
        /// As this system doesn't take credit cards, add tax, or ship, those
        /// pieces are purposely not shown.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
    
        public ActionResult SavePayment()
        {
            // has error occurred
            bool error = false;
    
            // do we raise events
            bool raiseEvents = false;
    
            // payment attempt result information
            IPaymentResult attempt = null;
            Guid paymentMethodGUID = new Guid("d37b53dd-78c6-40cd-969d-d1877c52de0e");
            // get payment method
            var paymentMethod = Payment.GetPaymentGatewayMethodByKey(paymentMethodGUID).PaymentMethod;
    
            // get customer, items
            var preparation = base.Basket.SalePreparation();
    
            // Save the payment method selection
            preparation.SavePaymentMethod(paymentMethod);
    
            // make sure there is a billing address - it can be empty - it just has to exist
            if (!preparation.IsReadyToInvoice()) return RedirectToUmbracoPage(BasketPageId);
    
            // AuthorizePayment will save the invoice with an Invoice Number.
            attempt = preparation.AuthorizePayment(paymentMethod.Key);
    
            // if payment isn't successful, grab some information
            if (!attempt.Payment.Success)
            {
                error = true;
    
                // TBD - Not in Merchello yet
                // Notification.Trigger("OrderConfirmationFailure", attempt, new[] { preparation.GetBillToAddress().Email });
    
                _log.CreateAuditLogWithKey("Checkout failed - attempt payment failure", preparation.Customer.ExtendedData);
            }
            else
            {
                // trigger the order notification confirmation
                Notification.Trigger("OrderConfirmation", attempt, new[] { preparation.GetBillToAddress().Email });
            }
    
            // grab final content page
            var receipt = Umbraco.TypedContent(ReceiptId);
    
            // redirect so that url has invoice number (encrypted) in address bar
            // this feels clunky and unsafe but illustrative all the same
            return
                Redirect(string.Format("{0}?inv={1}", receipt.Url,
                                       attempt.Invoice.Key.ToString().EncryptWithMachineKey()));
        }
    
        /// <summary>
        /// Render Receipt - sale has been processed
        /// </summary>
        /// <param name="invoiceKey"></param>
        /// <returns></returns>
        [ChildActionOnly]
        public ActionResult RenderReceipt(string invoiceKey)
        {
            Guid key;
            if (Guid.TryParse(invoiceKey, out key))
            {
                var invoice = Services.InvoiceService.GetByKey(key);
                return PartialView("CheckoutInvoice", invoice);
            }
            throw new InvalidOperationException();
        }
    
        /// <summary>
        /// Render Invoice (name, address, items, total)
        /// </summary>
        /// <param name="invoice"></param>
        /// <returns></returns>
        private ActionResult RenderInvoice(IInvoice invoice)
        {
            return PartialView("CheckoutInvoice", invoice);
        }
    
        /// <summary>
        /// When the payment is successful (i.e. Sale is complete)
        /// the basket is empty again. So decide if we are getting 
        /// information from basket or invoice
        /// </summary>
        /// <returns></returns>
        public ActionResult RenderInvoiceSummary(bool dataFromInvoice, Guid invoiceKey)
        {
            if (!dataFromInvoice)
            {
                return RenderIncompleteInvoiceSummary();
            }
            else
            {
                return RenderCompleteInvoiceSummary(invoiceKey);
            }
    
        }
    
        /// <summary>
        /// Renders checkout information in process so
        /// gets everything from basket
        /// </summary>
        /// <returns></returns>
        private ActionResult RenderIncompleteInvoiceSummary()
        {
    
            var model = new CheckoutViewModel();
    
            if ((base.Basket != null) &&
                (base.Basket.SalePreparation() != null))
            {
                if (base.Basket.SalePreparation().GetBillToAddress() != null)
                {
                    model.CustomerName = base.Basket.SalePreparation().GetBillToAddress().Name ?? "";
    
                    model.CustomerAddress = new AddressModel();
    
                    model.CustomerAddress.Email = base.Basket.SalePreparation().GetBillToAddress().Email ?? "";
                    model.CustomerAddress.Address1 = base.Basket.SalePreparation().GetBillToAddress().Address1 ?? "";
                    model.CustomerAddress.Locality = base.Basket.SalePreparation().GetBillToAddress().Locality ?? "";
                    model.CustomerAddress.CountryCode = base.Basket.SalePreparation().GetBillToAddress().CountryCode ?? "";
                    model.CustomerAddress.PostalCode = base.Basket.SalePreparation().GetBillToAddress().PostalCode ?? "";
                    model.CustomerAddress.Region = base.Basket.SalePreparation().GetBillToAddress().Region ?? "";
                }
    
                if (base.Basket.SalePreparation().GetPaymentMethod() != null)
                {
                    model.PaymentType = base.Basket.SalePreparation().GetPaymentMethod().Name ?? "";
                }
    
                if (base.Basket.Items != null)
                {
                    model.Items = base.Basket.Items;
                }
    
                model.TotalBasketPrice = base.Basket.TotalBasketPrice;
            }
    
    
            return PartialView("CheckoutSummary", model);
        }
        /// <summary>
        /// Renders checkout information after sale is done, so gets
        /// everything from invoice. Basket is now empty once again.
        /// </summary>
        /// <param name="invoiceKey"></param>
        /// <returns></returns>
        private ActionResult RenderCompleteInvoiceSummary(Guid invoiceKey)
        {
    
            var invoice = Services.InvoiceService.GetByKey(invoiceKey);
    
            var model = new CheckoutViewModel();
    
            // init objects
            model.CustomerAddress = new AddressModel();
            model.Items = new LineItemCollection();
    
            var customeraddress = new AddressModel();
    
            model.CustomerName = invoice.BillToName ?? "";
    
            customeraddress.Email = invoice.BillToEmail ?? "";
            customeraddress.Address1 = invoice.BillToAddress1 ?? "";
            customeraddress.Locality = invoice.BillToLocality ?? "";
            customeraddress.CountryCode = invoice.BillToCountryCode ?? "";
            customeraddress.PostalCode = invoice.BillToPostalCode ?? "";
            customeraddress.Region = invoice.BillToRegion ?? "";
    
            model.CustomerAddress = customeraddress;
    
            //model.PaymentType = invoice.;
    
            model.Items = invoice.Items;
            model.TotalBasketPrice = invoice.Total;
    
            return PartialView("CheckoutSummary", model);
        }
    }
    

    }

  • Anton 135 posts 186 karma points
    Nov 01, 2015 @ 19:17
    Anton
    0

    In Partial view I have

    @{
    var loginStatusModel = Members.GetCurrentLoginStatus();
    string userName = "";
    string userCompany = "";
    string userEmail = "";
    string userAddress = "";
    string userCity = "";
    string userState = "";
    string userZipCode = "";
    
    
    if(loginStatusModel.IsLoggedIn)
    {
        userName = loginStatusModel.Name + " " + Members.GetCurrentMember().GetProperty("umbracoMemberLastName").Value.ToString();
        userCompany = Members.GetCurrentMember().GetProperty("umbracoMemberCompany").Value.ToString();
        userEmail = loginStatusModel.Email;
        userAddress = Members.GetCurrentMember().GetProperty("umbracoMemberAddress").Value.ToString();
        userCity = Members.GetCurrentMember().GetProperty("umbracoMemberCity").Value.ToString();
        userState = Members.GetCurrentMember().GetProperty("umbracoMemberState").Value.ToString();
        userZipCode = Members.GetCurrentMember().GetProperty("umbracoMemberZipCode").Value.ToString();
    }
    

    }

                            <td style="width:20%;">Address</td>
                            <td style="width:80%;">
                                @Html.TextBoxFor(x => x.Address1, new {@class="form-control", @Value = @userAddress })
                            </td>
                        </tr>
                        <tr>
                            <td>City</td>
                            <td>
                                @Html.TextBoxFor(x => x.Locality, new {@class="form-control", Placeholder = "City", @Value = @userCity })
                            </td>
                        </tr>
                        <tr>
                            <td>State</td>
                            <td>
                                @Html.TextBoxFor(x => x.Region, new {@class="form-control", Placeholder = "State", @Value = @userState })
                            </td>
                        </tr>
                        <tr>
                            <td>Zip</td>
                            <td>
                                @Html.TextBoxFor(x => x.PostalCode, new {@class="form-control", Placeholder = "Postal or Zip Code", @Value = @userZipCode })
                            </td>
                        </tr>
                    </tbody>
                </table>
    
                @Html.HiddenFor(x => x.Name, new { @Value = @userName })
                @Html.HiddenFor(x => x.Email, new { @Value = @userEmail })
                @Html.HiddenFor(x => x.Organization, new { @Value = @userCompany })
                @Html.HiddenFor(x => x.CountryCode, new { @Value = "US" })
    
            </div>
    

  • Anton 135 posts 186 karma points
    Nov 01, 2015 @ 19:21
    Anton
    0

    Why this don`t works?

     Basket.SalePreparation().SaveBillToAddress(address);
     Basket.SalePreparation().SaveShipToAddress(address);
    

    I checked value address and it is not empty and AddressType=Shipping

  • Anton 135 posts 186 karma points
    Nov 02, 2015 @ 16:45
    Anton
    0

    I found solution, I didn`t add this function

    private void SaveApprovedShipmentRateQuote(Guid shipMethodKey) { // if (!ModelState.IsValid) return CurrentUmbracoPage();

            var shippingAddress = Basket.SalePreparation().GetShipToAddress();
          //  if (shippingAddress == null) return RedirectToUmbracoPage(GetContentIdByContentName(ShipRateQuotePage));
    
            // Get the shipment again
            var shipment = Basket.PackageBasket(shippingAddress).FirstOrDefault();
    
            // Clear any previously saved quotes (eg. the user went back to their basket and started the process over again).
            Basket.SalePreparation().ClearShipmentRateQuotes();
    
            // get the quote using the "approved shipping method"
            var quote = shipment.ShipmentRateQuoteByShipMethod(shipMethodKey);
    
            // save the quote
            Basket.SalePreparation().SaveShipmentRateQuote(quote);
    
           // return SavePayment(); // Proceed to step 3
        }
    
  • Rusty Swayne 1655 posts 4993 karma points c-trib
    Nov 02, 2015 @ 21:37
    Rusty Swayne
    0

    @Anton - exactly correct.

    You can think of the the SaveShipToAddress method as basically a temporary storage mechanism for holding the address as you progress through the checkout workflow.

    When you create a shipment, the address becomes the destination address for the shipment which is then serialized and added to the shipment line item of the invoice when created. This is so the original quote can be compared to the actual shipping cost, if for example the order was later broken into more than a single shipment , for example in a back order situation.

  • Tito 314 posts 623 karma points
    Dec 16, 2015 @ 13:31
    Tito
    0

    @Rusty I dont know what happens in my case, shipping address is cleaned. I am working on a Paypal controller. This is my code with comments of the issue:

        var preparation = Basket.SalePreparation();
        preparation.RaiseCustomerEvents = false;
    
                // Clear any previously saved quotes (eg. the user went back to their basket and started the process over again).
                    preparation.ClearShipmentRateQuotes();
    
                    var shippingAddress = Basket.SalePreparation().GetShipToAddress();
    
    //Here shippingAddress has all the shipping fields filled OK
    
                    // Get the shipment again
                    var shipment = Basket.PackageBasket(shippingAddress).FirstOrDefault();
    
    //Here shipment has all the fields unfilled
    
    //Its weird because the only fiels filled are FromName ("Default Warehouse") and "Phone" field
    
    
    
                    //Filling again the lost values
                    shipment.FromName = shippingAddress.Name;
                    shipment.FromAddress1 = shippingAddress.Address1;
                    shipment.FromAddress2 = shippingAddress.Address2;
                    shipment.FromCountryCode = shippingAddress.CountryCode;
                    shipment.FromIsCommercial = shippingAddress.IsCommercial;
                    shipment.FromLocality = shippingAddress.Locality;
                    shipment.FromOrganization = shippingAddress.Organization;
                    shipment.FromPostalCode = shippingAddress.PostalCode;
                    shipment.FromRegion = shippingAddress.Region;
                    shipment.Phone = shippingAddress.Phone;
    
    
    
    
                    // get the quote using the "approved shipping method"
                    var quote = shipment.ShipmentRateQuoteByShipMethod(model.ShipMethodKey);
    
        //quote.Shippment has all the fields unfilled again
    
                    // save the quote
                    Basket.SalePreparation().SaveShipmentRateQuote(quote);
    
  • Rusty Swayne 1655 posts 4993 karma points c-trib
    Dec 17, 2015 @ 17:02
    Rusty Swayne
    0

    Is the shipment null or just the destination address in the shipment? If the shipment is null it could be that the country code was not recognized ...

    Other than that, there must be something else going on in the application as the address is readonly in the packaging strategy.

    https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Core/Strategies/Packaging/DefaultWarehousePackagingStrategy.cs

    passed to base:

    https://github.com/Merchello/Merchello/blob/merchello-dev/src/Merchello.Core/Strategies/Packaging/PackagingStrategyBase.cs

  • Tito 314 posts 623 karma points
    Dec 17, 2015 @ 17:35
    Tito
    0

    @Rusty "shipment" is not null, it has all the fields blank but FromName ("Default Warehouse") and "Phone" field with the phone entered.

    May it be something about the cache on basket? i call the method from angularjs after calling save address from angularjs too. But its weird because "shippingAddress" object has all the fields filled...

    Its like the Basket.PackageBasket is not copying the fields from shippingAdress object to shipment object.

    And after manually filling them (as you can see in my code), calling to ShipmentRateQuoteByShipMethod copies the shipment to quote.Shipment but not the values. ¿?

  • Rusty Swayne 1655 posts 4993 karma points c-trib
    Dec 17, 2015 @ 20:42
    Rusty Swayne
    0

    Try using the overload of ShipmentRateQuoteByShipMethod with the cache parameter set to false. Depending on what you have going on the aysnc calls, it may be the quote (and thus the shipment in the quote) is being cached and never updating .

  • Markus Johansson 1911 posts 5735 karma points MVP c-trib
    Nov 20, 2016 @ 12:00
    Markus Johansson
    0

    Worked for me as well - man what I've been trying to fix this issue. One would think that shippingManager.ClearShipmentRateQuotes(); would clear stuff out?

  • Rusty Swayne 1655 posts 4993 karma points c-trib
    Nov 21, 2016 @ 17:03
    Rusty Swayne
    0

    ClearShipmentRateQuotes() should clear it out ... I'll have to add some tests to confirm that.

  • Tito 314 posts 623 karma points
    Dec 18, 2015 @ 09:06
    Tito
    0

    Thanks @Rusty, that made the trick!

Please Sign in or register to post replies

Write your reply to:

Draft