示例#1
0
        /// <summary>
        /// Gets an additional handling fee of a payment method
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <param name="paymentMethodSystemName">Payment method system name</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the additional handling fee
        /// </returns>
        public virtual async Task <decimal> GetAdditionalHandlingFeeAsync(IList <ShoppingCartItem> cart, string paymentMethodSystemName)
        {
            if (string.IsNullOrEmpty(paymentMethodSystemName))
            {
                return(decimal.Zero);
            }

            var customer = await _customerService.GetCustomerByIdAsync(cart.FirstOrDefault()?.CustomerId ?? 0);

            var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName, customer, cart.FirstOrDefault()?.StoreId ?? 0);

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

            var result = await paymentMethod.GetAdditionalHandlingFeeAsync(cart);

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

            if (!_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                return(result);
            }

            result = await _priceCalculationService.RoundPriceAsync(result);

            return(result);
        }
示例#2
0
        /// <summary>
        /// Formats the price
        /// </summary>
        /// <param name="price">Price</param>
        /// <param name="showCurrency">A value indicating whether to show a currency</param>
        /// <param name="targetCurrency">Target currency</param>
        /// <param name="languageId">Language</param>
        /// <param name="priceIncludesTax">A value indicating whether price includes tax</param>
        /// <param name="showTax">A value indicating whether to show tax suffix</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the price
        /// </returns>
        public virtual async Task <string> FormatPriceAsync(decimal price, bool showCurrency,
                                                            Currency targetCurrency, int languageId, bool priceIncludesTax, bool showTax)
        {
            //we should round it no matter of "ShoppingCartSettings.RoundPricesDuringCalculation" setting
            price = await _priceCalculationService.RoundPriceAsync(price, targetCurrency);

            var currencyString = GetCurrencyString(price, showCurrency, targetCurrency);

            if (!showTax)
            {
                return(currencyString);
            }

            //show tax suffix
            string formatStr;

            if (priceIncludesTax)
            {
                formatStr = await _localizationService.GetResourceAsync("Products.InclTaxSuffix", languageId, false);

                if (string.IsNullOrEmpty(formatStr))
                {
                    formatStr = "{0} incl tax";
                }
            }
            else
            {
                formatStr = await _localizationService.GetResourceAsync("Products.ExclTaxSuffix", languageId, false);

                if (string.IsNullOrEmpty(formatStr))
                {
                    formatStr = "{0} excl tax";
                }
            }

            return(string.Format(formatStr, currencyString));
        }
