示例#1
0
        private string GetPaymentFee(Provider <IPaymentMethod> provider, List <OrganizedShoppingCartItem> cart)
        {
            var paymentMethodAdditionalFee = provider.Value.GetAdditionalHandlingFee(cart);
            var rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, Services.WorkContext.CurrentCustomer);
            var rate     = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, Services.WorkContext.WorkingCurrency);

            if (rate != decimal.Zero)
            {
                return(_priceFormatter.FormatPaymentMethodAdditionalFee(rate, true));
            }
            return("");
        }
示例#2
0
        private async Task PreparePayment(OrderTotalsModel model, GetOrderTotals request)
        {
            var paymentMethodSystemName = request.Customer.GetUserFieldFromEntity <string>(
                SystemCustomerFieldNames.SelectedPaymentMethod, request.Store.Id);
            decimal paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(request.Cart, paymentMethodSystemName);

            decimal paymentMethodAdditionalFeeWithTaxBase = (await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, request.Customer)).paymentPrice;

            if (paymentMethodAdditionalFeeWithTaxBase > decimal.Zero)
            {
                model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeWithTaxBase);
            }
        }
示例#3
0
        private async Task PreparePayment(OrderTotalsModel model, GetOrderTotals request)
        {
            var paymentMethodSystemName = request.Customer.GetAttributeFromEntity <string>(
                SystemCustomerAttributeNames.SelectedPaymentMethod, request.Store.Id);
            decimal paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(request.Cart, paymentMethodSystemName);

            decimal paymentMethodAdditionalFeeWithTaxBase = (await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, request.Customer)).paymentPrice;

            if (paymentMethodAdditionalFeeWithTaxBase > decimal.Zero)
            {
                decimal paymentMethodAdditionalFeeWithTax = await _currencyService.ConvertFromPrimaryStoreCurrency(paymentMethodAdditionalFeeWithTaxBase, request.Currency);

                model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeWithTax, true);
            }
        }
        /// <summary>
        /// Create item for payment method additional fee
        /// </summary>
        /// <param name="shoppingCart">Shopping cart</param>
        /// <param name="customer">Customer</param>
        /// <returns>PayPal item</returns>
        protected Item CreateItemForPaymentAdditionalFee(IList <ShoppingCartItem> shoppingCart, Customer customer)
        {
            //var processor = _paymentPluginManager.LoadPluginBySystemName("Payment.PayPalPlus") as PayPalPlusPaymentProcessor; //_paymentService.LoadPaymentMethodBySystemName("Payments.PayPalPlus") as PayPalPlusPaymentProcessor;
            //if (processor == null || !processor.PluginDescriptor.Installed)
            //    throw new NopException("PayPal Standard module cannot be loaded");
            //get price
            //var paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(shoppingCart, processor.PluginDescriptor.SystemName);
            var paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(shoppingCart, "Payment.PayPalPlus");
            var paymentPrice         = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, false, customer);

            if (paymentPrice <= decimal.Zero)
            {
                return(null);
            }

            //create item
            return(new Item
            {
                //name = $"Metodo de Pago (" + processor.PluginDescriptor.FriendlyName + ") Costo adicional",
                name = $"Metodo de Pago Costo adicional",
                price = paymentPrice.ToString("N", new CultureInfo("en-US")),
                quantity = "1"
            });
        }
        /// <summary>
        /// Gets tax
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <param name="taxRates">Tax rates</param>
        /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating tax</param>
        /// <returns>Tax total</returns>
        public virtual decimal GetTaxTotal(IList <ShoppingCartItem> cart,
                                           out SortedDictionary <decimal, decimal> taxRates, bool usePaymentMethodAdditionalFee = true)
        {
            if (cart == null)
            {
                throw new ArgumentNullException("cart");
            }

            taxRates = new SortedDictionary <decimal, decimal>();

            var    customer = cart.GetCustomer();
            string paymentMethodSystemName = "";

            if (customer != null)
            {
                paymentMethodSystemName = customer.GetAttribute <string>(
                    SystemCustomerAttributeNames.SelectedPaymentMethod,
                    _genericAttributeService,
                    _storeContext.CurrentStore.Id);
            }

            //subscription sub total (items + checkout attributes)
            decimal subTotalTaxTotal = decimal.Zero;
            decimal subscriptionSubTotalDiscountAmount;

            decimal subTotalWithoutDiscountBase;
            decimal subTotalWithDiscountBase;
            SortedDictionary <decimal, decimal> subscriptionSubTotalTaxRates;

            GetShoppingCartSubTotal(cart, false,
                                    out subscriptionSubTotalDiscountAmount,
                                    out subTotalWithoutDiscountBase, out subTotalWithDiscountBase,
                                    out subscriptionSubTotalTaxRates);
            foreach (KeyValuePair <decimal, decimal> kvp in subscriptionSubTotalTaxRates)
            {
                decimal taxRate  = kvp.Key;
                decimal taxValue = kvp.Value;
                subTotalTaxTotal += taxValue;

                if (taxRate > decimal.Zero && taxValue > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, taxValue);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + taxValue;
                    }
                }
            }



            //payment method additional fee
            decimal paymentMethodAdditionalFeeTax = decimal.Zero;

            if (usePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable)
            {
                decimal taxRate;
                decimal paymentMethodAdditionalFee        = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName);
                decimal paymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer, out taxRate);
                decimal paymentMethodAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer, out taxRate);

                paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax;
                //ensure that tax is equal or greater than zero
                if (paymentMethodAdditionalFeeTax < decimal.Zero)
                {
                    paymentMethodAdditionalFeeTax = decimal.Zero;
                }

                //tax rates
                if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, paymentMethodAdditionalFeeTax);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + paymentMethodAdditionalFeeTax;
                    }
                }
            }

            //add at least one tax rate (0%)
            if (!taxRates.Any())
            {
                taxRates.Add(decimal.Zero, decimal.Zero);
            }

            //summarize taxes
            decimal taxTotal = subTotalTaxTotal + paymentMethodAdditionalFeeTax;

            //ensure that tax is equal or greater than zero
            if (taxTotal < decimal.Zero)
            {
                taxTotal = decimal.Zero;
            }
            //round tax
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                taxTotal = RoundingHelper.RoundPrice(taxTotal);
            }
            return(taxTotal);
        }
        /// <summary>
        /// Gets tax total
        /// </summary>
        /// <param name="taxTotalRequest">Tax total request</param>
        /// <returns>Tax total</returns>
        public TaxTotalResult GetTaxTotal(TaxTotalRequest taxTotalRequest)
        {
            if (!(_httpContextAccessor.HttpContext.Items.TryGetValue("nop.TaxTotal", out var result) && result is TaxTotalResult taxTotalResult))
            {
                var taxRates = new SortedDictionary <decimal, decimal>();

                //order sub total (items + checkout attributes)
                _orderTotalCalculationService
                .GetShoppingCartSubTotal(taxTotalRequest.ShoppingCart, false, out _, out _, out _, out _, out var orderSubTotalTaxRates);
                var subTotalTaxTotal = decimal.Zero;
                foreach (var kvp in orderSubTotalTaxRates)
                {
                    var taxRate  = kvp.Key;
                    var taxValue = kvp.Value;
                    subTotalTaxTotal += taxValue;

                    if (taxRate > decimal.Zero && taxValue > decimal.Zero)
                    {
                        if (!taxRates.ContainsKey(taxRate))
                        {
                            taxRates.Add(taxRate, taxValue);
                        }
                        else
                        {
                            taxRates[taxRate] = taxRates[taxRate] + taxValue;
                        }
                    }
                }

                //shipping
                var shippingTax = decimal.Zero;
                if (_taxSettings.ShippingIsTaxable)
                {
                    var shippingExclTax = _orderTotalCalculationService
                                          .GetShoppingCartShippingTotal(taxTotalRequest.ShoppingCart, false, out _);
                    var shippingInclTax = _orderTotalCalculationService
                                          .GetShoppingCartShippingTotal(taxTotalRequest.ShoppingCart, true, out var taxRate);
                    if (shippingExclTax.HasValue && shippingInclTax.HasValue)
                    {
                        shippingTax = shippingInclTax.Value - shippingExclTax.Value;
                        if (shippingTax < decimal.Zero)
                        {
                            shippingTax = decimal.Zero;
                        }

                        if (taxRate > decimal.Zero && shippingTax > decimal.Zero)
                        {
                            if (!taxRates.ContainsKey(taxRate))
                            {
                                taxRates.Add(taxRate, shippingTax);
                            }
                            else
                            {
                                taxRates[taxRate] = taxRates[taxRate] + shippingTax;
                            }
                        }
                    }
                }

                //add at least one tax rate (0%)
                if (!taxRates.Any())
                {
                    taxRates.Add(decimal.Zero, decimal.Zero);
                }

                var taxTotal = subTotalTaxTotal + shippingTax;

                if (taxTotal < decimal.Zero)
                {
                    taxTotal = decimal.Zero;
                }

                taxTotalResult = new TaxTotalResult {
                    TaxTotal = taxTotal, TaxRates = taxRates
                };
                _httpContextAccessor.HttpContext.Items.TryAdd("nop.TaxTotal", taxTotalResult);
            }

            //payment method additional fee
            if (taxTotalRequest.UsePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable)
            {
                var paymentMethodSystemName = taxTotalRequest.Customer != null
                    ? _genericAttributeService.GetAttribute <string>(taxTotalRequest.Customer,
                                                                     NopCustomerDefaults.SelectedPaymentMethodAttribute, taxTotalRequest.StoreId)
                    : string.Empty;

                var paymentMethodAdditionalFee        = _paymentService.GetAdditionalHandlingFee(taxTotalRequest.ShoppingCart, paymentMethodSystemName);
                var paymentMethodAdditionalFeeExclTax = _taxService
                                                        .GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, taxTotalRequest.Customer, out _);
                var paymentMethodAdditionalFeeInclTax = _taxService
                                                        .GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, taxTotalRequest.Customer, out var taxRate);
                var paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax;

                if (paymentMethodAdditionalFeeTax < decimal.Zero)
                {
                    paymentMethodAdditionalFeeTax = decimal.Zero;
                }

                taxTotalResult.TaxTotal += paymentMethodAdditionalFeeTax;

                if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero)
                {
                    if (!taxTotalResult.TaxRates.ContainsKey(taxRate))
                    {
                        taxTotalResult.TaxRates.Add(taxRate, paymentMethodAdditionalFeeTax);
                    }
                    else
                    {
                        taxTotalResult.TaxRates[taxRate] = taxTotalResult.TaxRates[taxRate] + paymentMethodAdditionalFeeTax;
                    }
                }
            }

            return(taxTotalResult);
        }
        protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList<OrganizedShoppingCartItem> cart)
        {
            var model = new CheckoutPaymentMethodModel();

            //reward points
            if (_rewardPointsSettings.Enabled && !cart.IsRecurring())
            {
                int rewardPointsBalance = _workContext.CurrentCustomer.GetRewardPointsBalance();
                decimal rewardPointsAmountBase = _orderTotalCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance);
                decimal rewardPointsAmount = _currencyService.ConvertFromPrimaryStoreCurrency(rewardPointsAmountBase, _workContext.WorkingCurrency);
                if (rewardPointsAmount > decimal.Zero)
                {
                    model.DisplayRewardPoints = true;
                    model.RewardPointsAmount = _priceFormatter.FormatPrice(rewardPointsAmount, true, false);
                    model.RewardPointsBalance = rewardPointsBalance;
                }
            }

            var boundPaymentMethods = _paymentService
                .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id)
                .Where(pm => pm.Value.PaymentMethodType == PaymentMethodType.Standard || pm.Value.PaymentMethodType == PaymentMethodType.Redirection ||
                    pm.Value.PaymentMethodType == PaymentMethodType.StandardAndRedirection)
                .ToList();

            foreach (var pm in boundPaymentMethods)
            {
                if (cart.IsRecurring() && pm.Value.RecurringPaymentType == RecurringPaymentType.NotSupported)
                    continue;

                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel()
                {
                    Name = _pluginMediator.GetLocalizedFriendlyName(pm.Metadata),
                    Description = _pluginMediator.GetLocalizedDescription(pm.Metadata),
                    PaymentMethodSystemName = pm.Metadata.SystemName,
                    PaymentInfoRoute = pm.Value.GetPaymentInfoRoute(),
                    RequiresInteraction = pm.Value.RequiresInteraction
                };

                pmModel.BrandUrl = _pluginMediator.GetBrandImageUrl(pm.Metadata);

                // payment method additional fee
                decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, pm.Metadata.SystemName);
                decimal rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                decimal rate = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency);

                if (rate != decimal.Zero)
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);

                model.PaymentMethods.Add(pmModel);
            }

            // find a selected (previously) payment method
            var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute<string>(
                 SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id);

            bool selected = false;
            if (selectedPaymentMethodSystemName.HasValue())
            {
                var paymentMethodToSelect = model.PaymentMethods.Find(pm => pm.PaymentMethodSystemName.IsCaseInsensitiveEqual(selectedPaymentMethodSystemName));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                    selected = true;
                }
            }

            // if no option has been selected, let's do it for the first one
            if (!selected)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                    paymentMethodToSelect.Selected = true;
            }

            return model;
        }
