public decimal GetShippingTotal(IList <ShoppingCartItem> cart)
        {
            //load all shipping rate computation methods
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer);

            return(_orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, shippingRateComputationMethods).GetValueOrDefault());
        }
Пример #2
0
        private async Task PrepareShippingInfo(OrderTotalsModel model, GetOrderTotals request)
        {
            model.RequiresShipping = request.Cart.RequiresShipping();
            if (model.RequiresShipping)
            {
                decimal?shoppingCartShippingBase = (await _orderTotalCalculationService.GetShoppingCartShippingTotal(request.Cart)).shoppingCartShippingTotal;
                if (shoppingCartShippingBase.HasValue)
                {
                    model.Shipping = _priceFormatter.FormatShippingPrice(shoppingCartShippingBase.Value, true);

                    //selected shipping method
                    var shippingOption = request.Customer.GetAttributeFromEntity <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, request.Store.Id);
                    if (shippingOption != null)
                    {
                        model.SelectedShippingMethod = shippingOption.Name;
                    }
                }
            }
        }
        /// <summary>
        /// Get transaction amount details
        /// </summary>
        /// <param name="paymentRequest">Payment info required for an order processing</param>
        /// <param name="shoppingCart">Shopping cart</param>
        /// <param name="items">List of PayPal items</param>
        /// <returns>Amount details object</returns>
        protected DetailsAmountInfo GetAmountDetails(IList <ShoppingCartItem> shoppingCart, IList <Item> items, out decimal totalAdjust)
        {
            //get total discount amount
            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(shoppingCart,
                                                                                out decimal discountAmount,
                                                                                out List <DiscountForCaching> _, out List <AppliedGiftCard> _, out int _, out decimal _);

            //get shipping total
            var shippingRateComputationMethods = _shippingPluginManager
                                                 .LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);
            var shipping      = _orderTotalCalculationService.GetShoppingCartShippingTotal(shoppingCart, shippingRateComputationMethods);
            var shippingTotal = shipping ?? 0;

            //get tax total
            var taxTotal = _orderTotalCalculationService.GetTaxTotal(shoppingCart, shippingRateComputationMethods);

            //get subtotal
            decimal subTotal;

            if (items != null && items.Any())
            {
                //items passed to PayPal, so calculate subtotal based on them
                subTotal = items.Sum(item => !decimal.TryParse(item.price, out decimal tmpPrice) || !int.TryParse(item.quantity, out int tmpQuantity) ? 0 : tmpPrice * tmpQuantity);
            }
            else
            {
                subTotal = orderTotal.Value - shippingTotal - taxTotal;
            }

            //adjust order total to avoid PayPal payment error: "Transaction amount details (subtotal, tax, shipping) must add up to specified amount total"
            totalAdjust = Math.Round(shippingTotal, 2) + Math.Round(subTotal, 2) + Math.Round(taxTotal, 2);

            //create amount details
            return(new DetailsAmountInfo
            {
                shipping = shippingTotal.ToString("N", new CultureInfo("en-US")),
                subtotal = subTotal.ToString("N", new CultureInfo("en-US")),
                tax = taxTotal.ToString("N", new CultureInfo("en-US"))
            });
        }
        /// <summary>
        /// Get transaction line items
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="storeId">Store identifier</param>
        /// <returns>List of transaction items</returns>
        private List <BasketItem> GetItems(Core.Domain.Customers.Customer customer, int storeId)
        {
            var items = new List <BasketItem>();

            //get current shopping cart
            var shoppingCart = _shoppingCartService.GetShoppingCart(customer, ShoppingCartType.ShoppingCart, storeId);

            //define function to create item
            BasketItem createItem(decimal price, string productId, string productName, string categoryName, BasketItemType itemType = BasketItemType.PHYSICAL)
            {
                return(new BasketItem
                {
                    Id = productId,
                    Name = productName,
                    Category1 = categoryName,
                    ItemType = itemType.ToString(),
                    Price = Convert.ToDecimal(price, CultureInfo.InvariantCulture).ToString("f8", CultureInfo.InvariantCulture),
                });
            }

            items.AddRange(shoppingCart.Select(sci =>
            {
                var product = _productService.GetProductById(sci.ProductId);

                var shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(product, _shoppingCartService.GetUnitPrice(sci), out var _);
                var shoppingCartUnitPriceWithDiscount     = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency);

                return(createItem(shoppingCartUnitPriceWithDiscount * sci.Quantity,
                                  product.Id.ToString(),
                                  product.Name,
                                  _categoryService.GetProductCategoriesByProductId(sci.ProductId).Aggregate(",", (all, pc) =>
                {
                    var res = _categoryService.GetCategoryById(pc.CategoryId).Name;
                    res = all == "," ? res : all + ", " + res;
                    return res;
                })));
            }));

            //shipping without tax
            var shoppingCartShipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(shoppingCart, false);

            if (shoppingCartShipping.HasValue && shoppingCartShipping.Value != 0)
            {
                items.Add(createItem(shoppingCartShipping ?? 0,
                                     Guid.NewGuid().ToString(),
                                     "Shipping",
                                     "Shipping",
                                     BasketItemType.VIRTUAL));
            }

            return(items);
        }