示例#3
0
        /// <summary>
        ///  Gets available shipping options
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <param name="shippingAddress">Shipping address</param>
        /// <param name="customer">Load records allowed only to a specified customer; pass null to ignore ACL permissions</param>
        /// <param name="allowedShippingRateComputationMethodSystemName">Filter by shipping rate computation method identifier; null to load shipping options of all shipping rate computation methods</param>
        /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param>
        /// <returns>Shipping options</returns>
        public virtual async Task <GetShippingOptionResponse> GetShippingOptionsAsync(IList <ShoppingCartItem> cart,
                                                                                      Address shippingAddress, Customer customer = null, string allowedShippingRateComputationMethodSystemName = "",
                                                                                      int storeId = 0)
        {
            if (cart == null)
            {
                throw new ArgumentNullException(nameof(cart));
            }

            var result = new GetShippingOptionResponse();

            //create a package
            var(shippingOptionRequests, shippingFromMultipleLocations) = await CreateShippingOptionRequestsAsync(cart, shippingAddress, storeId);

            result.ShippingFromMultipleLocations = shippingFromMultipleLocations;

            var shippingRateComputationMethods = await _shippingPluginManager
                                                 .LoadActivePluginsAsync(customer, storeId, allowedShippingRateComputationMethodSystemName);

            if (!shippingRateComputationMethods.Any())
            {
                return(result);
            }

            //request shipping options from each shipping rate computation methods
            foreach (var srcm in shippingRateComputationMethods)
            {
                //request shipping options (separately for each package-request)
                IList <ShippingOption> srcmShippingOptions = null;
                foreach (var shippingOptionRequest in shippingOptionRequests)
                {
                    var getShippingOptionResponse = await srcm.GetShippingOptionsAsync(shippingOptionRequest);

                    if (getShippingOptionResponse.Success)
                    {
                        //success
                        if (srcmShippingOptions == null)
                        {
                            //first shipping option request
                            srcmShippingOptions = getShippingOptionResponse.ShippingOptions;
                        }
                        else
                        {
                            //get shipping options which already exist for prior requested packages for this scrm (i.e. common options)
                            srcmShippingOptions = srcmShippingOptions
                                                  .Where(existingso => getShippingOptionResponse.ShippingOptions.Any(newso => newso.Name == existingso.Name))
                                                  .ToList();

                            //and sum the rates
                            foreach (var existingso in srcmShippingOptions)
                            {
                                existingso.Rate += getShippingOptionResponse
                                                   .ShippingOptions
                                                   .First(newso => newso.Name == existingso.Name)
                                                   .Rate;
                            }
                        }
                    }
                    else
                    {
                        //errors
                        foreach (var error in getShippingOptionResponse.Errors)
                        {
                            result.AddError(error);
                            await _logger.WarningAsync($"Shipping ({srcm.PluginDescriptor.FriendlyName}). {error}");
                        }
                        //clear the shipping options in this case
                        srcmShippingOptions = new List <ShippingOption>();
                        break;
                    }
                }

                //add this scrm's options to the result
                if (srcmShippingOptions == null)
                {
                    continue;
                }

                foreach (var so in srcmShippingOptions)
                {
                    //set system name if not set yet
                    if (string.IsNullOrEmpty(so.ShippingRateComputationMethodSystemName))
                    {
                        so.ShippingRateComputationMethodSystemName = srcm.PluginDescriptor.SystemName;
                    }
                    if (_shoppingCartSettings.RoundPricesDuringCalculation)
                    {
                        so.Rate = await _priceCalculationService.RoundPriceAsync(so.Rate);
                    }
                    result.ShippingOptions.Add(so);
                }
            }

            if (_shippingSettings.ReturnValidOptionsIfThereAreAny)
            {
                //return valid options if there are any (no matter of the errors returned by other shipping rate computation methods).
                if (result.ShippingOptions.Any() && result.Errors.Any())
                {
                    result.Errors.Clear();
                }
            }

            //no shipping options loaded
            if (!result.ShippingOptions.Any() && !result.Errors.Any())
            {
                result.Errors.Add(await _localizationService.GetResourceAsync("Checkout.ShippingOptionCouldNotBeLoaded"));
            }

            return(result);
        }
