public ActionResult Review(CheckoutViewModel model) { // In this step the user will be able to review their order, and finally go ahead // and finalize. We may want to have a null payment provider for free stuff? var user = _workContextAccessor.GetContext().CurrentUser; if (!_checkoutHelperService.UserMayCheckout(user, out ActionResult redirect)) { if (redirect != null) { return(redirect); } return(Redirect(RedirectUrl)); } // Try to fetch the model from TempData to handle the case where we have been // redirected here. if (TempData.ContainsKey("CheckoutViewModel")) { model = (CheckoutViewModel)TempData["CheckoutViewModel"]; } // decode stuff that may be encoded ReinflateViewModelAddresses(model); model.ShippingRequired = IsShippingRequired(); if (model.ShippingRequired && model.SelectedShippingOption == null) { if (string.IsNullOrWhiteSpace(model.ShippingOption)) { // Here we need a selected shipping method, but we don't have it somehow // so we redirect back to shipping selection // Put the model in TempData so it can be reused in the next action. // This is an attempt to skip shipping, so try to shortcircuit. model.UseDefaultShipping = true; TempData["CheckoutViewModel"] = model; return(RedirectToAction("Shipping")); } var selectedOption = ShippingService.RebuildShippingOption(model.ShippingOption); _shoppingCart.ShippingOption = selectedOption; model.SelectedShippingOption = selectedOption; } // We will need to display: // 1. The summary of all the user's choices up until this point. // (that's already in the model) // 2. The list of buttons for the available payment options. model.PosServices = _posServices; // encode addresses so we can hide them in the form model.EncodeAddresses(); // make sure services are injected so they may be used InjectServices(model); return(View(model)); }
public ActionResult Shipping(CheckoutViewModel model) { // In this step the user will select the shipping method from a list var user = _workContextAccessor.GetContext().CurrentUser; if (!_checkoutHelperService.UserMayCheckout(user, out ActionResult redirect)) { if (redirect != null) { return(redirect); } return(Redirect(RedirectUrl)); } // Try to fetch the model from TempData to handle the case where we have been // redirected here. if (TempData.ContainsKey("CheckoutViewModel")) { model = (CheckoutViewModel)TempData["CheckoutViewModel"]; } // Check if the mail returned an error: "A shipment has not been selected" if (TempData.ContainsKey("ShippingError")) { ModelState.AddModelError("_FORM", TempData["ShippingError"].ToString()); } // deserialize addresses ReinflateViewModelAddresses(model); model.ShippingRequired = IsShippingRequired(); if (model.ShippingAddressVM != null) { var productQuantities = _shoppingCart .GetProducts() .Where(p => p.Quantity > 0) .ToList(); // Hack: based on the address coming in model.ShippingAddressVM, we can // compute the actual destinations to be used at this stage var country = _addressConfigurationService ?.GetCountry(model.ShippingAddressVM.CountryId); var countryName = country ?.Record?.TerritoryInternalRecord.Name; // we should make sure that the country name is filled in for the shipping // address view model, so we can display it. if (string.IsNullOrWhiteSpace(model.ShippingAddressVM.Country)) { model.ShippingAddressVM.Country = _contentManager.GetItemMetadata(country).DisplayText; } // get all possible providers for shipping methods var shippingMethods = _shippingMethodProviders .SelectMany(p => p.GetShippingMethods()) .ToList(); // Test those providers with nwazet's default interface. var allShippingOptions = ShippingService .GetShippingOptions( shippingMethods, productQuantities, countryName, model.ShippingAddressVM.PostalCode, _workContextAccessor).ToList(); // Those tests done like that cannot be very reliable with respect to // territories' configuration, unless we configure a hierarchy of postal // codes. Rather than do that, we are going to do an hack on the PostalCode // that will let a shipping criterion parse out the territory Ids. allShippingOptions .AddRange(ShippingService .GetShippingOptions( shippingMethods, productQuantities, countryName, $"{model.ShippingAddressVM.PostalCode};" + $"{model.ShippingAddressVM.CountryId};" + $"{model.ShippingAddressVM.ProvinceId};" + $"{model.ShippingAddressVM.CityId}", _workContextAccessor)); // remove duplicate shipping options model.AvailableShippingOptions = allShippingOptions.Distinct(new ShippingOption.ShippingOptionComparer()).ToList(); // See whether we are trying to short circuit the checkout steps if (model.UseDefaultShipping) { // if there is no option selected, and there is only one possible option, we can skip // the selection. If the user is trying to reset their selection, there is a selected // option so it should not trigger this condition if (string.IsNullOrWhiteSpace(model.ShippingOption) && model.AvailableShippingOptions.Count == 1) { model.ShippingOption = model.AvailableShippingOptions.First().FormValue; return(ShippingPOST(model)); } } // to correctly display prices, the view will need the currency provider model.CurrencyProvider = _currencyProvider; // encode addresses so we can hide them in the form model.EncodeAddresses(); // make sure services are injected so they may be used InjectServices(model); return(View(model)); } // to get here something must have gone very wrong. Perhaps the user // is trying to select a shipping method where no shipping is required. // More likely, a refresh of the shipping page messed things up for us. // Either way, go through the index in an attempt to properly repopulate // the addresses model.UseDefaultAddress = true; // Put the model in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; return(RedirectToAction("Index")); }