示例#8
0
        /// <summary>
        /// Prepare payment method model
        /// </summary>
        /// <param name="cart">Cart</param>
        /// <param name="filterByCountryId">Filter by country identifier</param>
        /// <returns>Payment method model</returns>
        public virtual CheckoutPaymentMethodModel PreparePaymentMethodModel(IList <ShoppingCartItem> cart, int filterByCountryId)
        {
            var model = new CheckoutPaymentMethodModel();

            //reward points
            if (_rewardPointsSettings.Enabled && !_shoppingCartService.ShoppingCartIsRecurring(cart))
            {
                var rewardPointsBalance = _rewardPointService.GetRewardPointsBalance(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id);
                rewardPointsBalance = _rewardPointService.GetReducedPointsBalance(rewardPointsBalance);

                var rewardPointsAmountBase = _orderTotalCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance);
                var rewardPointsAmount     = _currencyService.ConvertFromPrimaryStoreCurrency(rewardPointsAmountBase, _workContext.WorkingCurrency);
                if (rewardPointsAmount > decimal.Zero &&
                    _orderTotalCalculationService.CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance))
                {
                    model.DisplayRewardPoints = true;
                    model.RewardPointsAmount  = _priceFormatter.FormatPrice(rewardPointsAmount, true, false);
                    model.RewardPointsBalance = rewardPointsBalance;

                    //are points enough to pay for entire order? like if this option (to use them) was selected
                    model.RewardPointsEnoughToPayForOrder = !_orderProcessingService.IsPaymentWorkflowRequired(cart, true);
                }
            }

            //filter by country
            var paymentMethods = _paymentService
                                 .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id, filterByCountryId)
                                 .Where(pm => pm.PaymentMethodType == PaymentMethodType.Standard || pm.PaymentMethodType == PaymentMethodType.Redirection)
                                 .Where(pm => !pm.HidePaymentMethod(cart))
                                 .ToList();

            foreach (var pm in paymentMethods)
            {
                if (_shoppingCartService.ShoppingCartIsRecurring(cart) && pm.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel
                {
                    Name                    = _localizationService.GetLocalizedFriendlyName(pm, _workContext.WorkingLanguage.Id),
                    Description             = _paymentSettings.ShowPaymentMethodDescriptions ? pm.PaymentMethodDescription : string.Empty,
                    PaymentMethodSystemName = pm.PluginDescriptor.SystemName,
                    LogoUrl                 = PluginManager.GetLogoUrl(pm.PluginDescriptor)
                };
                //payment method additional fee
                var paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, pm.PluginDescriptor.SystemName);
                var rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                var rate     = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency);
                if (rate > decimal.Zero)
                {
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);
                }

                model.PaymentMethods.Add(pmModel);
            }

            //find a selected (previously) payment method
            var selectedPaymentMethodSystemName = _genericAttributeService.GetAttribute <string>(_workContext.CurrentCustomer,
                                                                                                 NopCustomerDefaults.SelectedPaymentMethodAttribute, _storeContext.CurrentStore.Id);

            if (!string.IsNullOrEmpty(selectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                                            .Find(pm => pm.PaymentMethodSystemName.Equals(selectedPaymentMethodSystemName, StringComparison.InvariantCultureIgnoreCase));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }
            //if no option has been selected, let's do it for the first one
            if (model.PaymentMethods.FirstOrDefault(so => so.Selected) == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }

            return(model);
        }