示例#4
0
        public async override Task <(decimal unitPrice, decimal discountAmount, List <Discount> appliedDiscounts)> GetUnitPriceAsync(
            Product product,
            Customer customer,
            ShoppingCartType shoppingCartType,
            int quantity,
            string attributesXml,
            decimal customerEnteredPrice,
            DateTime?rentalStartDate, DateTime?rentalEndDate,
            bool includeDiscounts)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            if (customer == null)
            {
                throw new ArgumentNullException(nameof(customer));
            }

            var discountAmount   = decimal.Zero;
            var appliedDiscounts = new List <Discount>();

            decimal finalPrice;

            var combination = await _productAttributeParser.FindProductAttributeCombinationAsync(product, attributesXml);

            if (combination?.OverriddenPrice.HasValue ?? false)
            {
                (_, finalPrice, discountAmount, appliedDiscounts) = await _priceCalculationService.GetFinalPriceAsync(product,
                                                                                                                      customer,
                                                                                                                      combination.OverriddenPrice.Value,
                                                                                                                      decimal.Zero,
                                                                                                                      includeDiscounts,
                                                                                                                      quantity,
                                                                                                                      product.IsRental?rentalStartDate : null,
                                                                                                                      product.IsRental?rentalEndDate : null);
            }
            else
            {
                // custom
                // summarize price of all attributes except warranties (warranties processed separately)
                decimal warrantyPrice = decimal.Zero;
                ProductAttributeMapping warrantyPam = await _attributeUtilities.GetWarrantyAttributeMappingAsync(attributesXml);

                //summarize price of all attributes
                var attributesTotalPrice = decimal.Zero;
                var attributeValues      = await _productAttributeParser.ParseProductAttributeValuesAsync(attributesXml);

                // custom - considers warranties
                if (attributeValues != null)
                {
                    foreach (var attributeValue in attributeValues)
                    {
                        if (warrantyPam != null && attributeValue.ProductAttributeMappingId == warrantyPam.Id)
                        {
                            warrantyPrice =
                                await _priceCalculationService.GetProductAttributeValuePriceAdjustmentAsync(
                                    product,
                                    attributeValue,
                                    customer,
                                    product.CustomerEntersPrice?(decimal?)customerEnteredPrice : null
                                    );
                        }
                        else
                        {
                            attributesTotalPrice += await _priceCalculationService.GetProductAttributeValuePriceAdjustmentAsync(
                                product,
                                attributeValue,
                                customer,
                                product.CustomerEntersPrice?(decimal?)customerEnteredPrice : null
                                );
                        }
                    }
                }

                //get price of a product (with previously calculated price of all attributes)
                if (product.CustomerEntersPrice)
                {
                    finalPrice = customerEnteredPrice;
                }
                else
                {
                    int qty;
                    if (_shoppingCartSettings.GroupTierPricesForDistinctShoppingCartItems)
                    {
                        //the same products with distinct product attributes could be stored as distinct "ShoppingCartItem" records
                        //so let's find how many of the current products are in the cart
                        qty = (await GetShoppingCartAsync(customer, shoppingCartType: shoppingCartType, productId: product.Id))
                              .Sum(x => x.Quantity);

                        if (qty == 0)
                        {
                            qty = quantity;
                        }
                    }
                    else
                    {
                        qty = quantity;
                    }

                    (_, finalPrice, discountAmount, appliedDiscounts) = await _priceCalculationService.GetFinalPriceAsync(product,
                                                                                                                          customer,
                                                                                                                          attributesTotalPrice,
                                                                                                                          includeDiscounts,
                                                                                                                          qty,
                                                                                                                          product.IsRental?rentalStartDate : null,
                                                                                                                          product.IsRental?rentalEndDate : null);

                    finalPrice += warrantyPrice;
                }
            }

            //rounding
            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                finalPrice = await _priceCalculationService.RoundPriceAsync(finalPrice);
            }

            return(finalPrice, discountAmount, appliedDiscounts);
        }
