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 ShippingPOST(CheckoutViewModel model) { // validate the choice of shipping method then redirect to the action that lets // the user review their order. var user = _workContextAccessor.GetContext().CurrentUser; if (!_checkoutHelperService.UserMayCheckout(user, out ActionResult redirect)) { if (redirect != null) { return(redirect); } return(Redirect(RedirectUrl)); } // Addresses come from the form as encoded in a single thing, because at // this stage the user will have already selected them earlier. ReinflateViewModelAddresses(model); // check if the user is trying to reset the selected shipping option. if (model.ResetShipping || string.IsNullOrWhiteSpace(model.ShippingOption)) { // Put the model we validated in TempData so it can be reused in the next action. _shoppingCart.ShippingOption = null; TempData["CheckoutViewModel"] = model; // used tempdata because doing the "redirecttoaction" doesn't keep the modelstate value saved // it is an error only if I am not doing a reset shipping, // because if I am doing a reset shipping it is normal for the shipping options to be null if (!model.ResetShipping) { TempData["ShippingError"] = T("Select a shipment to proceed with your order").Text; } return(RedirectToAction("Shipping")); } // the selected shipping option if (string.IsNullOrWhiteSpace(model.ShippingOption)) { // TODO: they selected no shipping! // redirect them somewhere } var selectedOption = ShippingService.RebuildShippingOption(model.ShippingOption); _shoppingCart.ShippingOption = selectedOption; model.SelectedShippingOption = selectedOption; model.ShippingRequired = IsShippingRequired(); // Put the model in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; return(RedirectToAction("Review")); }
public void ShippingOptionCanBeRoundTripped() { var cart = new[] { new ShoppingCartQuantityProduct(1, new ProductStub { Weight = 3 }) }; var shippingMethod1 = ShippingHelpers.BuildWeightBasedShippingMethod(price: 3); shippingMethod1.Name = "Shipping method 1"; shippingMethod1.ShippingCompany = "Vandelay Import/Export"; shippingMethod1.ExcludedShippingAreas = "a,b"; shippingMethod1.IncludedShippingAreas = "c,d,e"; var shippingMethod2 = ShippingHelpers.BuildWeightBasedShippingMethod(price: 7); shippingMethod2.Name = "Shipping method 2"; shippingMethod2.ShippingCompany = "Northwind Shipping"; shippingMethod2.ExcludedShippingAreas = "f,g,h"; shippingMethod2.IncludedShippingAreas = "i,j"; var shippingMethods = new[] { shippingMethod1, shippingMethod2 }; var validMethods = ShippingService.GetShippingOptions(shippingMethods, cart, null, null, null).ToList(); var firstOption = ShippingService.RebuildShippingOption(validMethods.First().FormValue); Assert.That(firstOption.Description, Is.EqualTo(shippingMethod1.Name)); Assert.That(firstOption.Price, Is.EqualTo(3)); Assert.That(firstOption.ShippingCompany, Is.EqualTo(shippingMethod1.ShippingCompany)); Assert.That(String.Join(",", firstOption.ExcludedShippingAreas), Is.EqualTo(shippingMethod1.ExcludedShippingAreas)); Assert.That(String.Join(",", firstOption.IncludedShippingAreas), Is.EqualTo(shippingMethod1.IncludedShippingAreas)); var secondOption = ShippingService.RebuildShippingOption(validMethods.Skip(1).First().FormValue); Assert.That(secondOption.Description, Is.EqualTo(shippingMethod2.Name)); Assert.That(secondOption.Price, Is.EqualTo(7)); Assert.That(secondOption.ShippingCompany, Is.EqualTo(shippingMethod2.ShippingCompany)); Assert.That(String.Join(",", secondOption.ExcludedShippingAreas), Is.EqualTo(shippingMethod2.ExcludedShippingAreas)); Assert.That(String.Join(",", secondOption.IncludedShippingAreas), Is.EqualTo(shippingMethod2.IncludedShippingAreas)); }
public ActionResult ReviewPOST(CheckoutViewModel model) { // redirect the user to their payment method of choice // is there any validation that should be happening here? var user = _workContextAccessor.GetContext().CurrentUser; if (!_checkoutHelperService.UserMayCheckout(user, out ActionResult redirect)) { if (redirect != null) { return(redirect); } return(Redirect(RedirectUrl)); } if (string.IsNullOrWhiteSpace(model.SelectedPosService)) { // the user selected no payment method _notifier.Error(T("Impossible to start payment with the selected provider. Please try again.")); TempData["CheckoutViewModel"] = model; return(RedirectToAction("Review")); } // get the pos by name var selectedService = _posServices .FirstOrDefault(ps => ps.GetPosName() .Equals(model.SelectedPosService, StringComparison.OrdinalIgnoreCase)); if (selectedService == null) { // data got corrupted? _notifier.Error(T("Impossible to start payment with the selected provider. Please try again.")); TempData["CheckoutViewModel"] = model; return(RedirectToAction("Review")); } // Re-validate the entire model to be safe ReinflateViewModelAddresses(model); // later we'll need the country and postal code var countryName = !string.IsNullOrWhiteSpace(model.ShippingAddressVM?.Country) ? model.ShippingAddressVM?.Country : (!string.IsNullOrWhiteSpace(model.BillingAddressVM?.Country) ? model.BillingAddressVM?.Country : ""); _shoppingCart.Country = countryName; var postalCode = model.ShippingAddressVM != null ? model.ShippingAddressVM.PostalCode : model.BillingAddressVM.PostalCode; _shoppingCart.ZipCode = postalCode; // Validate ShippingOption model.ShippingRequired = IsShippingRequired(); if (model.ShippingRequired && model.SelectedShippingOption == null) { if (string.IsNullOrWhiteSpace(model.ShippingOption)) { // TODO: manage this error condition // Here we need a selected shipping method, but we don't have it somehow } // TODO: check this: we are reinflating from the model but maybe we have // this in _shoppingCart? var selectedOption = ShippingService.RebuildShippingOption(model.ShippingOption); _shoppingCart.ShippingOption = selectedOption; model.SelectedShippingOption = selectedOption; } // TODO: Validate Cart // Here we want to: // 1. Create the PayementGatewayCharge we'll use for events var paymentGuid = Guid.NewGuid().ToString(); // 2. Create the Order ContentItem var order = _checkoutHelperService.CreateOrder(model.AsAddressesVM(), paymentGuid, countryName, postalCode); // 3. Don't attach the address from the Order to the Contact for // the user, because that was done when inputing the address. // 3.1. If there is a User, we may wish to add their email and phone // number to the Contact. // 4. Create the payment record for the Order. var reason = string.Format("Purchase Order {0}", order.OrderKey); var payment = new PaymentRecord { Reason = reason, Amount = order.Total, Currency = order.CurrencyCode, ContentItemId = order.Id }; // 4.1. Invoke the StartPayment method for the selected IPosService. payment = selectedService.StartPayment(payment, paymentGuid); // 5. Get form the IPosService the controller URL and redirect there. // Put the model in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; return(Redirect(selectedService.GetPosActionUrl(payment.Guid))); }
public ActionResult Update( UpdateShoppingCartItemViewModel[] items, string country = null, string zipCode = null, string shippingOption = null) { _shoppingCart.Country = country; _shoppingCart.ZipCode = zipCode; _shoppingCart.ShippingOption = String.IsNullOrWhiteSpace(shippingOption) ? null : ShippingService.RebuildShippingOption(shippingOption); if (items != null) { UpdateShoppingCart(items.Reverse()); } return(RedirectToAction("Index")); }