Пример #5
0
        /// <summary>
        /// Get transaction line items
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="storeId">Store identifier</param>
        /// <returns>List of transaction items</returns>
        private List <BasketItem> GetItems(Core.Domain.Customers.Customer customer, int storeId)
        {
            var items = new List <BasketItem>();

            //get current shopping cart
            var shoppingCart = _shoppingCartService.GetShoppingCart(customer, ShoppingCartType.ShoppingCart, storeId);

            //define function to create item
            BasketItem createItem(decimal price, string productId, string productName, string categoryName, BasketItemType itemType = BasketItemType.PHYSICAL)
            {
                return(new BasketItem
                {
                    Id = productId,
                    Name = productName,
                    Category1 = categoryName,
                    ItemType = itemType.ToString(),
                    Price = Convert.ToDecimal(price, CultureInfo.InvariantCulture).ToString("f8", CultureInfo.InvariantCulture),
                });
            }

            items.AddRange(shoppingCart.Where(shoppingCartItem => shoppingCartItem.ProductId != 0).Select(shoppingCartItem =>
            {
                var product = _productService.GetProductById(shoppingCartItem.ProductId);

                var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id).FirstOrDefault();

                var category = _categoryService.GetCategoryById(productCategories.CategoryId);

                return(createItem(product.Price * shoppingCartItem.Quantity,
                                  product.Id.ToString(),
                                  product.Name,
                                  category.Name));
            }));

            //LoadAllShippingRateComputationMethods
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);
            //shipping without tax
            decimal taxRate = 0;
            var     shoppingCartShipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(shoppingCart, false, out taxRate /*shippingRateComputationMethods*/);

            if (shoppingCartShipping.HasValue)
            {
                items.Add(createItem(shoppingCartShipping ?? 0,
                                     Guid.NewGuid().ToString(),
                                     "Shipping",
                                     "Shipping",
                                     BasketItemType.VIRTUAL));
            }

            return(items);
        }
Пример #6
0
        public void CanGetShippingTotalWithFixedShippingRateExcludingTax()
        {
            var product = _productService.GetProductBySku("FR_451_RB");

            product.AdditionalShippingCharge = 21.25M;
            product.IsFreeShipping           = false;
            _productService.UpdateProduct(product);

            var shipping =
                _orderTotalCalcService.GetShoppingCartShippingTotal(ShoppingCart, false, out var taxRate,
                                                                    out var appliedDiscounts);

            product.AdditionalShippingCharge = 0M;
            product.IsFreeShipping           = true;
            _productService.UpdateProduct(product);

            shipping.Should().NotBeNull();
            //10 - default fixed shipping rate, 42.5 - additional shipping change
            shipping.Should().Be(52.5M);
            appliedDiscounts.Count.Should().Be(0);
            //10 - default fixed tax rate
            taxRate.Should().Be(10);
        }
