public JsonResult GetCities(ConfigurationRequestViewModel viewModel) { var country = _addressConfigurationService.GetCountry(viewModel.CountryId); if (country == null) { // this is an error } else { var cities = _addressConfigurationService.GetAllCities( viewModel.IsBillingAddress ? AddressRecordType.BillingAddress : AddressRecordType.ShippingAddress, country); return(Json(new { Success = true, Cities = cities .Select(tp => new { Value = tp.Record.TerritoryInternalRecord.Id, Text = _contentManager.GetItemMetadata(tp).DisplayText }) .OrderBy(obj => obj.Text) })); } // TODO return(Json(new List <string>())); }
private AddressEditViewModel CreateVM(AddressRecord address) { // defaults to "no country selected" for a new or "legacy" AddressRecord var countryId = address.CountryId; if (countryId == 0 && !string.IsNullOrWhiteSpace(address.Country)) { // from address.Country, find the value that should be used // address.Country is of type string. It could represent the // name of the country (legacy) or the Id of the country territory. // Try to parse it. if (!int.TryParse(address.Country, out countryId)) { // parsing failed, so the string may be a territory's name var tp = _addressConfigurationService.GetCountry(address.Country); if (tp != null) { countryId = tp.Record.TerritoryInternalRecord.Id; } } } return(new AddressEditViewModel(address) { Countries = _addressConfigurationService .CountryOptions(address.AddressType, countryId), CountryId = countryId }); }
private void ValidateVM(AddressEditViewModel vm) { int id = -1; if (vm.CityId > 0) { if (int.TryParse(vm.City, out id)) { // the form sent the city's id instead of its name vm.City = _addressConfigurationService .GetCity(vm.CityId) ?.As <TitlePart>() ?.Title ?? string.Empty; } } if (vm.ProvinceId > 0) { if (int.TryParse(vm.Province, out id)) { // the form sent the city's id instead of its name vm.Province = _addressConfigurationService .GetProvince(vm.ProvinceId) ?.As <TitlePart>() ?.Title ?? string.Empty; } } if (vm.CountryId > 0) { if (int.TryParse(vm.Country, out id)) { // the form sent the city's id instead of its name vm.Country = _addressConfigurationService .GetCountry(vm.CountryId) ?.As <TitlePart>() ?.Title ?? string.Empty; } } }
/// <summary> /// validation of the vm coming from a create/edit action /// </summary> /// <param name="vm"></param> /// <returns></returns> /// <remarks> /// It would be cleaner to do this in its own validation classes, /// but we need a bunch of IDependencies, so putting this code /// here is less of an hassle. /// </remarks> public bool Validate(AddressEditViewModel vm) { var validCountries = _addressConfigurationService .GetAllCountries(vm.AddressType); var countryTP = _addressConfigurationService .GetCountry(vm.CountryId); if (!SubValidation(validCountries, countryTP)) { return(false); } var validProvinces = _addressConfigurationService .GetAllProvinces(vm.AddressType, countryTP); if (validProvinces == null) { // error condition return(false); } var provinceTP = GetTerritory(vm.Province); if (validProvinces.Any()) { // there may not be any configured province, and that is ok, // but if any is configured, we check that the one selected is valid if (!SubValidation(validProvinces, provinceTP)) { return(false); } } var validCities = _addressConfigurationService .GetAllCities(vm.AddressType, // use province if it exists, otherwise country provinceTP == null ? countryTP : provinceTP); if (validCities == null) { // error condition return(false); } if (validCities.Any()) { // there may not be any configured city, and that is ok, // but if any is configured, we check that the one selected is valid var cityTP = GetTerritory(vm.City); if (!SubValidation(validCities, cityTP)) { return(false); } } return(true); }
public JsonResult GetAdministrativeInfo(int territoryId) { var country = _addressConfigurationService.GetCountry(territoryId); var part = country?.As <TerritoryAdministrativeTypePart>(); if (part != null) { return(Json(new { part.HasCities, part.HasProvinces, part.AdministrativeType }, JsonRequestBehavior.AllowGet)); } else { return(null); } }
public ActionResult Index(AddressesVM model) { ActionResult result = null; var thecurrentUser = _orchardServices.WorkContext.CurrentUser; switch (model.Submit) { case "cart": result = RedirectToAction("Index", "ShoppingCart", new { area = "Nwazet.Commerce" }); break; case "save": // validate addresses if (!TryUpdateModel(model.ShippingAddressVM) || !TryUpdateModel(model.BillingAddressVM) || !ValidateVM(model.ShippingAddressVM) || !ValidateVM(model.BillingAddressVM) || !ValidateVM(model)) { // in case of error, repopulate the default lists model.ShippingAddressVM = CreateVM(AddressRecordType.ShippingAddress); model.BillingAddressVM = CreateVM(AddressRecordType.BillingAddress); if (thecurrentUser != null) { model.ListAvailableBillingAddress = _nwazetCommunicationService.GetBillingByUser(thecurrentUser); model.ListAvailableShippingAddress = _nwazetCommunicationService.GetShippingByUser(thecurrentUser); } result = View("Index", model); break; } // Hack: based on the address coming in model.ShippingAddressVM, we can compute the actual // destinations to be used for tax computations at this stage var countryName = _addressConfigurationService ?.GetCountry(model.ShippingAddressVM.CountryId) ?.Record?.TerritoryInternalRecord.Name; // costruisce la lista di CheckoutItems in base al contenuto del carrello List <CheckoutItem> items = new List <CheckoutItem>(); foreach (var prod in _shoppingCart.GetProducts()) { items.Add(new CheckoutItem { Attributes = prod.AttributeIdsToValues, LinePriceAdjustment = prod.LinePriceAdjustment, OriginalPrice = prod.OriginalPrice, Price = prod.Product.DiscountPrice >= 0 && prod.Product.DiscountPrice < prod.Product.Price ? _productPriceService.GetDiscountPrice(prod.Product, countryName, null) : _productPriceService.GetPrice(prod.Product, countryName, null), ProductId = prod.Product.Id, PromotionId = prod.Promotion == null ? null : (int?)(prod.Promotion.Id), Quantity = prod.Quantity, Title = prod.Product.ContentItem.As <TitlePart>().Title }); } // check if there are products in the cart if (items.Count > 0) { var paymentGuid = Guid.NewGuid().ToString(); var charge = new PaymentGatewayCharge("Payment Gateway", paymentGuid); // get Orchard user id var userId = -1; var currentUser = _orchardServices.WorkContext.CurrentUser; if (currentUser != null) { userId = currentUser.Id; } // update addresses based on those populated in the form model.ShippingAddress = AddressFromVM(model.ShippingAddressVM); model.BillingAddress = AddressFromVM(model.BillingAddressVM); var currency = _currencyProvider.CurrencyCode; var order = _orderService.CreateOrder( charge, items, _shoppingCart.Subtotal(), _shoppingCart.Total(), _shoppingCart.Taxes(), _shoppingCart.ShippingOption, model.ShippingAddress, model.BillingAddress, model.Email, model.PhonePrefix + " " + model.Phone, model.SpecialInstructions, OrderPart.Pending, //.Cancelled, null, false, userId, 0, "", currency); // update advanced address information var addressPart = order.As <AddressOrderPart>(); if (addressPart != null) { // shipping info addressPart.ShippingCountryName = model.ShippingAddressVM.Country; addressPart.ShippingCountryId = model.ShippingAddressVM.CountryId; addressPart.ShippingCityName = model.ShippingAddressVM.City; addressPart.ShippingCityId = model.ShippingAddressVM.CityId; addressPart.ShippingProvinceName = model.ShippingAddressVM.Province; addressPart.ShippingProvinceId = model.ShippingAddressVM.ProvinceId; // billing addressPart.BillingCountryName = model.BillingAddressVM.Country; addressPart.BillingCountryId = model.BillingAddressVM.CountryId; addressPart.BillingCityName = model.BillingAddressVM.City; addressPart.BillingCityId = model.BillingAddressVM.CityId; addressPart.BillingProvinceName = model.BillingAddressVM.Province; addressPart.BillingProvinceId = model.BillingAddressVM.ProvinceId; } // To properly handle the order's advanced address configuration we need // to call again the providers to store the additional data, because when they // are invoked in Nwazet's IOrderService implementation we can't have access // to the new information yet. If we ever overhaul that module, we should // account for this extensibility requirement. foreach (var oaip in _orderAdditionalInformationProviders) { oaip.StoreAdditionalInformation(order); } order.LogActivity(OrderPart.Event, "Order created"); // we unpublish the order here. The service from Nwazet creates it // and publishes it. This would cause issues whenever a user leaves // mid checkout rather than completing the entire process, because we // would end up having unprocessed orders that are created and published. // By unpublishing, we practically turn the order in a draft. Later, // after processing payments, we publish the order again so it shows // in the "normal" queries and lists. // Note that this is a workaround for order management that only really // works as long as payments are processed and the order published there. // In cases where we may not wish to have payments happen when a new order // is created, this system should be reworked properly. _contentManager.Unpublish(order.ContentItem); // save the addresses for the contact doing the order. _nwazetCommunicationService.OrderToContact(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 }; var nonce = _paymentService.CreatePaymentNonce(payment); result = RedirectToAction("Pay", "Payment", new { area = "Laser.Orchard.PaymentGateway", nonce = nonce, newPaymentGuid = paymentGuid }); } else { _notifier.Information(T("There are no products in the cart. Go back to the catalog and add products.")); result = View("Index", model); } break; default: model.ShippingAddressVM = CreateVM(AddressRecordType.ShippingAddress); model.BillingAddressVM = CreateVM(AddressRecordType.BillingAddress); if (thecurrentUser != null) { model.ListAvailableBillingAddress = _nwazetCommunicationService.GetBillingByUser(thecurrentUser); model.ListAvailableShippingAddress = _nwazetCommunicationService.GetShippingByUser(thecurrentUser); model.Email = thecurrentUser.Email; var cel = _nwazetCommunicationService.GetPhone(thecurrentUser); if (cel.Length == 2) { model.PhonePrefix = cel[0]; model.Phone = cel[1]; } } result = View("Index", model); break; } return(result); }
public ActionResult IndexPOST(CheckoutViewModel model) { // Depending on whether shipping is required or not, the validation of what has been // input changes, because if there is no shipping there's no need for the shipping // address. var user = _workContextAccessor.GetContext().CurrentUser; if (!_checkoutHelperService.UserMayCheckout(user, out ActionResult redirect)) { if (redirect != null) { return(redirect); } return(Redirect(RedirectUrl)); } // check if the user is trying to reset the selected addresses to select different // ones. if (model.ResetAddresses) { // reset shipment to redo the calculation correctly, // removing from the total the shipment that will have to be reselected _shoppingCart.ShippingOption = null; ReinflateViewModelAddresses(model); // Put the model we validated in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; return(RedirectToAction("Index")); } model.ShippingRequired = IsShippingRequired(); //we'll reuse this // Ensure address types are initialized correctly model.BillingAddressVM.AddressType = AddressRecordType.BillingAddress; model.BillingAddressVM.AddressRecord.AddressType = AddressRecordType.BillingAddress; if (model.ShippingAddressVM != null) { model.ShippingAddressVM.AddressType = AddressRecordType.ShippingAddress; model.ShippingAddressVM.AddressRecord.AddressType = AddressRecordType.ShippingAddress; } // validate var validationSuccess = ValidateVM(model); if (!validationSuccess) { // don't move on, but rather leave the user on this form model.BillingAddressVM = CreateVM(AddressRecordType.BillingAddress, model.BillingAddressVM); if (model.ShippingRequired) { model.ShippingAddressVM = CreateVM(AddressRecordType.ShippingAddress, model.ShippingAddressVM); } InjectServices(model); if (user != null) { // also load the list of existing addresses for them model.ListAvailableBillingAddress = _nwazetCommunicationService.GetBillingByUser(user); // we are only going to load the shipping addresses if shipping is required if (model.ShippingRequired) { model.ListAvailableShippingAddress = _nwazetCommunicationService.GetShippingByUser(user); } } return(View(model)); } // in case validation is successful, if a user exists, try to store the // addresses they just configured. if (user != null) { if (model.BillingAddressVM != null && model.BillingAddressVM.AddressRecord != null) { var countryTP = _addressConfigurationService.GetCountry(model.BillingAddressVM.CountryId); model.BillingAddressVM.Country = _contentManager.GetItemMetadata(countryTP).DisplayText; if (model.BillingAddressVMListAddress > 0) { model.BillingAddressVM.AddressRecord.Id = model.BillingAddressVMListAddress; } _nwazetCommunicationService.AddAddress(model.BillingAddressVM.AddressRecord, user); } if (model.ShippingAddressVM != null && model.ShippingAddressVM.AddressRecord != null) { var countryTP = _addressConfigurationService.GetCountry(model.ShippingAddressVM.CountryId); model.ShippingAddressVM.Country = _contentManager.GetItemMetadata(countryTP).DisplayText; if (model.ShippingAddressVMListAddress > 0) { model.ShippingAddressVM.AddressRecord.Id = model.ShippingAddressVMListAddress; } _nwazetCommunicationService.AddAddress(model.ShippingAddressVM.AddressRecord, user); } if (!string.IsNullOrWhiteSpace(model.PhonePrefix) || !string.IsNullOrWhiteSpace(model.Phone)) { _nwazetCommunicationService.SetPhone(model.PhonePrefix, model.Phone, user); } } // In case validation is successful, depending on whether shipping is required, we // should redirect to a different action/step. // If shipping is required, we should redirect to an action that lets the user select // their preferred shipping method. If only one method is configured, the user should // still be made to go through that step. The selection of the list of available methods // can make use of the address the user has selected for shipping. // If no shipping is required we can move on to reviewing the order. // At this stage, since we also have the correct address, we can correctly compute TAX // TODO: compute VAT // Put the model we validated in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; if (IsShippingRequired()) { // Set values into the ShoppingCart storage var country = _addressConfigurationService ?.GetCountry(model.ShippingAddressVM.CountryId); _shoppingCart.Country = _contentManager.GetItemMetadata(country).DisplayText; _shoppingCart.ZipCode = model.ShippingAddressVM.PostalCode; return(RedirectToAction("Shipping")); } return(RedirectToAction("Review")); }
public ActionResult Index(CheckoutViewModel model) { // This will be the entry point for the checkout process. // This method should probably have parameters to handle displaying its form // with some information already in it in case of validation errors when posting // it. 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"]; } model.ShippingRequired = IsShippingRequired(); if (user != null) { // If the user is authenticated, set the model's email and any other information // we can get from the user's contact, but avoid overwriting previous input if (string.IsNullOrWhiteSpace(model.Email)) { model.Email = user.Email; } if (string.IsNullOrWhiteSpace(model.Phone)) { var cel = _nwazetCommunicationService.GetPhone(user); if (cel.Length == 2) { model.PhonePrefix = cel[0]; model.Phone = cel[1]; } } // also load the list of existing addresses for them model.ListAvailableBillingAddress = _nwazetCommunicationService.GetBillingByUser(user); // we are only going to load the shipping addresses if shipping is required if (model.ShippingRequired) { model.ListAvailableShippingAddress = _nwazetCommunicationService.GetShippingByUser(user); } } // attempt to shortcircuit the actions if (model.UseDefaultAddress) { // if the user has saved addresses, preselect the ones used most recently if (model.ListAvailableBillingAddress.Any() && (!model.ShippingRequired || (model.ShippingRequired && model.ListAvailableShippingAddress.Any()))) { model.BillingAddressVM = new AddressEditViewModel(model .ListAvailableBillingAddress // pick the one used/updated most recently .OrderByDescending(a => a.TimeStampUTC) .First()); if (model.ShippingRequired) { model.ShippingAddressVM = new AddressEditViewModel(model .ListAvailableShippingAddress // pick the one used/updated most recently .OrderByDescending(a => a.TimeStampUTC) .First()); } // redirect to next step // Put the model we validated in TempData so it can be reused in the next action. TempData["CheckoutViewModel"] = model; if (model.ShippingRequired) { // Set values into the ShoppingCart storage var country = _addressConfigurationService ?.GetCountry(model.ShippingAddressVM.CountryId); _shoppingCart.Country = _contentManager.GetItemMetadata(country).DisplayText; _shoppingCart.ZipCode = model.ShippingAddressVM.PostalCode; } // we redirect to this post action, where we do validation return(IndexPOST(model)); } } model.BillingAddressVM = CreateVM(AddressRecordType.BillingAddress, model.BillingAddressVM); // test whether shipping will be required for the order, because that will change // what must be displayed for the addresses as well as what happens when we go ahead // with the checkout: if no shipping is required, we can go straight to order review // and then payment. if (model.ShippingRequired) { model.ShippingAddressVM = CreateVM(AddressRecordType.ShippingAddress, model.ShippingAddressVM); } InjectServices(model); FinalizeVM(model); return(View(model)); }
/// <summary> /// validation of the vm coming from a create/edit action /// </summary> /// <param name="vm"></param> /// <returns></returns> /// <remarks> /// It would be cleaner to do this in its own validation classes, /// but we need a bunch of IDependencies, so putting this code /// here is less of an hassle. /// </remarks> public bool Validate(AddressEditViewModel vm) { var validCountries = _addressConfigurationService .GetAllCountries(vm.AddressType); var countryTP = _addressConfigurationService .GetCountry(vm.CountryId); if (!SubValidation(validCountries, countryTP)) { return(false); } var provinceTP = GetTerritory(vm.Province) ?? _addressConfigurationService.SingleTerritory(vm.ProvinceId); if (provinceTP == null) { // maybe we did not find a territory because it's not configured, // but we had a free text input for the province var provinceName = vm.Province.Trim(); if (provinceName.Length < 2) { // at least two characters return(false); } } else { // check in the configuration parts if they are a valid province or not var adminTypePart = provinceTP.As <TerritoryAdministrativeTypePart>(); if (adminTypePart != null) { if (adminTypePart.AdministrativeType == TerritoryAdministrativeType.Province) { var territoryAddressTypePart = provinceTP.As <TerritoryAddressTypePart>(); if (territoryAddressTypePart != null) { if (vm.AddressType == AddressRecordType.ShippingAddress) { if (!territoryAddressTypePart.Shipping) { return(false); } } else { if (!territoryAddressTypePart.Billing) { return(false); } } } } } } var cityTP = GetTerritory(vm.City) ?? _addressConfigurationService.SingleTerritory(vm.CityId); // check in the configuration parts if they are a valid city or not if (cityTP != null) { var adminTypePart = cityTP.As <TerritoryAdministrativeTypePart>(); if (adminTypePart != null) { if (adminTypePart.AdministrativeType == TerritoryAdministrativeType.City) { var territoryAddressTypePart = cityTP.As <TerritoryAddressTypePart>(); if (territoryAddressTypePart != null) { if (vm.AddressType == AddressRecordType.ShippingAddress) { if (!territoryAddressTypePart.Shipping) { return(false); } } else { if (!territoryAddressTypePart.Billing) { return(false); } } } } } } // https://en.wikipedia.org/wiki/List_of_postal_codes // we had to make the change because we first checked // it was just a number // during use we noticed that the Netherlands have PS in the cap // therefore changed the control over the character if (string.IsNullOrWhiteSpace(vm.PostalCode)) { return(false); } else { foreach (char c in vm.PostalCode) { if (!char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c)) { vm.Errors.Add(T("Postal or ZIP code may contain only characters or digits.").Text); return(false); } } } return(true); }