public async Task <IActionResult> ExemptionCertificates() { var customer = await _workContext.GetCurrentCustomerAsync(); if (!await _customerService.IsRegisteredAsync(customer)) { return(Challenge()); } //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName, customer)) { return(RedirectToRoute("CustomerInfo")); } if (!_avalaraTaxSettings.EnableCertificates) { return(RedirectToRoute("CustomerInfo")); } //ACL if (_avalaraTaxSettings.CustomerRoleIds.Any()) { var customerRoleIds = await _customerService.GetCustomerRoleIdsAsync(customer); if (!customerRoleIds.Intersect(_avalaraTaxSettings.CustomerRoleIds).Any()) { return(RedirectToRoute("CustomerInfo")); } } var token = await _avalaraTaxManager.CreateTokenAsync(customer); var link = await _avalaraTaxManager.GetInvitationAsync(customer) ?? AvalaraTaxDefaults.CertExpressUrl; var certificates = await _avalaraTaxManager.GetCustomerCertificatesAsync(customer); var model = new TaxExemptionModel { Token = token, Link = link, CustomerId = customer.Id, Certificates = certificates?.Select(certificate => new ExemptionCertificateModel { Id = certificate.id ?? 0, Status = certificate.status, SignedDate = certificate.signedDate.ToShortDateString(), ExpirationDate = certificate.expirationDate.ToShortDateString(), ExposureZone = certificate.exposureZone?.name }).ToList() ?? new List <ExemptionCertificateModel>() }; model.AvailableExposureZones = (await _avalaraTaxManager.GetExposureZonesAsync()) .Select(zone => new SelectListItem(zone.name, zone.name)) .ToList(); return(View("~/Plugins/Tax.Avalara/Views/Customer/ExemptionCertificates.cshtml", model)); }
/// <returns>A task that represents the asynchronous operation</returns> public async Task <IActionResult> ExportProducts(string selectedIds) { //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName)) { return(RedirectToAction("List", "Product")); } if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings)) { return(AccessDeniedView()); } //export items var exportedItems = await _avalaraTaxManager.ExportProductsAsync(selectedIds); if (exportedItems.HasValue) { if (exportedItems > 0) { _notificationService.SuccessNotification(string.Format(await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.Items.Export.Success"), exportedItems)); } else { _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.Items.Export.AlreadyExported")); } } else { _notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.Items.Export.Error")); } return(RedirectToAction("List", "Product")); }
/// <returns>A task that represents the asynchronous operation</returns> public override async Task <IActionResult> Categories() { //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName)) { //if isn't active return base action result RouteData.Values["controller"] = "Tax"; return(await base.Categories()); } if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings)) { return(AccessDeniedView()); } //prepare model var model = new Models.Tax.TaxCategorySearchModel(); var cacheKey = _cacheManager.PrepareKeyForDefaultCache(AvalaraTaxDefaults.TaxCodeTypesCacheKey); var taxCodeTypes = await _cacheManager.GetAsync(cacheKey, async() => await _avalaraTaxManager.GetTaxCodeTypesAsync()); if (taxCodeTypes != null) { model.AvailableTypes = taxCodeTypes.Select(type => new SelectListItem(type.Value, type.Key)).ToList(); } model.SetGridPageSize(); //use overridden view return(View("~/Plugins/Tax.Avalara/Views/Tax/Categories.cshtml", model)); }
/// <summary> /// Handle customer activated event /// </summary> /// <param name="eventMessage">Event message</param> /// <returns>A task that represents the asynchronous operation</returns> public async Task HandleEventAsync(CustomerActivatedEvent eventMessage) { if (eventMessage.Customer is null) { return; } //ensure that Avalara tax provider is active for the passed customer, since it's the event from the public area if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName, eventMessage.Customer)) { return; } if (!_avalaraTaxSettings.EnableCertificates) { return; } //create customer await _avalaraTaxManager.CreateOrUpdateCustomerAsync(eventMessage.Customer); }
/// <summary> /// Invoke the widget view component /// </summary> /// <param name="widgetZone">Widget zone</param> /// <param name="additionalData">Additional parameters</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the view component result /// </returns> public async Task <IViewComponentResult> InvokeAsync(string widgetZone, object additionalData) { //ensure that Avalara tax provider is active var customer = await _workContext.GetCurrentCustomerAsync(); if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName, customer)) { return(Content(string.Empty)); } if (!_avalaraTaxSettings.EnableCertificates) { return(Content(string.Empty)); } //ACL if (_avalaraTaxSettings.CustomerRoleIds.Any()) { var customerRoleIds = await _customerService.GetCustomerRoleIdsAsync(customer); if (!customerRoleIds.Intersect(_avalaraTaxSettings.CustomerRoleIds).Any()) { return(Content(string.Empty)); } } //ensure that it's a proper widget zone if (!widgetZone.Equals(PublicWidgetZones.OrderSummaryContentBefore)) { return(Content(string.Empty)); } //ensure that model is passed if (additionalData is not ShoppingCartModel cartModel || cartModel.OrderReviewData?.Display != true) { return(Content(string.Empty)); } var store = await _storeContext.GetCurrentStoreAsync(); var validCertificate = await _avalaraTaxManager.GetValidCertificatesAsync(customer, store.Id); var certificateValue = !string.IsNullOrEmpty(validCertificate?.exemptionNumber) ? validCertificate.exemptionNumber : validCertificate?.id?.ToString(); return(View("~/Plugins/Tax.Avalara/Views/Checkout/AppliedCertificate.cshtml", certificateValue)); }
/// <summary> /// Invoke the widget view component /// </summary> /// <param name="widgetZone">Widget zone</param> /// <param name="additionalData">Additional parameters</param> /// <returns>View component result</returns> public async Task <IViewComponentResult> InvokeAsync(string widgetZone, object additionalData) { //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName)) { return(Content(string.Empty)); } if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings)) { return(Content(string.Empty)); } //ensure that it's a proper widget zone if (!widgetZone.Equals(AdminWidgetZones.ProductListButtons)) { return(Content(string.Empty)); } return(View("~/Plugins/Tax.Avalara/Views/Product/ExportItems.cshtml")); }
/// <summary> /// Handle model received event /// </summary> /// <param name="eventMessage">Event message</param> /// <returns>A task that represents the asynchronous operation</returns> public async Task HandleEventAsync(ModelReceivedEvent <BaseNopModel> eventMessage) { //get entity by received model var entity = eventMessage.Model switch { CustomerModel customerModel => (BaseEntity)await _customerService.GetCustomerByIdAsync(customerModel.Id), CustomerRoleModel customerRoleModel => await _customerService.GetCustomerRoleByIdAsync(customerRoleModel.Id), ProductModel productModel => await _productService.GetProductByIdAsync(productModel.Id), CheckoutAttributeModel checkoutAttributeModel => await _checkoutAttributeService.GetCheckoutAttributeByIdAsync(checkoutAttributeModel.Id), _ => null }; if (entity == null) { return; } //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName)) { return; } if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings)) { return; } //whether there is a form value for the entity use code if (_httpContextAccessor.HttpContext.Request.Form.TryGetValue(AvalaraTaxDefaults.EntityUseCodeAttribute, out var entityUseCodeValue) && !StringValues.IsNullOrEmpty(entityUseCodeValue)) { //save attribute var entityUseCode = !entityUseCodeValue.ToString().Equals(Guid.Empty.ToString()) ? entityUseCodeValue.ToString() : null; await _genericAttributeService.SaveAttributeAsync(entity, AvalaraTaxDefaults.EntityUseCodeAttribute, entityUseCode); } }
/// <summary> /// Invoke the widget view component /// </summary> /// <param name="widgetZone">Widget zone</param> /// <param name="additionalData">Additional parameters</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the view component result /// </returns> public async Task <IViewComponentResult> InvokeAsync(string widgetZone, object additionalData) { //ensure that model is passed if (additionalData is not BaseNopEntityModel entityModel) { return(Content(string.Empty)); } //ensure that Avalara tax provider is active if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName)) { return(Content(string.Empty)); } if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings)) { return(Content(string.Empty)); } //ensure that it's a proper widget zone if (!widgetZone.Equals(AdminWidgetZones.CustomerDetailsBlock) && !widgetZone.Equals(AdminWidgetZones.CustomerRoleDetailsTop) && !widgetZone.Equals(AdminWidgetZones.ProductDetailsBlock) && !widgetZone.Equals(AdminWidgetZones.CheckoutAttributeDetailsBlock)) { return(Content(string.Empty)); } //get Avalara pre-defined entity use codes var cacheKey = _staticCacheManager.PrepareKeyForDefaultCache(AvalaraTaxDefaults.EntityUseCodesCacheKey); var cachedEntityUseCodes = await _staticCacheManager.GetAsync(cacheKey, async() => await _avalaraTaxManager.GetEntityUseCodesAsync()); var entityUseCodes = cachedEntityUseCodes?.Select(useCode => new SelectListItem { Value = useCode.code, Text = $"{useCode.name} ({string.Join(", ", useCode.validCountries)})" }).ToList() ?? new List <SelectListItem>(); //add the special item for 'undefined' with empty guid value var defaultValue = Guid.Empty.ToString(); entityUseCodes.Insert(0, new SelectListItem { Value = defaultValue, Text = await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.Fields.EntityUseCode.None") }); //prepare model var model = new EntityUseCodeModel { Id = entityModel.Id, EntityUseCodes = entityUseCodes }; //get entity by the model identifier BaseEntity entity = null; if (widgetZone.Equals(AdminWidgetZones.CustomerDetailsBlock)) { model.PrecedingElementId = nameof(CustomerModel.IsTaxExempt); entity = await _customerService.GetCustomerByIdAsync(entityModel.Id); } if (widgetZone.Equals(AdminWidgetZones.CustomerRoleDetailsTop)) { model.PrecedingElementId = nameof(CustomerRoleModel.TaxExempt); entity = await _customerService.GetCustomerRoleByIdAsync(entityModel.Id); } if (widgetZone.Equals(AdminWidgetZones.ProductDetailsBlock)) { model.PrecedingElementId = nameof(ProductModel.IsTaxExempt); entity = await _productService.GetProductByIdAsync(entityModel.Id); } if (widgetZone.Equals(AdminWidgetZones.CheckoutAttributeDetailsBlock)) { model.PrecedingElementId = nameof(CheckoutAttributeModel.IsTaxExempt); entity = await _checkoutAttributeService.GetCheckoutAttributeByIdAsync(entityModel.Id); } //try to get previously saved entity use code model.AvalaraEntityUseCode = entity == null ? defaultValue : await _genericAttributeService.GetAttributeAsync <string>(entity, AvalaraTaxDefaults.EntityUseCodeAttribute); return(View("~/Plugins/Tax.Avalara/Views/EntityUseCode/EntityUseCode.cshtml", model)); }
/// <summary> /// Invoke the widget view component /// </summary> /// <param name="widgetZone">Widget zone</param> /// <param name="additionalData">Additional parameters</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the view component result /// </returns> public async Task <IViewComponentResult> InvokeAsync(string widgetZone, object additionalData) { //ensure that Avalara tax provider is active var customer = await _workContext.GetCurrentCustomerAsync(); if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName, customer)) { return(Content(string.Empty)); } //ensure that it's a proper widget zone if (!widgetZone.Equals(PublicWidgetZones.CheckoutConfirmTop) && !widgetZone.Equals(PublicWidgetZones.OpCheckoutConfirmTop)) { return(Content(string.Empty)); } //ensure thet address validation is enabled if (!_avalaraTaxSettings.ValidateAddress) { return(Content(string.Empty)); } //validate entered by customer addresses only var addressId = _taxSettings.TaxBasedOn == TaxBasedOn.BillingAddress ? customer.BillingAddressId : _taxSettings.TaxBasedOn == TaxBasedOn.ShippingAddress ? customer.ShippingAddressId : null; var address = await _addressService.GetAddressByIdAsync(addressId ?? 0); if (address == null) { return(Content(string.Empty)); } //validate address var validationResult = await _avalaraTaxManager.ValidateAddressAsync(address); //whether there are errors in validation result var errorDetails = validationResult?.messages? .Where(message => message.severity.Equals("Error", StringComparison.InvariantCultureIgnoreCase)) .Select(message => message.details) ?? new List <string>(); if (errorDetails.Any()) { //display error message to customer return(View("~/Plugins/Tax.Avalara/Views/Checkout/AddressValidation.cshtml", new AddressValidationModel { Message = string.Format(await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.AddressValidation.Error"), WebUtility.HtmlEncode(string.Join("; ", errorDetails))), IsError = true })); } //if there are no errors and no validated addresses, nothing to display if (!validationResult?.validatedAddresses?.Any() ?? true) { return(Content(string.Empty)); } //get validated address info var validatedAddressInfo = validationResult.validatedAddresses.FirstOrDefault(); //create new address as a copy of address to validate and with details of the validated one var validatedAddress = _addressService.CloneAddress(address); validatedAddress.City = validatedAddressInfo.city; validatedAddress.CountryId = (await _countryService.GetCountryByTwoLetterIsoCodeAsync(validatedAddressInfo.country))?.Id; validatedAddress.Address1 = validatedAddressInfo.line1; validatedAddress.Address2 = validatedAddressInfo.line2; validatedAddress.ZipPostalCode = validatedAddressInfo.postalCode; validatedAddress.StateProvinceId = (await _stateProvinceService.GetStateProvinceByAbbreviationAsync(validatedAddressInfo.region))?.Id; //try to find an existing address with the same values var existingAddress = _addressService.FindAddress((await _customerService.GetAddressesByCustomerIdAsync(customer.Id)).ToList(), validatedAddress.FirstName, validatedAddress.LastName, validatedAddress.PhoneNumber, validatedAddress.Email, validatedAddress.FaxNumber, validatedAddress.Company, validatedAddress.Address1, validatedAddress.Address2, validatedAddress.City, validatedAddress.County, validatedAddress.StateProvinceId, validatedAddress.ZipPostalCode, validatedAddress.CountryId, validatedAddress.CustomAttributes); //if the found address is the same as address to validate, nothing to display if (address.Id == existingAddress?.Id) { return(Content(string.Empty)); } //otherwise display to customer a confirmation dialog about address updating var model = new AddressValidationModel(); if (existingAddress == null) { await _addressService.InsertAddressAsync(validatedAddress); model.AddressId = validatedAddress.Id; model.IsNewAddress = true; } else { model.AddressId = existingAddress.Id; } async Task <string> getAddressLineAsync(Address address) => WebUtility.HtmlEncode($"{(!string.IsNullOrEmpty(address.Address1) ? $"{address.Address1}, " : string.Empty)}" + $"{(!string.IsNullOrEmpty(address.Address2) ? $"{address.Address2}, " : string.Empty)}" + $"{(!string.IsNullOrEmpty(address.City) ? $"{address.City}, " : string.Empty)}" + $"{(await _stateProvinceService.GetStateProvinceByAddressAsync(address) is StateProvince stateProvince ? $"{stateProvince.Name}, " : string.Empty)}" + $"{(await _countryService.GetCountryByAddressAsync(address) is Country country ? $"{country.Name}, " : string.Empty)}" + $"{(!string.IsNullOrEmpty(address.ZipPostalCode) ? $"{address.ZipPostalCode}, " : string.Empty)}" .TrimEnd(' ').TrimEnd(',')); model.Message = string.Format(await _localizationService.GetResourceAsync("Plugins.Tax.Avalara.AddressValidation.Confirm"), await getAddressLineAsync(address), await getAddressLineAsync(existingAddress ?? validatedAddress)); return(View("~/Plugins/Tax.Avalara/Views/Checkout/AddressValidation.cshtml", model)); }