示例#9
0
        /// <summary>
        /// Gets tax
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <param name="taxRates">Tax rates</param>
        /// <returns>Tax total</returns>
        public virtual decimal GetTaxTotal(IList <ShoppingCartItem> cart,
                                           out SortedDictionary <decimal, decimal> taxRates)
        {
            if (cart == null)
            {
                throw new ArgumentNullException("cart");
            }

            taxRates = new SortedDictionary <decimal, decimal>();

            var    customer = cart.GetCustomer();
            string paymentMethodSystemName = "";

            if (customer != null)
            {
                paymentMethodSystemName = customer.SelectedPaymentMethodSystemName;
            }

            //order sub total (items + checkout attributes)
            decimal  subTotalTaxTotal             = decimal.Zero;
            decimal  orderSubTotalDiscountAmount  = decimal.Zero;
            Discount orderSubTotalAppliedDiscount = null;
            decimal  subTotalWithoutDiscountBase  = decimal.Zero;
            decimal  subTotalWithDiscountBase     = decimal.Zero;
            SortedDictionary <decimal, decimal> orderSubTotalTaxRates = null;

            GetShoppingCartSubTotal(cart, false,
                                    out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount,
                                    out subTotalWithoutDiscountBase, out subTotalWithDiscountBase,
                                    out orderSubTotalTaxRates);
            foreach (KeyValuePair <decimal, decimal> kvp in orderSubTotalTaxRates)
            {
                decimal taxRate  = kvp.Key;
                decimal taxValue = kvp.Value;
                subTotalTaxTotal += taxValue;

                if (taxRate > decimal.Zero && taxValue > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, taxValue);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + taxValue;
                    }
                }
            }

            //shipping
            decimal shippingTax = decimal.Zero;

            if (_taxSettings.ShippingIsTaxable)
            {
                decimal taxRate         = decimal.Zero;
                decimal?shippingExclTax = GetShoppingCartShippingTotal(cart, false, out taxRate);
                decimal?shippingInclTax = GetShoppingCartShippingTotal(cart, true, out taxRate);
                if (shippingExclTax.HasValue && shippingInclTax.HasValue)
                {
                    shippingTax = shippingInclTax.Value - shippingExclTax.Value;

                    //tax rates
                    if (taxRate > decimal.Zero && shippingTax > decimal.Zero)
                    {
                        if (!taxRates.ContainsKey(taxRate))
                        {
                            taxRates.Add(taxRate, shippingTax);
                        }
                        else
                        {
                            taxRates[taxRate] = taxRates[taxRate] + shippingTax;
                        }
                    }
                }
            }

            //payment method additional fee
            decimal paymentMethodAdditionalFeeTax = decimal.Zero;

            if (_taxSettings.PaymentMethodAdditionalFeeIsTaxable)
            {
                decimal taxRate = decimal.Zero;

                decimal paymentMethodAdditionalFee        = _paymentService.GetAdditionalHandlingFee(paymentMethodSystemName);
                decimal paymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer, out taxRate);
                decimal paymentMethodAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer, out taxRate);

                paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax;

                //tax rates
                if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, paymentMethodAdditionalFeeTax);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + paymentMethodAdditionalFeeTax;
                    }
                }
            }

            //add at least one tax rate (0%)
            if (taxRates.Count == 0)
            {
                taxRates.Add(decimal.Zero, decimal.Zero);
            }

            //summarize taxes
            decimal taxTotal = subTotalTaxTotal + shippingTax + paymentMethodAdditionalFeeTax;

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                taxTotal = Math.Round(taxTotal, 2);
            }
            return(taxTotal);
        }
        /// <summary>
        /// Gets tax
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <param name="taxRates">Tax rates</param>
        /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating tax</param>
        /// <returns>Tax total</returns>
        public virtual async Task <(decimal taxtotal, SortedDictionary <decimal, decimal> taxRates)> GetTaxTotal(IList <ShoppingCartItem> cart, bool usePaymentMethodAdditionalFee = true)
        {
            if (cart == null)
            {
                throw new ArgumentNullException(nameof(cart));
            }

            var taxRates = new SortedDictionary <decimal, decimal>();

            var    customer = _workContext.CurrentCustomer;
            string paymentMethodSystemName = "";

            if (customer != null)
            {
                paymentMethodSystemName = customer.GetUserFieldFromEntity <string>(
                    SystemCustomerFieldNames.SelectedPaymentMethod,
                    _workContext.CurrentStore.Id);
            }

            //order sub total (items + checkout attributes)
            decimal subTotalTaxTotal = decimal.Zero;

            var shoppingCartSubTotal = await GetShoppingCartSubTotal(cart, false);

            SortedDictionary <decimal, decimal> orderSubTotalTaxRates = shoppingCartSubTotal.taxRates;

            foreach (KeyValuePair <decimal, decimal> kvp in orderSubTotalTaxRates)
            {
                decimal taxRate  = kvp.Key;
                decimal taxValue = kvp.Value;
                subTotalTaxTotal += taxValue;

                if (taxRate > decimal.Zero && taxValue > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, taxValue);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + taxValue;
                    }
                }
            }

            //shipping
            decimal shippingTax = decimal.Zero;

            if (_taxSettings.ShippingIsTaxable)
            {
                decimal taxRate;
                var     shippingTotalExcl = await GetShoppingCartShippingTotal(cart, false);

                decimal?shippingExclTax = shippingTotalExcl.shoppingCartShippingTotal;

                var shippingTotalIncl = await GetShoppingCartShippingTotal(cart, true);

                decimal?shippingInclTax = shippingTotalIncl.shoppingCartShippingTotal;

                taxRate = shippingTotalIncl.taxRate;

                if (shippingExclTax.HasValue && shippingInclTax.HasValue)
                {
                    shippingTax = shippingInclTax.Value - shippingExclTax.Value;
                    //ensure that tax is equal or greater than zero
                    if (shippingTax < decimal.Zero)
                    {
                        shippingTax = decimal.Zero;
                    }

                    //tax rates
                    if (taxRate > decimal.Zero && shippingTax > decimal.Zero)
                    {
                        if (!taxRates.ContainsKey(taxRate))
                        {
                            taxRates.Add(taxRate, shippingTax);
                        }
                        else
                        {
                            taxRates[taxRate] = taxRates[taxRate] + shippingTax;
                        }
                    }
                }
            }

            //payment method additional fee
            decimal paymentMethodAdditionalFeeTax = decimal.Zero;

            if (usePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable)
            {
                decimal taxRate;
                decimal paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName);

                var additionalFeeExclTax = await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer);

                decimal paymentMethodAdditionalFeeExclTax = additionalFeeExclTax.paymentPrice;

                var additionalFeeInclTax = await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer);

                decimal paymentMethodAdditionalFeeInclTax = additionalFeeInclTax.paymentPrice;

                taxRate = additionalFeeInclTax.taxRate;

                paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax;
                //ensure that tax is equal or greater than zero
                if (paymentMethodAdditionalFeeTax < decimal.Zero)
                {
                    paymentMethodAdditionalFeeTax = decimal.Zero;
                }

                //tax rates
                if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero)
                {
                    if (!taxRates.ContainsKey(taxRate))
                    {
                        taxRates.Add(taxRate, paymentMethodAdditionalFeeTax);
                    }
                    else
                    {
                        taxRates[taxRate] = taxRates[taxRate] + paymentMethodAdditionalFeeTax;
                    }
                }
            }

            //add at least one tax rate (0%)
            if (!taxRates.Any())
            {
                taxRates.Add(decimal.Zero, decimal.Zero);
            }

            //summarize taxes
            decimal taxTotal = subTotalTaxTotal + shippingTax + paymentMethodAdditionalFeeTax;

            //ensure that tax is equal or greater than zero
            if (taxTotal < decimal.Zero)
            {
                taxTotal = decimal.Zero;
            }
            //round tax
            if (_shoppingCartSettings.RoundPrices)
            {
                taxTotal = RoundingHelper.RoundPrice(taxTotal, _workContext.WorkingCurrency);
            }
            return(taxTotal, taxRates);
        }
        /// <summary>
        /// PrepareOrderTotalsModel:
        /// </summary>
        /// <param name="cart"></param>
        /// <param name="isEditable"></param>
        /// <returns></returns>
        public virtual decimal PrepareOrderTotalsModel(IList <ShoppingCartItem> cart, bool isEditable)
        {
            var model = new OrderTotalsModel();

            model.IsEditable = isEditable;

            if (cart.Count > 0)
            {
                //subtotal
                decimal  orderSubTotalDiscountAmountBase;
                Discount orderSubTotalAppliedDiscount;
                decimal  subTotalWithoutDiscountBase;
                decimal  subTotalWithDiscountBase;
                var      subTotalIncludingTax = _workContext.TaxDisplayType == TaxDisplayType.IncludingTax && !_taxSettings.ForceTaxExclusionFromOrderSubtotal;
                _orderTotalCalculationService.GetShoppingCartSubTotal(cart, subTotalIncludingTax,
                                                                      out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount,
                                                                      out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);
                decimal subtotalBase = subTotalWithoutDiscountBase;
                decimal subtotal     = _currencyService.ConvertFromPrimaryStoreCurrency(subtotalBase, _workContext.WorkingCurrency);
                model.SubTotal = _priceFormatter.FormatPrice(subtotal, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage, subTotalIncludingTax);

                if (orderSubTotalDiscountAmountBase > decimal.Zero)
                {
                    decimal orderSubTotalDiscountAmount = _currencyService.ConvertFromPrimaryStoreCurrency(orderSubTotalDiscountAmountBase, _workContext.WorkingCurrency);
                    model.SubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountAmount, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage, subTotalIncludingTax);
                    model.AllowRemovingSubTotalDiscount = orderSubTotalAppliedDiscount != null &&
                                                          orderSubTotalAppliedDiscount.RequiresCouponCode &&
                                                          !String.IsNullOrEmpty(orderSubTotalAppliedDiscount.CouponCode) &&
                                                          model.IsEditable;
                }


                //shipping info
                model.RequiresShipping = cart.RequiresShipping();
                if (model.RequiresShipping)
                {
                    decimal?shoppingCartShippingBase = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart);
                    if (shoppingCartShippingBase.HasValue)
                    {
                        decimal shoppingCartShipping = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartShippingBase.Value, _workContext.WorkingCurrency);
                        model.Shipping = _priceFormatter.FormatShippingPrice(shoppingCartShipping, true);

                        //selected shipping method
                        var shippingOption = _workContext.CurrentCustomer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id);
                        if (shippingOption != null)
                        {
                            model.SelectedShippingMethod = shippingOption.Name;
                        }
                    }
                }

                //payment method fee
                var paymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute <string>(
                    SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id);
                decimal paymentMethodAdditionalFee            = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName);
                decimal paymentMethodAdditionalFeeWithTaxBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                if (paymentMethodAdditionalFeeWithTaxBase > decimal.Zero)
                {
                    decimal paymentMethodAdditionalFeeWithTax = _currencyService.ConvertFromPrimaryStoreCurrency(paymentMethodAdditionalFeeWithTaxBase, _workContext.WorkingCurrency);
                    model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeWithTax, true);
                }

                //tax
                bool displayTax      = true;
                bool displayTaxRates = true;
                if (_taxSettings.HideTaxInOrderSummary && _workContext.TaxDisplayType == TaxDisplayType.IncludingTax)
                {
                    displayTax      = false;
                    displayTaxRates = false;
                }
                else
                {
                    SortedDictionary <decimal, decimal> taxRates;
                    decimal shoppingCartTaxBase = _orderTotalCalculationService.GetTaxTotal(cart, out taxRates);
                    decimal shoppingCartTax     = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTaxBase, _workContext.WorkingCurrency);

                    if (shoppingCartTaxBase == 0 && _taxSettings.HideZeroTax)
                    {
                        displayTax      = false;
                        displayTaxRates = false;
                    }
                    else
                    {
                        displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Count > 0;
                        displayTax      = !displayTaxRates;

                        model.Tax = _priceFormatter.FormatPrice(shoppingCartTax, true, false);
                        foreach (var tr in taxRates)
                        {
                            model.TaxRates.Add(new OrderTotalsModel.TaxRate
                            {
                                Rate  = _priceFormatter.FormatTaxRate(tr.Key),
                                Value = _priceFormatter.FormatPrice(_currencyService.ConvertFromPrimaryStoreCurrency(tr.Value, _workContext.WorkingCurrency), true, false),
                            });
                        }
                    }
                }
                model.DisplayTaxRates = displayTaxRates;
                model.DisplayTax      = displayTax;

                //total
                decimal  orderTotalDiscountAmountBase;
                Discount orderTotalAppliedDiscount;
                List <AppliedGiftCard> appliedGiftCards;
                int     redeemedRewardPoints;
                decimal redeemedRewardPointsAmount;
                decimal?shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart,
                                                                                                   out orderTotalDiscountAmountBase, out orderTotalAppliedDiscount,
                                                                                                   out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount);

                return(_currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, _workContext.WorkingCurrency));
            }

            return(decimal.Zero);
        }