Пример #7
0
        public PayPalResponse CreatePayment(
            PayPalApiSettingsBase settings,
            PayPalSessionData session,
            List <OrganizedShoppingCartItem> cart,
            string providerSystemName,
            string returnUrl,
            string cancelUrl)
        {
            var store        = _services.StoreContext.CurrentStore;
            var customer     = _services.WorkContext.CurrentCustomer;
            var language     = _services.WorkContext.WorkingLanguage;
            var currencyCode = store.PrimaryStoreCurrency.CurrencyCode;

            var dateOfBirth = customer.GetAttribute <DateTime?>(SystemCustomerAttributeNames.DateOfBirth);

            Discount orderAppliedDiscount;
            List <AppliedGiftCard> appliedGiftCards;
            int     redeemedRewardPoints = 0;
            decimal redeemedRewardPointsAmount;
            decimal orderDiscountInclTax;
            decimal totalOrderItems = decimal.Zero;

            var includingTax = (_services.WorkContext.GetTaxDisplayTypeFor(customer, store.Id) == TaxDisplayType.IncludingTax);

            var shipping = (_orderTotalCalculationService.GetShoppingCartShippingTotal(cart) ?? decimal.Zero);

            var paymentFee = _paymentService.GetAdditionalHandlingFee(cart, providerSystemName);

            var total = (_orderTotalCalculationService.GetShoppingCartTotal(cart, out orderDiscountInclTax, out orderAppliedDiscount, out appliedGiftCards,
                                                                            out redeemedRewardPoints, out redeemedRewardPointsAmount) ?? decimal.Zero);

            var data          = new Dictionary <string, object>();
            var redirectUrls  = new Dictionary <string, object>();
            var payer         = new Dictionary <string, object>();
            var payerInfo     = new Dictionary <string, object>();
            var transaction   = new Dictionary <string, object>();
            var amount        = new Dictionary <string, object>();
            var amountDetails = new Dictionary <string, object>();
            var items         = new List <Dictionary <string, object> >();
            var itemList      = new Dictionary <string, object>();

            // "PayPal PLUS only supports transaction type “Sale” (instant settlement)"
            if (providerSystemName == PayPalPlusProvider.SystemName)
            {
                data.Add("intent", "sale");
            }
            else
            {
                data.Add("intent", settings.TransactMode == TransactMode.AuthorizeAndCapture ? "sale" : "authorize");
            }

            if (settings.ExperienceProfileId.HasValue())
            {
                data.Add("experience_profile_id", settings.ExperienceProfileId);
            }

            // redirect urls
            if (returnUrl.HasValue())
            {
                redirectUrls.Add("return_url", returnUrl);
            }

            if (cancelUrl.HasValue())
            {
                redirectUrls.Add("cancel_url", cancelUrl);
            }

            if (redirectUrls.Any())
            {
                data.Add("redirect_urls", redirectUrls);
            }

            // payer, payer_info
            if (dateOfBirth.HasValue)
            {
                payerInfo.Add("birth_date", dateOfBirth.Value.ToString("yyyy-MM-dd"));
            }
            if (customer.BillingAddress != null)
            {
                payerInfo.Add("billing_address", CreateAddress(customer.BillingAddress, false));
            }

            payer.Add("payment_method", "paypal");
            payer.Add("payer_info", payerInfo);
            data.Add("payer", payer);

            // line items
            foreach (var item in cart)
            {
                decimal unitPriceTaxRate = decimal.Zero;
                decimal unitPrice        = _priceCalculationService.GetUnitPrice(item, true);
                decimal productPrice     = _taxService.GetProductPrice(item.Item.Product, unitPrice, includingTax, customer, out unitPriceTaxRate);

                var line = new Dictionary <string, object>();
                line.Add("quantity", item.Item.Quantity);
                line.Add("name", item.Item.Product.GetLocalized(x => x.Name, language.Id, true, false).Truncate(127));
                line.Add("price", productPrice.FormatInvariant());
                line.Add("currency", currencyCode);
                line.Add("sku", item.Item.Product.Sku.Truncate(50));
                items.Add(line);

                totalOrderItems += (productPrice * item.Item.Quantity);
            }

            var itemsPlusMisc = (totalOrderItems + shipping + paymentFee);

            if (total != itemsPlusMisc)
            {
                var line = new Dictionary <string, object>();
                line.Add("quantity", "1");
                line.Add("name", T("Plugins.SmartStore.PayPal.Other").Text.Truncate(127));
                line.Add("price", (total - itemsPlusMisc).FormatInvariant());
                line.Add("currency", currencyCode);
                items.Add(line);

                totalOrderItems += (total - itemsPlusMisc);
            }

            itemList.Add("items", items);
            if (customer.ShippingAddress != null)
            {
                itemList.Add("shipping_address", CreateAddress(customer.ShippingAddress, true));
            }

            // transactions
            amountDetails.Add("shipping", shipping.FormatInvariant());
            amountDetails.Add("subtotal", totalOrderItems.FormatInvariant());
            if (!includingTax)
            {
                // "To avoid rounding errors we recommend not submitting tax amounts on line item basis.
                // Calculated tax amounts for the entire shopping basket may be submitted in the amount objects.
                // In this case the item amounts will be treated as amounts excluding tax.
                // In a B2C scenario, where taxes are included, no taxes should be submitted to PayPal."

                SortedDictionary <decimal, decimal> taxRates = null;
                var taxTotal = _orderTotalCalculationService.GetTaxTotal(cart, out taxRates);

                amountDetails.Add("tax", taxTotal.FormatInvariant());
            }
            if (paymentFee != decimal.Zero)
            {
                amountDetails.Add("handling_fee", paymentFee.FormatInvariant());
            }

            amount.Add("total", total.FormatInvariant());
            amount.Add("currency", currencyCode);
            amount.Add("details", amountDetails);

            transaction.Add("amount", amount);
            transaction.Add("item_list", itemList);
            transaction.Add("invoice_number", session.OrderGuid.ToString());

            data.Add("transactions", new List <Dictionary <string, object> > {
                transaction
            });

            var result = CallApi("POST", "/v1/payments/payment", session.AccessToken, settings, JsonConvert.SerializeObject(data));

            if (result.Success && result.Json != null)
            {
                result.Id = (string)result.Json.id;
            }

            //Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : ""));

            return(result);
        }
        /// <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);
        }
        /// <summary>
        /// Handle shopping cart changed event
        /// </summary>
        /// <param name="cartItem">Shopping cart item</param>
        public void HandleShoppingCartChangedEvent(ShoppingCartItem cartItem)
        {
            //whether marketing automation is enabled
            if (!_sendInBlueSettings.UseMarketingAutomation)
            {
                return;
            }

            try
            {
                //create API client
                var client = CreateMarketingAutomationClient();

                //first, try to identify current customer
                client.Identify(new Identify(cartItem.Customer.Email));

                //get shopping cart GUID
                var shoppingCartGuid = _genericAttributeService.GetAttribute <Guid?>(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute);

                //create track event object
                var trackEvent = new TrackEvent(cartItem.Customer.Email, string.Empty);

                //get current customer's shopping cart
                var cart = cartItem.Customer.ShoppingCartItems
                           .Where(item => item.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(_storeContext.CurrentStore.Id).ToList();

                if (cart.Any())
                {
                    //get URL helper
                    var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);

                    //get shopping cart amounts
                    _orderTotalCalculationService.GetShoppingCartSubTotal(cart, _workContext.TaxDisplayType == TaxDisplayType.IncludingTax,
                                                                          out var cartDiscount, out _, out var cartSubtotal, out _);
                    var cartTax      = _orderTotalCalculationService.GetTaxTotal(cart, false);
                    var cartShipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart);
                    var cartTotal    = _orderTotalCalculationService.GetShoppingCartTotal(cart, false, false);

                    //get products data by shopping cart items
                    var itemsData = cart.Where(item => item.Product != null).Select(item =>
                    {
                        //try to get product attribute combination
                        var combination = _productAttributeParser.FindProductAttributeCombination(item.Product, item.AttributesXml);

                        //get default product picture
                        var picture = _pictureService.GetProductPicture(item.Product, item.AttributesXml);

                        //get product SEO slug name
                        var seName = _urlRecordService.GetSeName(item.Product);

                        //create product data
                        return(new
                        {
                            id = item.Product.Id,
                            name = item.Product.Name,
                            variant_id = combination?.Id ?? item.Product.Id,
                            variant_name = combination?.Sku ?? item.Product.Name,
                            sku = combination?.Sku ?? item.Product.Sku,
                            category = item.Product.ProductCategories.Aggregate(",", (all, category) => {
                                var res = category.Category.Name;
                                res = all == "," ? res : all + ", " + res;
                                return res;
                            }),
                            url = urlHelper.RouteUrl("Product", new { SeName = seName }, _webHelper.CurrentRequestProtocol),
                            image = _pictureService.GetPictureUrl(picture),
                            quantity = item.Quantity,
                            price = _priceCalculationService.GetSubTotal(item)
                        });
                    }).ToArray();

                    //prepare cart data
                    var cartData = new
                    {
                        affiliation      = _storeContext.CurrentStore.Name,
                        subtotal         = cartSubtotal,
                        shipping         = cartShipping ?? decimal.Zero,
                        total_before_tax = cartSubtotal + cartShipping ?? decimal.Zero,
                        tax      = cartTax,
                        discount = cartDiscount,
                        revenue  = cartTotal ?? decimal.Zero,
                        url      = urlHelper.RouteUrl("ShoppingCart", null, _webHelper.CurrentRequestProtocol),
                        currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)?.CurrencyCode,
                        //gift_wrapping = string.Empty, //currently we can't get this value
                        items = itemsData
                    };

                    //if there is a single item in the cart, so the cart is just created
                    if (cart.Count == 1)
                    {
                        shoppingCartGuid = Guid.NewGuid();
                    }
                    else
                    {
                        //otherwise cart is updated
                        shoppingCartGuid = shoppingCartGuid ?? Guid.NewGuid();
                    }
                    trackEvent.EventName = SendinBlueDefaults.CartUpdatedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}", data = cartData };
                }
                else
                {
                    //there are no items in the cart, so the cart is deleted
                    shoppingCartGuid     = shoppingCartGuid ?? Guid.NewGuid();
                    trackEvent.EventName = SendinBlueDefaults.CartDeletedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}" };
                }

                //track event
                client.TrackEvent(trackEvent);

                //update GUID for the current customer's shopping cart
                _genericAttributeService.SaveAttribute(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute, shoppingCartGuid);
            }
            catch (Exception exception)
            {
                //log full error
                _logger.Error($"SendinBlue Marketing Automation error: {exception.Message}.", exception, cartItem.Customer);
            }
        }
        public void Can_get_shipping_total_with_fixed_shipping_rate_excluding_tax()
        {
            var product1 = new Product
            {
                Weight = 1.5M,
                Height = 2.5M,
                Length = 3.5M,
                Width  = 4.5M,
                AdditionalShippingCharge = 5.5M,
                IsShipEnabled            = true
            };

            _productService.InsertProduct(product1);

            var product2 = new Product
            {
                Weight = 11.5M,
                Height = 12.5M,
                Length = 13.5M,
                Width  = 14.5M,
                AdditionalShippingCharge = 6.5M,
                IsShipEnabled            = true
            };

            _productService.InsertProduct(product2);

            var sci1 = new ShoppingCartItem {
                AttributesXml = string.Empty, Quantity = 3, ProductId = product1.Id
            };
            var sci2 = new ShoppingCartItem {
                AttributesXml = string.Empty, Quantity = 4, ProductId = product2.Id
            };

            //sci3 is not shippable

            var product3 = new Product
            {
                Weight = 11.5M,
                Height = 12.5M,
                Length = 13.5M,
                Width  = 14.5M,
                AdditionalShippingCharge = 7.5M,
                IsShipEnabled            = false
            };

            _productService.InsertProduct(product3);

            var sci3 = new ShoppingCartItem {
                AttributesXml = string.Empty, Quantity = 5, ProductId = product3.Id
            };

            var cart = new List <ShoppingCartItem> {
                sci1, sci2, sci3
            };
            var customer = _customerService.GetCustomerById(1);

            cart.ForEach(sci => sci.CustomerId = customer.Id);

            var shipping =
                _orderTotalCalcService.GetShoppingCartShippingTotal(cart, false, out var taxRate,
                                                                    out var appliedDiscounts);

            shipping.Should().NotBeNull();
            //10 - default fixed shipping rate, 42.5 - additional shipping change
            shipping.Should().Be(52.5M);
            appliedDiscounts.Count.Should().Be(0);
            //10 - default fixed tax rate
            taxRate.Should().Be(10);
        }
        /// <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);
        }