示例#5
0
        public async Task <IList <YahooHeaderRow> > GetYahooHeaderRowsAsync(Order order)
        {
            var result = new List <YahooHeaderRow>();

            var orderItems = await _customOrderService.GetOrderItemsAsync(order.Id);

            if (!orderItems.Any())
            {
                return(result);
            }

            var splitItems = orderItems.SplitByPickupAndShipping();
            var address    = await _addressService.GetAddressByIdAsync(order.BillingAddressId);

            var stateAbbv    = (await _stateProvinceService.GetStateProvinceByAddressAsync(address)).Abbreviation;
            var country      = (await _countryService.GetCountryByAddressAsync(address)).Name;
            var cardName     = _encryptionService.DecryptText(order.CardName, _securitySettings.EncryptionKey);
            var cardNumber   = _encryptionService.DecryptText(order.CardNumber, _securitySettings.EncryptionKey);
            var cardMonth    = _encryptionService.DecryptText(order.CardExpirationMonth, _securitySettings.EncryptionKey);
            var cardYear     = _encryptionService.DecryptText(order.CardExpirationYear, _securitySettings.EncryptionKey);
            var cardCvv2     = _encryptionService.DecryptText(order.CardCvv2, _securitySettings.EncryptionKey);
            var customValues = _paymentService.DeserializeCustomValues(order);
            var ccRefNo      = customValues != null?
                               customValues.Where(cv => cv.Key == "CC_REFNO")
                               .Select(cv => cv.Value?.ToString())
                               .FirstOrDefault() :
                                   null;

            var pickupItems = splitItems.pickupItems;

            if (pickupItems.Any())
            {
                decimal backendOrderTax, backendOrderTotal;
                CalculateValues(pickupItems, out backendOrderTax, out backendOrderTotal);

                var giftCard = await CalculateGiftCardAsync(order, backendOrderTotal);

                result.Add(new YahooHeaderRow(
                               _settings.OrderIdPrefix,
                               order,
                               address,
                               stateAbbv,
                               country,
                               cardName,
                               cardNumber,
                               cardMonth,
                               cardYear,
                               cardCvv2,
                               await _priceCalculationService.RoundPriceAsync(backendOrderTax),
                               await _priceCalculationService.RoundPriceAsync(backendOrderTotal),
                               giftCard.GiftCardCode,
                               giftCard.GiftCardUsage,
                               ccRefNo
                               ));
            }

            var shippingItems = splitItems.shippingItems;

            if (shippingItems.Any())
            {
                decimal homeDeliveryCost = 0;
                decimal shippingCost     = 0;

                homeDeliveryCost = await _homeDeliveryCostService.GetHomeDeliveryCostAsync(shippingItems);

                shippingCost = order.OrderShippingExclTax - homeDeliveryCost;

                decimal backendOrderTax, backendOrderTotal;
                CalculateValues(shippingItems, out backendOrderTax, out backendOrderTotal);

                decimal shippingTax = order.OrderShippingInclTax - order.OrderShippingExclTax;
                backendOrderTax   += shippingTax;
                backendOrderTotal += order.OrderShippingInclTax;

                var giftCard = await CalculateGiftCardAsync(order, backendOrderTotal);

                result.Add(new YahooHeaderRowShipping(
                               _settings.OrderIdPrefix,
                               order,
                               address,
                               stateAbbv,
                               country,
                               cardName,
                               cardNumber,
                               cardMonth,
                               cardYear,
                               cardCvv2,
                               await _priceCalculationService.RoundPriceAsync(backendOrderTax),
                               await _priceCalculationService.RoundPriceAsync(shippingCost),
                               await _priceCalculationService.RoundPriceAsync(homeDeliveryCost),
                               await _priceCalculationService.RoundPriceAsync(backendOrderTotal),
                               giftCard.GiftCardCode,
                               giftCard.GiftCardUsage,
                               ccRefNo
                               ));
            }

            return(result);
        }
        public override async Task <(decimal discountAmount, List <Discount> appliedDiscounts, decimal subTotalWithoutDiscount, decimal subTotalWithDiscount, SortedDictionary <decimal, decimal> taxRates)> GetShoppingCartSubTotalAsync(
            IList <ShoppingCartItem> cart,
            bool includingTax)
        {
            var discountAmount          = decimal.Zero;
            var appliedDiscounts        = new List <Discount>();
            var subTotalWithoutDiscount = decimal.Zero;
            var subTotalWithDiscount    = decimal.Zero;
            var taxRates = new SortedDictionary <decimal, decimal>();

            if (!cart.Any())
            {
                return(discountAmount, appliedDiscounts, subTotalWithoutDiscount, subTotalWithDiscount, taxRates);
            }

            //get the customer
            var customer = await _customerService.GetShoppingCartCustomerAsync(cart);

            //sub totals
            var subTotalExclTaxWithoutDiscount = decimal.Zero;
            var subTotalInclTaxWithoutDiscount = decimal.Zero;

            foreach (var shoppingCartItem in cart)
            {
                var sciSubTotal = (await _shoppingCartService.GetSubTotalAsync(shoppingCartItem, true)).subTotal;
                var product     = await _productService.GetProductByIdAsync(shoppingCartItem.ProductId);

                var(sciExclTax, taxRate) = await _taxService.GetProductPriceAsync(product, sciSubTotal, false, customer);

                // custom
                var(_, sciInclTax) = await _warrantyTaxService.CalculateWarrantyTaxAsync(shoppingCartItem, customer, sciExclTax);

                subTotalExclTaxWithoutDiscount += sciExclTax;
                subTotalInclTaxWithoutDiscount += sciInclTax;

                //tax rates
                var sciTax = sciInclTax - sciExclTax;
                if (taxRate <= decimal.Zero || sciTax <= decimal.Zero)
                {
                    continue;
                }

                if (!taxRates.ContainsKey(taxRate))
                {
                    taxRates.Add(taxRate, sciTax);
                }
                else
                {
                    taxRates[taxRate] = taxRates[taxRate] + sciTax;
                }
            }

            //checkout attributes
            if (customer != null)
            {
                var checkoutAttributesXml = await _genericAttributeService.GetAttributeAsync <string>(customer, NopCustomerDefaults.CheckoutAttributes, (await _storeContext.GetCurrentStoreAsync()).Id);

                var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml);
                if (attributeValues != null)
                {
                    await foreach (var(attribute, values) in attributeValues)
                    {
                        await foreach (var attributeValue in values)
                        {
                            var(caExclTax, taxRate) = await _taxService.GetCheckoutAttributePriceAsync(attribute, attributeValue, false, customer);

                            var(caInclTax, _) = await _taxService.GetCheckoutAttributePriceAsync(attribute, attributeValue, true, customer);

                            subTotalExclTaxWithoutDiscount += caExclTax;
                            subTotalInclTaxWithoutDiscount += caInclTax;

                            //tax rates
                            var caTax = caInclTax - caExclTax;
                            if (taxRate <= decimal.Zero || caTax <= decimal.Zero)
                            {
                                continue;
                            }

                            if (!taxRates.ContainsKey(taxRate))
                            {
                                taxRates.Add(taxRate, caTax);
                            }
                            else
                            {
                                taxRates[taxRate] = taxRates[taxRate] + caTax;
                            }
                        }
                    }
                }
            }

            //subtotal without discount
            subTotalWithoutDiscount = includingTax ? subTotalInclTaxWithoutDiscount : subTotalExclTaxWithoutDiscount;
            if (subTotalWithoutDiscount < decimal.Zero)
            {
                subTotalWithoutDiscount = decimal.Zero;
            }

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                subTotalWithoutDiscount = await _priceCalculationService.RoundPriceAsync(subTotalWithoutDiscount);
            }

            //We calculate discount amount on order subtotal excl tax (discount first)
            //calculate discount amount ('Applied to order subtotal' discount)
            decimal discountAmountExclTax;

            (discountAmountExclTax, appliedDiscounts) = await GetOrderSubtotalDiscountAsync(customer, subTotalExclTaxWithoutDiscount);

            if (subTotalExclTaxWithoutDiscount < discountAmountExclTax)
            {
                discountAmountExclTax = subTotalExclTaxWithoutDiscount;
            }
            var discountAmountInclTax = discountAmountExclTax;
            //subtotal with discount (excl tax)
            var subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax;
            var subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount;

            //add tax for shopping items & checkout attributes
            var tempTaxRates = new Dictionary <decimal, decimal>(taxRates);

            foreach (var kvp in tempTaxRates)
            {
                var taxRate  = kvp.Key;
                var taxValue = kvp.Value;

                if (taxValue == decimal.Zero)
                {
                    continue;
                }

                //discount the tax amount that applies to subtotal items
                if (subTotalExclTaxWithoutDiscount > decimal.Zero)
                {
                    var discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount);
                    discountAmountInclTax += discountTax;
                    taxValue = taxRates[taxRate] - discountTax;
                    if (_shoppingCartSettings.RoundPricesDuringCalculation)
                    {
                        taxValue = await _priceCalculationService.RoundPriceAsync(taxValue);
                    }
                    taxRates[taxRate] = taxValue;
                }

                //subtotal with discount (incl tax)
                subTotalInclTaxWithDiscount += taxValue;
            }

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                discountAmountInclTax = await _priceCalculationService.RoundPriceAsync(discountAmountInclTax);

                discountAmountExclTax = await _priceCalculationService.RoundPriceAsync(discountAmountExclTax);
            }

            if (includingTax)
            {
                subTotalWithDiscount = subTotalInclTaxWithDiscount;
                discountAmount       = discountAmountInclTax;
            }
            else
            {
                subTotalWithDiscount = subTotalExclTaxWithDiscount;
                discountAmount       = discountAmountExclTax;
            }

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

            if (_shoppingCartSettings.RoundPricesDuringCalculation)
            {
                subTotalWithDiscount = await _priceCalculationService.RoundPriceAsync(subTotalWithDiscount);
            }

            return(discountAmount, appliedDiscounts, subTotalWithoutDiscount, subTotalWithDiscount, taxRates);
        }