示例#12
0
        public async Task <CheckoutPaymentMethodModel> Handle(GetPaymentMethod request, CancellationToken cancellationToken)
        {
            var model = new CheckoutPaymentMethodModel();

            //loyalty points
            if (_loyaltyPointsSettings.Enabled)
            {
                int loyaltyPointsBalance = await _loyaltyPointsService.GetLoyaltyPointsBalance(request.Customer.Id, request.Store.Id);

                double loyaltyPointsAmount = await _currencyService.ConvertFromPrimaryStoreCurrency(await _orderTotalCalculationService.ConvertLoyaltyPointsToAmount(loyaltyPointsBalance), request.Currency);

                if (loyaltyPointsAmount > 0 &&
                    _orderTotalCalculationService.CheckMinimumLoyaltyPointsToUseRequirement(loyaltyPointsBalance))
                {
                    model.DisplayLoyaltyPoints = true;
                    model.LoyaltyPointsAmount  = _priceFormatter.FormatPrice(loyaltyPointsAmount, false);
                    model.LoyaltyPointsBalance = loyaltyPointsBalance;
                    var shoppingCartTotalBase = (await _orderTotalCalculationService.GetShoppingCartTotal(request.Cart, useLoyaltyPoints: true)).shoppingCartTotal;
                    model.LoyaltyPointsEnoughToPayForOrder = (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value == 0);
                }
            }

            //filter by country
            var paymentMethods = (await _paymentService
                                  .LoadActivePaymentMethods(request.Customer, request.Store.Id, request.FilterByCountryId))
                                 .Where(pm => pm.PaymentMethodType == PaymentMethodType.Standard || pm.PaymentMethodType == PaymentMethodType.Redirection).ToList();
            var availablepaymentMethods = new List <IPaymentProvider>();

            foreach (var pm in paymentMethods)
            {
                if (!await pm.HidePaymentMethod(request.Cart))
                {
                    availablepaymentMethods.Add(pm);
                }
            }

            foreach (var pm in availablepaymentMethods)
            {
                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel
                {
                    Name                    = pm.FriendlyName,
                    Description             = _paymentSettings.ShowPaymentDescriptions ? await pm.Description() : string.Empty,
                    PaymentMethodSystemName = pm.SystemName,
                    LogoUrl                 = pm.LogoURL
                };
                //payment method additional fee
                double paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(request.Cart, pm.SystemName);

                double rate = (await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, request.Customer)).paymentPrice;
                if (rate > 0)
                {
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate);
                }

                model.PaymentMethods.Add(pmModel);
            }

            //find a selected (previously) payment method
            var selectedPaymentMethodSystemName = request.Customer.GetUserFieldFromEntity <string>(SystemCustomerFieldNames.SelectedPaymentMethod, request.Store.Id);

            if (!string.IsNullOrEmpty(selectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                                            .Find(pm => pm.PaymentMethodSystemName.Equals(selectedPaymentMethodSystemName, StringComparison.OrdinalIgnoreCase));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }
            //if no option has been selected, do it for the first one
            if (model.PaymentMethods.FirstOrDefault(so => so.Selected) == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }

            return(model);
        }
        /// <summary>
        /// Prepare details to place an order. It also sets some properties to "processPaymentRequest"
        /// </summary>
        /// <param name="processPaymentRequest">Process payment request</param>
        /// <returns>Details</returns>
        protected override PlaceOrderContainter PreparePlaceOrderDetails(ProcessPaymentRequest processPaymentRequest)
        {
            var details = new PlaceOrderContainter();

            //customer
            details.Customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId);
            if (details.Customer == null)
            {
                throw new ArgumentException("Customer is not set");
            }

            //affiliate
            var affiliate = _affiliateService.GetAffiliateById(details.Customer.AffiliateId);

            if (affiliate != null && affiliate.Active && !affiliate.Deleted)
            {
                details.AffiliateId = affiliate.Id;
            }

            //check whether customer is guest
            if (details.Customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)
            {
                throw new NopException("Anonymous checkout is not allowed");
            }

            //customer currency
            var currencyTmp = _currencyService.GetCurrencyById(
                details.Customer.GetAttribute <int>(SystemCustomerAttributeNames.CurrencyId, processPaymentRequest.StoreId));
            var customerCurrency     = (currencyTmp != null && currencyTmp.Published) ? currencyTmp : _workContext.WorkingCurrency;
            var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);

            details.CustomerCurrencyCode = customerCurrency.CurrencyCode;

            //START PATCH

            var coinServiceSettings = EngineContext.Current.ContainerManager.Resolve <CoinServiceSettings>();

            string[] Cryptos;

            if (coinServiceSettings.SupportedCoins != null)
            {
                Cryptos = coinServiceSettings.SupportedCoins.Split(',');
            }
            else
            {
                Cryptos = new string[0];
            }

            if (Cryptos.Contains(details.CustomerCurrencyCode))
            {
                details.CustomerCurrencyRate = CoinMarketCapHelper.GetCoinMarketCapRate(details.CustomerCurrencyCode) / primaryStoreCurrency.Rate;
            }
            else
            {
                details.CustomerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate;
            }

            //END PATCH

            //customer language
            details.CustomerLanguage = _languageService.GetLanguageById(
                details.Customer.GetAttribute <int>(SystemCustomerAttributeNames.LanguageId, processPaymentRequest.StoreId));
            if (details.CustomerLanguage == null || !details.CustomerLanguage.Published)
            {
                details.CustomerLanguage = _workContext.WorkingLanguage;
            }

            //billing address
            if (details.Customer.BillingAddress == null)
            {
                throw new NopException("Billing address is not provided");
            }

            if (!CommonHelper.IsValidEmail(details.Customer.BillingAddress.Email))
            {
                throw new NopException("Email is not valid");
            }

            details.BillingAddress = (Address)details.Customer.BillingAddress.Clone();
            if (details.BillingAddress.Country != null && !details.BillingAddress.Country.AllowsBilling)
            {
                throw new NopException(string.Format("Country '{0}' is not allowed for billing", details.BillingAddress.Country.Name));
            }

            //checkout attributes
            details.CheckoutAttributesXml        = details.Customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, processPaymentRequest.StoreId);
            details.CheckoutAttributeDescription = _checkoutAttributeFormatter.FormatAttributes(details.CheckoutAttributesXml, details.Customer);

            //load shopping cart
            details.Cart = details.Customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(processPaymentRequest.StoreId).ToList();

            if (!details.Cart.Any())
            {
                throw new NopException("Cart is empty");
            }

            //validate the entire shopping cart
            var warnings = _shoppingCartService.GetShoppingCartWarnings(details.Cart, details.CheckoutAttributesXml, true);

            if (warnings.Any())
            {
                throw new NopException(warnings.Aggregate(string.Empty, (current, next) => string.Format("{0}{1};", current, next)));
            }

            //validate individual cart items
            foreach (var sci in details.Cart)
            {
                var sciWarnings = _shoppingCartService.GetShoppingCartItemWarnings(details.Customer,
                                                                                   sci.ShoppingCartType, sci.Product, processPaymentRequest.StoreId, sci.AttributesXml,
                                                                                   sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false);
                if (sciWarnings.Any())
                {
                    throw new NopException(sciWarnings.Aggregate(string.Empty, (current, next) => string.Format("{0}{1};", current, next)));
                }
            }

            //min totals validation
            if (!ValidateMinOrderSubtotalAmount(details.Cart))
            {
                var minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency);
                throw new NopException(string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"),
                                                     _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)));
            }

            if (!ValidateMinOrderTotalAmount(details.Cart))
            {
                var minOrderTotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderTotalAmount, _workContext.WorkingCurrency);
                throw new NopException(string.Format(_localizationService.GetResource("Checkout.MinOrderTotalAmount"),
                                                     _priceFormatter.FormatPrice(minOrderTotalAmount, true, false)));
            }

            //tax display type
            if (_taxSettings.AllowCustomersToSelectTaxDisplayType)
            {
                details.CustomerTaxDisplayType = (TaxDisplayType)details.Customer.GetAttribute <int>(SystemCustomerAttributeNames.TaxDisplayTypeId, processPaymentRequest.StoreId);
            }
            else
            {
                details.CustomerTaxDisplayType = _taxSettings.TaxDisplayType;
            }

            //sub total (incl tax)
            decimal orderSubTotalDiscountAmount;
            List <DiscountForCaching> orderSubTotalAppliedDiscounts;
            decimal subTotalWithoutDiscountBase;
            decimal subTotalWithDiscountBase;

            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, true, out orderSubTotalDiscountAmount,
                                                                  out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);
            details.OrderSubTotalInclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountInclTax = orderSubTotalDiscountAmount;

            //discount history
            foreach (var disc in orderSubTotalAppliedDiscounts)
            {
                if (!details.AppliedDiscounts.ContainsDiscount(disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //sub total (excl tax)
            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, false, out orderSubTotalDiscountAmount,
                                                                  out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);
            details.OrderSubTotalExclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountExclTax = orderSubTotalDiscountAmount;

            //shipping info
            if (details.Cart.RequiresShipping())
            {
                var pickupPoint = details.Customer.GetAttribute <PickupPoint>(SystemCustomerAttributeNames.SelectedPickupPoint, processPaymentRequest.StoreId);
                if (_shippingSettings.AllowPickUpInStore && pickupPoint != null)
                {
                    var country = _countryService.GetCountryByTwoLetterIsoCode(pickupPoint.CountryCode);
                    var state   = _stateProvinceService.GetStateProvinceByAbbreviation(pickupPoint.StateAbbreviation);

                    details.PickUpInStore = true;
                    details.PickupAddress = new Address
                    {
                        Address1      = pickupPoint.Address,
                        City          = pickupPoint.City,
                        Country       = country,
                        StateProvince = state,
                        ZipPostalCode = pickupPoint.ZipPostalCode,
                        CreatedOnUtc  = DateTime.UtcNow,
                    };
                }
                else
                {
                    if (details.Customer.ShippingAddress == null)
                    {
                        throw new NopException("Shipping address is not provided");
                    }

                    if (!CommonHelper.IsValidEmail(details.Customer.ShippingAddress.Email))
                    {
                        throw new NopException("Email is not valid");
                    }

                    //clone shipping address
                    details.ShippingAddress = (Address)details.Customer.ShippingAddress.Clone();
                    if (details.ShippingAddress.Country != null && !details.ShippingAddress.Country.AllowsShipping)
                    {
                        throw new NopException(string.Format("Country '{0}' is not allowed for shipping", details.ShippingAddress.Country.Name));
                    }
                }

                var shippingOption = details.Customer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, processPaymentRequest.StoreId);
                if (shippingOption != null)
                {
                    details.ShippingMethodName = shippingOption.Name;
                    details.ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName;
                }

                details.ShippingStatus = ShippingStatus.NotYetShipped;
            }
            else
            {
                details.ShippingStatus = ShippingStatus.ShippingNotRequired;
            }

            //shipping total
            decimal tax;
            List <DiscountForCaching> shippingTotalDiscounts;
            var orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, true, out tax, out shippingTotalDiscounts);
            var orderShippingTotalExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, false);

            if (!orderShippingTotalInclTax.HasValue || !orderShippingTotalExclTax.HasValue)
            {
                throw new NopException("Shipping total couldn't be calculated");
            }

            details.OrderShippingTotalInclTax = orderShippingTotalInclTax.Value;
            details.OrderShippingTotalExclTax = orderShippingTotalExclTax.Value;

            foreach (var disc in shippingTotalDiscounts)
            {
                if (!details.AppliedDiscounts.ContainsDiscount(disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //payment total
            var paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(details.Cart, processPaymentRequest.PaymentMethodSystemName);

            details.PaymentAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, true, details.Customer);
            details.PaymentAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, false, details.Customer);

            //tax amount
            SortedDictionary <decimal, decimal> taxRatesDictionary;

            details.OrderTaxTotal = _orderTotalCalculationService.GetTaxTotal(details.Cart, out taxRatesDictionary);

            //VAT number
            var customerVatStatus = (VatNumberStatus)details.Customer.GetAttribute <int>(SystemCustomerAttributeNames.VatNumberStatusId);

            if (_taxSettings.EuVatEnabled && customerVatStatus == VatNumberStatus.Valid)
            {
                details.VatNumber = details.Customer.GetAttribute <string>(SystemCustomerAttributeNames.VatNumber);
            }

            //tax rates
            details.TaxRates = taxRatesDictionary.Aggregate(string.Empty, (current, next) =>
                                                            string.Format("{0}{1}:{2};   ", current, next.Key.ToString(CultureInfo.InvariantCulture), next.Value.ToString(CultureInfo.InvariantCulture)));

            //order total (and applied discounts, gift cards, reward points)
            List <AppliedGiftCard>    appliedGiftCards;
            List <DiscountForCaching> orderAppliedDiscounts;
            decimal orderDiscountAmount;
            int     redeemedRewardPoints;
            decimal redeemedRewardPointsAmount;
            var     orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(details.Cart, out orderDiscountAmount,
                                                                                    out orderAppliedDiscounts, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount);

            if (!orderTotal.HasValue)
            {
                throw new NopException("Order total couldn't be calculated");
            }

            details.OrderDiscountAmount        = orderDiscountAmount;
            details.RedeemedRewardPoints       = redeemedRewardPoints;
            details.RedeemedRewardPointsAmount = redeemedRewardPointsAmount;
            details.AppliedGiftCards           = appliedGiftCards;
            details.OrderTotal = orderTotal.Value;

            //discount history
            foreach (var disc in orderAppliedDiscounts)
            {
                if (!details.AppliedDiscounts.ContainsDiscount(disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            processPaymentRequest.OrderTotal = details.OrderTotal;

            //recurring or standard shopping cart?
            details.IsRecurringShoppingCart = details.Cart.IsRecurring();
            if (details.IsRecurringShoppingCart)
            {
                int recurringCycleLength;
                RecurringProductCyclePeriod recurringCyclePeriod;
                int recurringTotalCycles;
                var recurringCyclesError = details.Cart.GetRecurringCycleInfo(_localizationService,
                                                                              out recurringCycleLength, out recurringCyclePeriod, out recurringTotalCycles);
                if (!string.IsNullOrEmpty(recurringCyclesError))
                {
                    throw new NopException(recurringCyclesError);
                }

                processPaymentRequest.RecurringCycleLength = recurringCycleLength;
                processPaymentRequest.RecurringCyclePeriod = recurringCyclePeriod;
                processPaymentRequest.RecurringTotalCycles = recurringTotalCycles;
            }

            return(details);
        }
示例#14
0
 /// <summary>
 /// Gets payment method additional handling fee
 /// </summary>
 /// <param name="price">Price</param>
 /// <param name="customer">Customer</param>
 /// <returns>Price</returns>
 public decimal GetPaymentMethodAdditionalFee(decimal price, Customer customer)
 {
     return(_taxService.GetPaymentMethodAdditionalFee(price, customer));
 }
        /// <summary>
        /// Prepare tax details by Avalara tax service
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        private void PrepareTaxDetails(IList <ShoppingCartItem> cart)
        {
            //ensure that Avalara tax provider is active
            var taxProvider = _taxPluginManager
                              .LoadPluginBySystemName(AvalaraTaxDefaults.SystemName, _workContext.CurrentCustomer, _storeContext.CurrentStore.Id)
                              as AvalaraTaxProvider;

            if (!_taxPluginManager.IsPluginActive(taxProvider))
            {
                return;
            }

            //create dummy order for the tax request
            var order = new Order {
                Customer = _workContext.CurrentCustomer
            };

            //addresses
            order.BillingAddress  = _workContext.CurrentCustomer.BillingAddress;
            order.ShippingAddress = _workContext.CurrentCustomer.ShippingAddress;
            if (_shippingSettings.AllowPickupInStore)
            {
                var pickupPoint = _genericAttributeService.GetAttribute <PickupPoint>(_workContext.CurrentCustomer,
                                                                                      NopCustomerDefaults.SelectedPickupPointAttribute, _storeContext.CurrentStore.Id);
                if (pickupPoint != null)
                {
                    var country = _countryService.GetCountryByTwoLetterIsoCode(pickupPoint.CountryCode);
                    order.PickupAddress = new Address
                    {
                        Address1      = pickupPoint.Address,
                        City          = pickupPoint.City,
                        Country       = country,
                        StateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(pickupPoint.StateAbbreviation, country?.Id),
                        ZipPostalCode = pickupPoint.ZipPostalCode,
                        CreatedOnUtc  = DateTime.UtcNow,
                    };
                }
            }

            //checkout attributes
            order.CheckoutAttributesXml = _genericAttributeService.GetAttribute <string>(_workContext.CurrentCustomer,
                                                                                         NopCustomerDefaults.CheckoutAttributes, _storeContext.CurrentStore.Id);

            //shipping method
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);

            order.OrderShippingExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, false, shippingRateComputationMethods) ?? 0;
            order.ShippingMethod       = _genericAttributeService.GetAttribute <ShippingOption>(_workContext.CurrentCustomer,
                                                                                                NopCustomerDefaults.SelectedShippingOptionAttribute, _storeContext.CurrentStore.Id)?.Name;

            //payment method
            var paymentMethod = _genericAttributeService.GetAttribute <string>(_workContext.CurrentCustomer,
                                                                               NopCustomerDefaults.SelectedPaymentMethodAttribute, _storeContext.CurrentStore.Id);
            var paymentFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethod);

            order.PaymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentFee, false, _workContext.CurrentCustomer);
            order.PaymentMethodSystemName           = paymentMethod;

            //add discount amount
            _orderTotalCalculationService.GetShoppingCartSubTotal(cart, false, out var orderSubTotalDiscountExclTax, out _, out _, out _);
            order.OrderSubTotalDiscountExclTax = orderSubTotalDiscountExclTax;

            //create dummy order items
            foreach (var cartItem in cart)
            {
                var orderItem = new OrderItem
                {
                    AttributesXml = cartItem.AttributesXml,
                    Product       = cartItem.Product,
                    Quantity      = cartItem.Quantity
                };

                var itemSubtotal = _priceCalculationService.GetSubTotal(cartItem, true, out _, out _, out _);
                orderItem.PriceExclTax = _taxService.GetProductPrice(cartItem.Product, itemSubtotal, false, _workContext.CurrentCustomer, out _);

                order.OrderItems.Add(orderItem);
            }

            //get tax details
            var taxTransaction = taxProvider.CreateOrderTaxTransaction(order, false);

            if (taxTransaction == null)
            {
                return;
            }

            //and save it for the further usage
            var taxDetails = new TaxDetails {
                TaxTotal = taxTransaction.totalTax
            };

            foreach (var item in taxTransaction.summary)
            {
                if (!item.rate.HasValue || !item.tax.HasValue)
                {
                    continue;
                }

                var taxRate  = item.rate.Value * 100;
                var taxValue = item.tax.Value;

                if (!taxDetails.TaxRates.ContainsKey(taxRate))
                {
                    taxDetails.TaxRates.Add(taxRate, taxValue);
                }
                else
                {
                    taxDetails.TaxRates[taxRate] = taxDetails.TaxRates[taxRate] + taxValue;
                }
            }
            _httpContextAccessor.HttpContext.Session.Set(AvalaraTaxDefaults.TaxDetailsSessionValue, taxDetails);
        }
        public virtual async Task <CheckoutPaymentMethodModel> PreparePaymentMethod(IList <ShoppingCartItem> cart, string filterByCountryId)
        {
            var model = new CheckoutPaymentMethodModel();

            //reward points
            if (_rewardPointsSettings.Enabled && !cart.IsRecurring())
            {
                int rewardPointsBalance = await _rewardPointsService.GetRewardPointsBalance(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id);

                decimal rewardPointsAmountBase = await _orderTotalCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance);

                decimal rewardPointsAmount = await _currencyService.ConvertFromPrimaryStoreCurrency(rewardPointsAmountBase, _workContext.WorkingCurrency);

                if (rewardPointsAmount > decimal.Zero &&
                    _orderTotalCalculationService.CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance))
                {
                    model.DisplayRewardPoints             = true;
                    model.RewardPointsAmount              = _priceFormatter.FormatPrice(rewardPointsAmount, true, false);
                    model.RewardPointsBalance             = rewardPointsBalance;
                    model.RewardPointsEnoughToPayForOrder = !(await IsPaymentWorkflowRequired(cart, true));
                }
            }

            //filter by country
            var paymentMethods = (await _paymentService
                                  .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id, filterByCountryId))
                                 .Where(pm => pm.PaymentMethodType == PaymentMethodType.Standard || pm.PaymentMethodType == PaymentMethodType.Redirection).ToList();
            var availablepaymentMethods = new List <IPaymentMethod>();

            foreach (var pm in paymentMethods)
            {
                if (!await pm.HidePaymentMethod(cart))
                {
                    availablepaymentMethods.Add(pm);
                }
            }

            foreach (var pm in availablepaymentMethods)
            {
                if (cart.IsRecurring() && pm.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel {
                    Name                    = pm.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id),
                    Description             = _paymentSettings.ShowPaymentMethodDescriptions ? await pm.PaymentMethodDescription() : string.Empty,
                    PaymentMethodSystemName = pm.PluginDescriptor.SystemName,
                    LogoUrl                 = pm.PluginDescriptor.GetLogoUrl(_webHelper)
                };
                //payment method additional fee
                decimal paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(cart, pm.PluginDescriptor.SystemName);

                decimal rateBase = (await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer)).paymentPrice;
                decimal rate     = await _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency);

                if (rate > decimal.Zero)
                {
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);
                }

                model.PaymentMethods.Add(pmModel);
            }

            //find a selected (previously) payment method
            var selectedPaymentMethodSystemName = await _workContext.CurrentCustomer.GetAttribute <string>(
                _genericAttributeService, SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id);

            if (!String.IsNullOrEmpty(selectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                                            .Find(pm => pm.PaymentMethodSystemName.Equals(selectedPaymentMethodSystemName, StringComparison.OrdinalIgnoreCase));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }
            //if no option has been selected, let's do it for the first one
            if (model.PaymentMethods.FirstOrDefault(so => so.Selected) == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }

            return(model);
        }