Пример #12
0
        public void Can_get_shipping_total_with_fixed_shipping_rate_excluding_tax()
        {
            var sci1 = new ShoppingCartItem()
            {
                AttributesXml  = "",
                Quantity       = 3,
                ProductVariant = new ProductVariant()
                {
                    Id     = 1,
                    Weight = 1.5M,
                    Height = 2.5M,
                    Length = 3.5M,
                    Width  = 4.5M,
                    AdditionalShippingCharge = 5.5M,
                    IsShipEnabled            = true,
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                AttributesXml  = "",
                Quantity       = 4,
                ProductVariant = new ProductVariant()
                {
                    Id     = 2,
                    Weight = 11.5M,
                    Height = 12.5M,
                    Length = 13.5M,
                    Width  = 14.5M,
                    AdditionalShippingCharge = 6.5M,
                    IsShipEnabled            = true,
                }
            };

            //sci3 is not shippable
            var sci3 = new ShoppingCartItem()
            {
                AttributesXml  = "",
                Quantity       = 5,
                ProductVariant = new ProductVariant()
                {
                    Id     = 3,
                    Weight = 11.5M,
                    Height = 12.5M,
                    Length = 13.5M,
                    Width  = 14.5M,
                    AdditionalShippingCharge = 7.5M,
                    IsShipEnabled            = false,
                }
            };

            var cart = new List <ShoppingCartItem>()
            {
                sci1, sci2, sci3
            };
            var customer = new Customer();

            cart.ForEach(sci => sci.Customer   = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            decimal  taxRate         = decimal.Zero;
            Discount appliedDiscount = null;
            decimal? shipping        = null;


            shipping = _orderTotalCalcService.GetShoppingCartShippingTotal(cart, false, out taxRate, out appliedDiscount);
            shipping.ShouldNotBeNull();
            //10 - default fixed shipping rate, 42.5 - additional shipping change
            shipping.ShouldEqual(52.5);
            appliedDiscount.ShouldBeNull();
            //10 - default fixed tax rate
            taxRate.ShouldEqual(10);
        }
Пример #13
0
 public decimal GetShippingTotal(IList <ShoppingCartItem> cart)
 {
     return(_orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true).GetValueOrDefault());
 }
        /// <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);
        }
        /// <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);
        }
        /// <summary>
        /// Process a payment
        /// </summary>
        /// <param name="processPaymentRequest">Payment info required for an order processing</param>
        /// <returns>Process payment result</returns>
        public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            var     result   = new ProcessPaymentResult();
            decimal subTotal = 0;
            decimal?shipping = 0;
            decimal taxTotal = 0;
            SortedDictionary <decimal, decimal> taxRatesDictionary;
            var _products = new List <Models.ApiProduct>();
            var NotifyUrl = _manualPaymentSettings.MerchantBaseUrl + "PaymentSendSpend/IPNHandler/?order={0}&status={1}";
            var customer  = _customerService.GetCustomerById(processPaymentRequest.CustomerId);

            if (customer == null)
            {
                throw new Exception("Customer cannot be loaded");
            }

            var shoppingCart = customer.ShoppingCartItems
                               .Where(shoppingCartItem => shoppingCartItem.ShoppingCartType == ShoppingCartType.ShoppingCart)
                               .LimitPerStore(processPaymentRequest.StoreId).ToList();

            shipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(shoppingCart, false);
            taxTotal = _orderTotalCalculationService.GetTaxTotal(shoppingCart, out taxRatesDictionary);
            subTotal = shoppingCart.Sum(x => x.Product.Price * x.Quantity);
            shoppingCart.ForEach(x =>
            {
                _products.Add(new Models.ApiProduct
                {
                    merch_productId        = x.ProductId.ToString(),
                    merch_productName      = x.Product.Name,
                    merch_productQty       = x.Quantity,
                    merch_productUnitPrice = _currencyService.ConvertFromPrimaryStoreCurrency(x.Product.Price, _workContext.WorkingCurrency)
                });
            });

            var apiPayment = new Models.ApiPaymentRequest
            {
                merch_name                      = _manualPaymentSettings.MerchantName,
                apiId                           = _manualPaymentSettings.AppId,
                merch_uniqueId                  = _manualPaymentSettings.MerchantUniqueId,
                merch_baseURL                   = _manualPaymentSettings.MerchantBaseUrl,
                merch_orderId                   = processPaymentRequest.OrderGuid.ToString(),
                merch_orderDescription          = processPaymentRequest.InitialOrderId > 0 ? string.Format("Parent Order Id: {0}", processPaymentRequest.InitialOrderId) : "",
                merch_subTotal                  = _currencyService.ConvertFromPrimaryStoreCurrency(subTotal, _workContext.WorkingCurrency),
                merch_totalAmount               = _currencyService.ConvertFromPrimaryStoreCurrency(processPaymentRequest.OrderTotal, _workContext.WorkingCurrency),
                merch_currency                  = processPaymentRequest.CustomValues["Currency"].ToString(),
                merch_orderDateTime             = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")),
                merch_notifyUrl                 = NotifyUrl,
                merch_continueUrl               = _manualPaymentSettings.ContinueUrl,
                merch_Products                  = _products,
                customer_firstName              = customer.BillingAddress.FirstName,
                customer_lastName               = customer.BillingAddress.LastName,
                customer_Email                  = customer.BillingAddress.Email,
                customer_fmm_UserNameOrMobileNo = processPaymentRequest.CustomValues["PhoneNumber"].ToString(),
                merch_order_alive               = _manualPaymentSettings.MerchantOrderAlive,
                merch_shortOrderNo              = string.Empty,
                merch_shippingCost              = shipping.HasValue ? _currencyService.ConvertFromPrimaryStoreCurrency(shipping.Value, _workContext.WorkingCurrency) : 0,
                merch_otherCharges              = _currencyService.ConvertFromPrimaryStoreCurrency(taxTotal, _workContext.WorkingCurrency),
                merch_preAuth                   = _manualPaymentSettings.PreAuth,
                countryCode                     = processPaymentRequest.CustomValues["Country"].ToString()
            };

            using (var client = new HttpClient())
            {
                var content = new StringContent(JsonConvert.SerializeObject(apiPayment));
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                using (var res = client.PostAsync(String.Format("{0}api/v1/SecurePayment", _manualPaymentSettings.AppUrl), content))
                {
                    res.Wait();
                    if (res.Result.IsSuccessStatusCode)
                    {
                        var data = res.Result.Content.ReadAsStringAsync();
                        var ret  = JsonConvert.DeserializeObject <Models.ApiResponse>(data.Result.ToString());
                        switch (ret.responseCode.ToUpper())
                        {
                        case "APPROVED":
                            result.NewPaymentStatus = Core.Domain.Payments.PaymentStatus.Pending;
                            break;

                        default:
                            result.AddError(ret.responseText);
                            break;
                        }
                    }
                    else
                    {
                        result.AddError("Unable to process your request, Please try again later.");
                    }
                }
            }
            return(result);
        }
        private PaymentMessage GetPaymentoMessage(PayPalPlusBrasilPaymentSettings payPalPlusBrasilPaymentSettings, Customer customer)
        {
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.
                       Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                       .LimitPerStore(_storeContext.CurrentStore.Id)
                       .ToList();

            List <AppliedGiftCard> appliedGiftCards;
            List <Discount>        orderAppliedDiscounts;
            decimal orderDiscountAmount;
            int     redeemedRewardPoints;
            decimal redeemedRewardPointsAmount;
            var     orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart, out orderDiscountAmount,
                                                                                    out orderAppliedDiscounts, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount);

            decimal         tax;
            List <Discount> shippingTotalDiscounts;
            var             orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, out tax, out shippingTotalDiscounts);

            decimal         orderSubTotalDiscountAmount;
            List <Discount> orderSubTotalAppliedDiscounts;
            decimal         subTotalWithoutDiscountBase;
            decimal         subTotalWithDiscountBase;

            _orderTotalCalculationService.GetShoppingCartSubTotal(cart, true, out orderSubTotalDiscountAmount,
                                                                  out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);

            var paymentMessage = new PaymentMessage();

            paymentMessage.Intent = "sale";
            paymentMessage.Payer.PaymentMethod = "paypal";

            paymentMessage.ExperienceProfileId = payPalPlusBrasilPaymentSettings.IdProfileExperience;

            var transactionList = new List <Models.Message.Request.Transaction>();
            var itemTransaction = new Models.Message.Request.Transaction();

            itemTransaction.Amount.Currency         = "BRL";
            itemTransaction.Amount.Total            = orderTotal.Value.ToString("N", new CultureInfo("en-US"));
            itemTransaction.Amount.Details.Shipping = orderShippingTotalInclTax.Value.ToString("N", new CultureInfo("en-US"));
            itemTransaction.Amount.Details.Subtotal = subTotalWithoutDiscountBase.ToString("N", new CultureInfo("en-US"));
            itemTransaction.Amount.Details.Discount = (orderDiscountAmount + orderSubTotalDiscountAmount).ToString("N", new CultureInfo("en-US"));

            itemTransaction.Description = "This is the payment transaction description";
            itemTransaction.PaymentOptions.AllowedPaymentMethod = "IMMEDIATE_PAY";
            itemTransaction.InvoiceNumber = string.Empty;


            var number     = string.Empty;
            var complement = string.Empty;

            new AddressHelper(_addressAttributeParser, _workContext).GetCustomNumberAndComplement(customer.ShippingAddress.CustomAttributes,
                                                                                                  out number, out complement);

            itemTransaction.ItemList.ShippingAddress.RecipientName = AddressHelper.GetFullName(customer.ShippingAddress);
            itemTransaction.ItemList.ShippingAddress.Line1         = customer.ShippingAddress.Address1;
            itemTransaction.ItemList.ShippingAddress.Line2         = complement;
            itemTransaction.ItemList.ShippingAddress.City          = customer.ShippingAddress.City;
            itemTransaction.ItemList.ShippingAddress.CountryCode   = customer.ShippingAddress.Country.TwoLetterIsoCode;
            itemTransaction.ItemList.ShippingAddress.PostalCode    = customer.ShippingAddress.ZipPostalCode;
            itemTransaction.ItemList.ShippingAddress.State         = customer.ShippingAddress.StateProvince.Name;
            itemTransaction.ItemList.ShippingAddress.Phone         = AddressHelper.FormatarCelular(customer.ShippingAddress.PhoneNumber);

            var itemList = new List <Models.Message.Request.Item>();

            foreach (var itemCart in cart)
            {
                var item = new Models.Message.Request.Item();

                item.Name        = itemCart.Product.Name;
                item.Description = itemCart.Product.ShortDescription;
                item.Quantity    = itemCart.Quantity;

                List <Discount> scDiscounts;
                decimal         discountAmount;

                var scUnitPrice = _priceCalculationService.GetUnitPrice(itemCart, true, out discountAmount, out scDiscounts);

                item.Price    = decimal.Round(scUnitPrice, 2).ToString("N2", new CultureInfo("en-US"));
                item.Sku      = itemCart.Product.Sku;
                item.Currency = "BRL";

                itemList.Add(item);
            }

            itemTransaction.ItemList.Items = itemList.ToArray();

            transactionList.Add(itemTransaction);

            paymentMessage.Transactions = transactionList.ToArray();

            string returnUrl       = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalPlusBrasil/IPNHandler";
            string cancelReturnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalPlusBrasil/IPNHandler";

            paymentMessage.RedirectUrls.ReturnUrl = new Uri(returnUrl);
            paymentMessage.RedirectUrls.CancelUrl = new Uri(cancelReturnUrl);


            return(paymentMessage);
        }
        /// <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);
        }