示例#17
0
        /// <summary>
        /// Gets shopping cart total
        /// </summary>
        /// <param name="cart">Cart</param>
        /// <param name="appliedGiftCards">Applied gift cards</param>
        /// <param name="discountAmount">Applied discount amount</param>
        /// <param name="appliedDiscounts">Applied discounts</param>
        /// <param name="redeemedRewardPoints">Reward points to redeem</param>
        /// <param name="redeemedRewardPointsAmount">Reward points amount in primary store currency to redeem</param>
        /// <param name="useRewardPoints">A value indicating reward points should be used; null to detect current choice of the customer</param>
        /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating order total</param>
        /// <returns>Shopping cart total;Null if shopping cart total couldn't be calculated now</returns>
        public override decimal?GetShoppingCartTotal(IList <ShoppingCartItem> cart,
                                                     out decimal discountAmount, out List <DiscountForCaching> appliedDiscounts,
                                                     out List <AppliedGiftCard> appliedGiftCards,
                                                     out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount,
                                                     bool?useRewardPoints = null, bool usePaymentMethodAdditionalFee = true)
        {
            redeemedRewardPoints       = 0;
            redeemedRewardPointsAmount = decimal.Zero;

            var customer = cart.FirstOrDefault(item => item.Customer != null)?.Customer;
            var paymentMethodSystemName = string.Empty;

            if (customer != null)
            {
                paymentMethodSystemName = _genericAttributeService.GetAttribute <string>(customer,
                                                                                         NopCustomerDefaults.SelectedPaymentMethodAttribute, _storeContext.CurrentStore.Id);
            }

            //subtotal without tax
            GetShoppingCartSubTotal(cart, false, out _, out _, out _, out var subTotalWithDiscountBase);
            //subtotal with discount
            var subtotalBase = subTotalWithDiscountBase;

            //LoadAllShippingRateComputationMethods
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);

            //shipping without tax
            var shoppingCartShipping = GetShoppingCartShippingTotal(cart, false, shippingRateComputationMethods);

            //todo override this method again to include the refundable price
            //refundable price without tax
            var refundablePrice = cart.Sum(x => x.Product.RefundablePrice * x.Quantity);

            //payment method additional fee without tax
            var paymentMethodAdditionalFeeWithoutTax = decimal.Zero;

            if (usePaymentMethodAdditionalFee && !string.IsNullOrEmpty(paymentMethodSystemName))
            {
                var paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart,
                                                                                          paymentMethodSystemName);
                paymentMethodAdditionalFeeWithoutTax =
                    _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee,
                                                              false, customer);
            }

            //tax
            var shoppingCartTax = GetTaxTotal(cart, shippingRateComputationMethods, usePaymentMethodAdditionalFee);

            //Avalara plugin changes
            //adjust tax total according to received value from the Avalara
            shoppingCartTax = _httpContextAccessor.HttpContext.Session
                              .Get <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue)?.TaxTotal ?? shoppingCartTax;
            //Avalara plugin changes

            //order total
            var resultTemp = decimal.Zero;

            //refundable price
            resultTemp += refundablePrice;

            resultTemp += subtotalBase;
            if (shoppingCartShipping.HasValue)
            {
                resultTemp += shoppingCartShipping.Value;
            }

            resultTemp += paymentMethodAdditionalFeeWithoutTax;
            resultTemp += shoppingCartTax;
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                resultTemp = _priceCalculationService.RoundPrice(resultTemp);
            }

            //order total discount
            discountAmount = GetOrderTotalDiscount(customer, resultTemp, out appliedDiscounts);

            //sub totals with discount
            if (resultTemp < discountAmount)
            {
                discountAmount = resultTemp;
            }

            //reduce subtotal
            resultTemp -= discountAmount;

            if (resultTemp < decimal.Zero)
            {
                resultTemp = decimal.Zero;
            }
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                resultTemp = _priceCalculationService.RoundPrice(resultTemp);
            }

            //let's apply gift cards now (gift cards that can be used)
            appliedGiftCards = new List <AppliedGiftCard>();
            AppliedGiftCards(cart, appliedGiftCards, customer, ref resultTemp);

            if (resultTemp < decimal.Zero)
            {
                resultTemp = decimal.Zero;
            }
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                resultTemp = _priceCalculationService.RoundPrice(resultTemp);
            }

            if (!shoppingCartShipping.HasValue)
            {
                //we have errors
                return(null);
            }

            var orderTotal = resultTemp;

            //reward points
            SetRewardPoints(ref redeemedRewardPoints, ref redeemedRewardPointsAmount, useRewardPoints, customer, orderTotal);

            orderTotal = orderTotal - redeemedRewardPointsAmount;
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                orderTotal = _priceCalculationService.RoundPrice(orderTotal);
            }

            //todo append the refundable price

            return(orderTotal);
        }
示例#18
0
        protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList <OrganizedShoppingCartItem> cart)
        {
            var model = new CheckoutPaymentMethodModel();

            // was shipping skipped
            var shippingOptions = _shippingService.GetShippingOptions(cart, _workContext.CurrentCustomer.ShippingAddress, "", _storeContext.CurrentStore.Id).ShippingOptions;

            if (!cart.RequiresShipping() || (shippingOptions.Count <= 1 && _shippingSettings.SkipShippingIfSingleOption))
            {
                model.SkippedSelectShipping = true;
            }

            var paymentTypes = new PaymentMethodType[] { PaymentMethodType.Standard, PaymentMethodType.Redirection, PaymentMethodType.StandardAndRedirection };

            var boundPaymentMethods = _paymentService
                                      .LoadActivePaymentMethods(_workContext.CurrentCustomer, cart, _storeContext.CurrentStore.Id, paymentTypes)
                                      .ToList();

            var allPaymentMethods = _paymentService.GetAllPaymentMethods();

            foreach (var pm in boundPaymentMethods)
            {
                if (cart.IsRecurring() && pm.Value.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                var paymentMethod = allPaymentMethods.FirstOrDefault(x => x.PaymentMethodSystemName.IsCaseInsensitiveEqual(pm.Metadata.SystemName));

                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel
                {
                    Name                    = _pluginMediator.GetLocalizedFriendlyName(pm.Metadata),
                    Description             = _pluginMediator.GetLocalizedDescription(pm.Metadata),
                    PaymentMethodSystemName = pm.Metadata.SystemName,
                    PaymentInfoRoute        = pm.Value.GetPaymentInfoRoute(),
                    RequiresInteraction     = pm.Value.RequiresInteraction
                };

                if (paymentMethod != null)
                {
                    pmModel.FullDescription = paymentMethod.GetLocalized(x => x.FullDescription, _workContext.WorkingLanguage.Id);
                }

                pmModel.BrandUrl = _pluginMediator.GetBrandImageUrl(pm.Metadata);

                // payment method additional fee
                decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, pm.Metadata.SystemName);
                decimal rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                decimal rate     = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency);

                if (rate != decimal.Zero)
                {
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);
                }

                model.PaymentMethods.Add(pmModel);
            }

            // find a selected (previously) payment method
            var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute <string>(
                SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id);

            bool selected = false;

            if (selectedPaymentMethodSystemName.HasValue())
            {
                var paymentMethodToSelect = model.PaymentMethods.Find(pm => pm.PaymentMethodSystemName.IsCaseInsensitiveEqual(selectedPaymentMethodSystemName));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                    selected = true;
                }
            }

            // if no option has been selected, let's do it for the first one
            if (!selected)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }

            return(model);
        }
        /// <summary>
        /// Prepare details to place an order. It also sets some properties to "processPaymentRequest"
        /// </summary>
        /// <param name="processPaymentRequest">Process payment request</param>
        /// <returns>Details</returns>
        protected override PlaceOrderContainer PreparePlaceOrderDetails(ProcessPaymentRequest processPaymentRequest)
        {
            var details = new PlaceOrderContainer
            {
                //customer
                Customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId)
            };

            if (details.Customer == null)
            {
                throw new ArgumentException("Customer is not set");
            }

            //affiliate
            var affiliate = _affiliateService.GetAffiliateById(details.Customer.AffiliateId);

            if (affiliate != null && affiliate.Active && !affiliate.Deleted)
            {
                details.AffiliateId = affiliate.Id;
            }

            //check whether customer is guest
            if (details.Customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)
            {
                throw new QNetException("Anonymous checkout is not allowed");
            }

            //customer currency
            var currencyTmp = _currencyService.GetCurrencyById(
                _genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.CurrencyIdAttribute, processPaymentRequest.StoreId));
            var customerCurrency     = currencyTmp != null && currencyTmp.Published ? currencyTmp : _workContext.WorkingCurrency;
            var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);

            details.CustomerCurrencyCode = customerCurrency.CurrencyCode;
            details.CustomerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate;

            //customer language
            details.CustomerLanguage = _languageService.GetLanguageById(
                _genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.LanguageIdAttribute, processPaymentRequest.StoreId));
            if (details.CustomerLanguage == null || !details.CustomerLanguage.Published)
            {
                details.CustomerLanguage = _workContext.WorkingLanguage;
            }

            //billing address
            if (details.Customer.BillingAddress == null)
            {
                throw new QNetException("Billing address is not provided");
            }

            if (!CommonHelper.IsValidEmail(details.Customer.BillingAddress.Email))
            {
                throw new QNetException("Email is not valid");
            }

            details.BillingAddress = (Address)details.Customer.BillingAddress.Clone();
            if (details.BillingAddress.Country != null && !details.BillingAddress.Country.AllowsBilling)
            {
                throw new QNetException($"Country '{details.BillingAddress.Country.Name}' is not allowed for billing");
            }

            //checkout attributes
            details.CheckoutAttributesXml        = _genericAttributeService.GetAttribute <string>(details.Customer, QNetCustomerDefaults.CheckoutAttributes, processPaymentRequest.StoreId);
            details.CheckoutAttributeDescription = _checkoutAttributeFormatter.FormatAttributes(details.CheckoutAttributesXml, details.Customer);

            //load shopping cart
            details.Cart = _shoppingCartService.GetShoppingCart(details.Customer, ShoppingCartType.ShoppingCart, processPaymentRequest.StoreId);

            if (!details.Cart.Any())
            {
                throw new QNetException("Cart is empty");
            }

            //validate the entire shopping cart
            var warnings = _shoppingCartService.GetShoppingCartWarnings(details.Cart, details.CheckoutAttributesXml, true);

            if (warnings.Any())
            {
                throw new QNetException(warnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
            }

            //validate individual cart items
            foreach (var sci in details.Cart)
            {
                var sciWarnings = _shoppingCartService.GetShoppingCartItemWarnings(details.Customer,
                                                                                   sci.ShoppingCartType, sci.Product, processPaymentRequest.StoreId, sci.AttributesXml,
                                                                                   sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false, sci.Id);
                if (sciWarnings.Any())
                {
                    throw new QNetException(sciWarnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
                }
            }

            //min totals validation
            if (!ValidateMinOrderSubtotalAmount(details.Cart))
            {
                var minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency);
                throw new QNetException(string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"),
                                                      _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)));
            }

            if (!ValidateMinOrderTotalAmount(details.Cart))
            {
                var minOrderTotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderTotalAmount, _workContext.WorkingCurrency);
                throw new QNetException(string.Format(_localizationService.GetResource("Checkout.MinOrderTotalAmount"),
                                                      _priceFormatter.FormatPrice(minOrderTotalAmount, true, false)));
            }

            //tax display type
            if (_taxSettings.AllowCustomersToSelectTaxDisplayType)
            {
                details.CustomerTaxDisplayType = (TaxDisplayType)_genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.TaxDisplayTypeIdAttribute, processPaymentRequest.StoreId);
            }
            else
            {
                details.CustomerTaxDisplayType = _taxSettings.TaxDisplayType;
            }

            //sub total (incl tax)
            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, true, out var orderSubTotalDiscountAmount, out var orderSubTotalAppliedDiscounts, out var subTotalWithoutDiscountBase, out var _);
            details.OrderSubTotalInclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountInclTax = orderSubTotalDiscountAmount;

            //discount history
            foreach (var disc in orderSubTotalAppliedDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //sub total (excl tax)
            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, false, out orderSubTotalDiscountAmount,
                                                                  out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out _);
            details.OrderSubTotalExclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountExclTax = orderSubTotalDiscountAmount;

            //shipping info
            if (_shoppingCartService.ShoppingCartRequiresShipping(details.Cart))
            {
                var pickupPoint = _genericAttributeService.GetAttribute <PickupPoint>(details.Customer,
                                                                                      QNetCustomerDefaults.SelectedPickupPointAttribute, processPaymentRequest.StoreId);
                if (_shippingSettings.AllowPickupInStore && pickupPoint != null)
                {
                    var country = _countryService.GetCountryByTwoLetterIsoCode(pickupPoint.CountryCode);
                    var state   = _stateProvinceService.GetStateProvinceByAbbreviation(pickupPoint.StateAbbreviation, country?.Id);

                    details.PickupInStore = true;
                    details.PickupAddress = new Address
                    {
                        Address1      = pickupPoint.Address,
                        City          = pickupPoint.City,
                        County        = pickupPoint.County,
                        Country       = country,
                        StateProvince = state,
                        ZipPostalCode = pickupPoint.ZipPostalCode,
                        CreatedOnUtc  = DateTime.UtcNow
                    };
                }
                else
                {
                    if (details.Customer.ShippingAddress == null)
                    {
                        throw new QNetException("Shipping address is not provided");
                    }

                    if (!CommonHelper.IsValidEmail(details.Customer.ShippingAddress.Email))
                    {
                        throw new QNetException("Email is not valid");
                    }

                    //clone shipping address
                    details.ShippingAddress = (Address)details.Customer.ShippingAddress.Clone();
                    if (details.ShippingAddress.Country != null && !details.ShippingAddress.Country.AllowsShipping)
                    {
                        throw new QNetException($"Country '{details.ShippingAddress.Country.Name}' is not allowed for shipping");
                    }
                }

                var shippingOption = _genericAttributeService.GetAttribute <ShippingOption>(details.Customer,
                                                                                            QNetCustomerDefaults.SelectedShippingOptionAttribute, processPaymentRequest.StoreId);
                if (shippingOption != null)
                {
                    details.ShippingMethodName = shippingOption.Name;
                    details.ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName;
                }

                details.ShippingStatus = ShippingStatus.NotYetShipped;
            }
            else
            {
                details.ShippingStatus = ShippingStatus.ShippingNotRequired;
            }

            //LoadAllShippingRateComputationMethods
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);

            //shipping total
            var orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, true, shippingRateComputationMethods, out var _, out var shippingTotalDiscounts);
            var orderShippingTotalExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, false, shippingRateComputationMethods);

            if (!orderShippingTotalInclTax.HasValue || !orderShippingTotalExclTax.HasValue)
            {
                throw new QNetException("Shipping total couldn't be calculated");
            }

            details.OrderShippingTotalInclTax = orderShippingTotalInclTax.Value;
            details.OrderShippingTotalExclTax = orderShippingTotalExclTax.Value;

            foreach (var disc in shippingTotalDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //payment total
            var paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(details.Cart, processPaymentRequest.PaymentMethodSystemName);

            details.PaymentAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, true, details.Customer);
            details.PaymentAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, false, details.Customer);

            //tax amount
            details.OrderTaxTotal = _orderTotalCalculationService.GetTaxTotal(details.Cart, shippingRateComputationMethods, out var taxRatesDictionary);

            //Avalara plugin changes
            //get previously saved tax details received from the Avalara tax service
            var taxDetails = _httpContextAccessor.HttpContext.Session.Get <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue);

            if (taxDetails != null)
            {
                //adjust tax total according to received value from the Avalara
                if (taxDetails.TaxTotal.HasValue)
                {
                    details.OrderTaxTotal = taxDetails.TaxTotal.Value;
                }

                if (taxDetails.TaxRates?.Any() ?? false)
                {
                    taxRatesDictionary = new SortedDictionary <decimal, decimal>(taxDetails.TaxRates);
                }
            }
            //Avalara plugin changes

            //VAT number
            var customerVatStatus = (VatNumberStatus)_genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.VatNumberStatusIdAttribute);

            if (_taxSettings.EuVatEnabled && customerVatStatus == VatNumberStatus.Valid)
            {
                details.VatNumber = _genericAttributeService.GetAttribute <string>(details.Customer, QNetCustomerDefaults.VatNumberAttribute);
            }

            //tax rates
            details.TaxRates = taxRatesDictionary.Aggregate(string.Empty, (current, next) =>
                                                            $"{current}{next.Key.ToString(CultureInfo.InvariantCulture)}:{next.Value.ToString(CultureInfo.InvariantCulture)};   ");

            //order total (and applied discounts, gift cards, reward points)
            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(details.Cart, out var orderDiscountAmount, out var orderAppliedDiscounts, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount);

            if (!orderTotal.HasValue)
            {
                throw new QNetException("Order total couldn't be calculated");
            }

            details.OrderDiscountAmount        = orderDiscountAmount;
            details.RedeemedRewardPoints       = redeemedRewardPoints;
            details.RedeemedRewardPointsAmount = redeemedRewardPointsAmount;
            details.AppliedGiftCards           = appliedGiftCards;
            details.OrderTotal = orderTotal.Value;

            //discount history
            foreach (var disc in orderAppliedDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            processPaymentRequest.OrderTotal = details.OrderTotal;

            //Avalara plugin changes
            //delete custom value
            _httpContextAccessor.HttpContext.Session.Set <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue, null);
            //Avalara plugin changes

            //recurring or standard shopping cart?
            details.IsRecurringShoppingCart = _shoppingCartService.ShoppingCartIsRecurring(details.Cart);
            if (!details.IsRecurringShoppingCart)
            {
                return(details);
            }

            var recurringCyclesError = _shoppingCartService.GetRecurringCycleInfo(details.Cart,
                                                                                  out var recurringCycleLength, out var recurringCyclePeriod, out var recurringTotalCycles);

            if (!string.IsNullOrEmpty(recurringCyclesError))
            {
                throw new QNetException(recurringCyclesError);
            }

            processPaymentRequest.RecurringCycleLength = recurringCycleLength;
            processPaymentRequest.RecurringCyclePeriod = recurringCyclePeriod;
            processPaymentRequest.RecurringTotalCycles = recurringTotalCycles;

            return(details);
        }