/// <summary> /// Gets a value indicating whether shipping is free /// </summary> /// <param name="cart">Cart</param> /// <returns>A value indicating whether shipping is free</returns> public virtual bool IsFreeShipping(IList<ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); if (customer != null) { //check whether customer is in a customer role with free shipping applied var customerRoles = customer.CustomerRoles.Where(cr => cr.Active); foreach (var customerRole in customerRoles) if (customerRole.FreeShipping) return true; } bool shoppingCartRequiresShipping = cart.RequiresShipping(); if (!shoppingCartRequiresShipping) return true; //check whether all shopping cart items are marked as free shipping bool allItemsAreFreeShipping = true; foreach (var sc in cart) { if (sc.IsShipEnabled && !sc.IsFreeShipping) { allItemsAreFreeShipping = false; break; } } if (allItemsAreFreeShipping) return true; //free shipping over $X if (_shippingSettings.FreeShippingOverXEnabled) { //check whether we have subtotal enough to have free shipping decimal subTotalDiscountAmount = decimal.Zero; Discount subTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; GetShoppingCartSubTotal(cart, _shippingSettings.FreeShippingOverXIncludingTax, out subTotalDiscountAmount, out subTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); if (subTotalWithDiscountBase > _shippingSettings.FreeShippingOverXValue) return true; } //otherwise, return false return false; }
/// <summary> /// Gets shopping cart total /// </summary> /// <param name="cart">Cart</param> /// <param name="appliedGiftCards">Applied gift cards</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscount">Applied discount</param> /// <param name="redeemedRewardPoints">Reward points to redeem</param> /// <param name="redeemedRewardPointsAmount">Reward points amount in primary store currency to redeem</param> /// <param name="ignoreRewardPonts">A value indicating whether we should ignore reward points (if enabled and a customer is going to use them)</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating order total</param> /// <returns>Shopping cart total;Null if shopping cart total couldn't be calculated now</returns> public virtual decimal? GetShoppingCartTotal(IList<ShoppingCartItem> cart, out decimal discountAmount, out Discount appliedDiscount, out List<AppliedGiftCard> appliedGiftCards, out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount, bool ignoreRewardPonts = false, bool usePaymentMethodAdditionalFee = true) { redeemedRewardPoints = 0; redeemedRewardPointsAmount = decimal.Zero; var customer = cart.GetCustomer(); string paymentMethodSystemName = ""; if (customer != null) { paymentMethodSystemName = customer.GetAttribute<string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //subtotal without tax decimal subtotalBase = decimal.Zero; decimal orderSubTotalDiscountAmount = decimal.Zero; Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; GetShoppingCartSubTotal(cart, false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); //subtotal with discount subtotalBase = subTotalWithDiscountBase; //shipping without tax decimal? shoppingCartShipping = GetShoppingCartShippingTotal(cart, false); //payment method additional fee without tax decimal paymentMethodAdditionalFeeWithoutTax = decimal.Zero; if (usePaymentMethodAdditionalFee && !String.IsNullOrEmpty(paymentMethodSystemName)) { decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); paymentMethodAdditionalFeeWithoutTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer); } //tax decimal shoppingCartTax = GetTaxTotal(cart, usePaymentMethodAdditionalFee); //order total decimal resultTemp = decimal.Zero; resultTemp += subtotalBase; if (shoppingCartShipping.HasValue) { resultTemp += shoppingCartShipping.Value; } resultTemp += paymentMethodAdditionalFeeWithoutTax; resultTemp += shoppingCartTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) resultTemp = Math.Round(resultTemp, 2); #region Order total discount discountAmount = GetOrderTotalDiscount(customer, resultTemp, out appliedDiscount); //sub totals with discount if (resultTemp < discountAmount) discountAmount = resultTemp; //reduce subtotal resultTemp -= discountAmount; if (resultTemp < decimal.Zero) resultTemp = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) resultTemp = Math.Round(resultTemp, 2); #endregion #region Applied gift cards //let's apply gift cards now (gift cards that can be used) appliedGiftCards = new List<AppliedGiftCard>(); if (!cart.IsRecurring()) { //we don't apply gift cards for recurring products var giftCards = _giftCardService.GetActiveGiftCardsAppliedByCustomer(customer); if (giftCards!=null) foreach (var gc in giftCards) if (resultTemp > decimal.Zero) { decimal remainingAmount = gc.GetGiftCardRemainingAmount(); decimal amountCanBeUsed = decimal.Zero; if (resultTemp > remainingAmount) amountCanBeUsed = remainingAmount; else amountCanBeUsed = resultTemp; //reduce subtotal resultTemp -= amountCanBeUsed; var appliedGiftCard = new AppliedGiftCard(); appliedGiftCard.GiftCard = gc; appliedGiftCard.AmountCanBeUsed = amountCanBeUsed; appliedGiftCards.Add(appliedGiftCard); } } #endregion if (resultTemp < decimal.Zero) resultTemp = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) resultTemp = Math.Round(resultTemp, 2); decimal? orderTotal = null; if (!shoppingCartShipping.HasValue) { //return null if we have errors orderTotal = null; return orderTotal; } else { //return result if we have no errors orderTotal = resultTemp; } #region Reward points if (_rewardPointsSettings.Enabled && !ignoreRewardPonts && customer.GetAttribute<bool>(SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, _genericAttributeService, _storeContext.CurrentStore.Id)) { int rewardPointsBalance = customer.GetRewardPointsBalance(); if (CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance)) { decimal rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); if (orderTotal.HasValue && orderTotal.Value > decimal.Zero) { if (orderTotal.Value > rewardPointsBalanceAmount) { redeemedRewardPoints = rewardPointsBalance; redeemedRewardPointsAmount = rewardPointsBalanceAmount; } else { redeemedRewardPointsAmount = orderTotal.Value; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } } } #endregion if (orderTotal.HasValue) { orderTotal = orderTotal.Value - redeemedRewardPointsAmount; if (_shoppingCartSettings.RoundPricesDuringCalculation) orderTotal = Math.Round(orderTotal.Value, 2); return orderTotal; } else return null; }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal? GetShoppingCartShippingTotal(IList<ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out Discount appliedDiscount) { decimal? shippingTotal = null; decimal? shippingTotalTaxed = null; appliedDiscount = null; taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = IsFreeShipping(cart); if (isFreeShipping) return decimal.Zero; ShippingOption shippingOption = null; if (customer != null) shippingOption = customer.GetAttribute<ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _genericAttributeService, _storeContext.CurrentStore.Id); if (shippingOption != null) { //use last shipping option (get from cache) //adjust shipping rate shippingTotal = AdjustShippingRate(shippingOption.Rate, cart, out appliedDiscount); } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) shippingAddress = customer.ShippingAddress; var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id); if (shippingRateComputationMethods == null || shippingRateComputationMethods.Count == 0) throw new NopException("Shipping rate computation method could not be loaded"); if (shippingRateComputationMethods.Count == 1) { var shippingRateComputationMethod = shippingRateComputationMethods[0]; var shippingOptionRequests = _shippingService.CreateShippingOptionRequests(cart, shippingAddress); decimal? fixedRate = null; foreach (var shippingOptionRequest in shippingOptionRequests) { //calculate fixed rates for each request-package var fixedRateTmp = shippingRateComputationMethod.GetFixedRate(shippingOptionRequest); if (fixedRateTmp.HasValue) { if (!fixedRate.HasValue) fixedRate = decimal.Zero; fixedRate += fixedRateTmp.Value; } } if (fixedRate.HasValue) { //adjust shipping rate shippingTotal = AdjustShippingRate(fixedRate.Value, cart, out appliedDiscount); } } } if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) shippingTotal = decimal.Zero; //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotal = Math.Round(shippingTotal.Value, 2); shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalTaxed = Math.Round(shippingTotalTaxed.Value, 2); } return shippingTotalTaxed; }
/// <summary> /// Create shipment packages (requests) from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <returns>Shipment packages (requests)</returns> public virtual IList<GetShippingOptionRequest> CreateShippingOptionRequests(IList<ShoppingCartItem> cart, Address shippingAddress) { //if we always ship from the default shipping origin, then there's only one request //if we ship from warehouses, then there could be several requests //key - warehouse identifier (0 - default shipping origin) //value - request var requests = new Dictionary<int, GetShippingOptionRequest>(); foreach (var sci in cart) { if (!sci.IsShipEnabled) continue; Warehouse warehouse = null; if (_shippingSettings.UseWarehouseLocation) { warehouse = GetWarehouseById(sci.Product.WarehouseId); } GetShippingOptionRequest request = null; if (requests.ContainsKey(warehouse != null ? warehouse.Id : 0)) { request = requests[warehouse != null ? warehouse.Id : 0]; //add item request.Items.Add(sci); } else { request = new GetShippingOptionRequest(); //add item request.Items.Add(sci); //customer request.Customer = cart.GetCustomer(); //ship to request.ShippingAddress = shippingAddress; //ship from Address originAddress = null; if (warehouse != null) { //warehouse address originAddress = _addressService.GetAddressById(warehouse.AddressId); } if (originAddress == null) { //no warehouse address. in this case use the default shipping origin originAddress = _addressService.GetAddressById(_shippingSettings.ShippingOriginAddressId); } if (originAddress != null) { request.CountryFrom = originAddress.Country; request.StateProvinceFrom = originAddress.StateProvince; request.ZipPostalCodeFrom = originAddress.ZipPostalCode; request.CityFrom = originAddress.City; request.AddressFrom = originAddress.Address1; } requests.Add(warehouse != null ? warehouse.Id : 0, request); } } return requests.Values.ToList(); }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal? GetShoppingCartShippingTotal(IList<OrganizedShoppingCartItem> cart, bool includingTax, out decimal taxRate, out Discount appliedDiscount) { decimal? shippingTotal = null; decimal? shippingTotalTaxed = null; appliedDiscount = null; taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = IsFreeShipping(cart); if (isFreeShipping) return decimal.Zero; ShippingOption shippingOption = null; if (customer != null) shippingOption = customer.GetAttribute<ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _genericAttributeService, _storeContext.CurrentStore.Id); if (shippingOption != null) { //use last shipping option (get from cache) //adjust shipping rate var shippingMethods = _shippingService.GetAllShippingMethods(); shippingTotal = AdjustShippingRate(shippingOption.Rate, cart, shippingOption.Name, shippingMethods, out appliedDiscount); } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) shippingAddress = customer.ShippingAddress; var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id); if (!shippingRateComputationMethods.Any()) throw new SmartException(T("Shipping.CouldNotLoadMethod")); if (shippingRateComputationMethods.Count() == 1) { var getShippingOptionRequest = _shippingService.CreateShippingOptionRequest(cart, shippingAddress, _storeContext.CurrentStore.Id); var shippingRateComputationMethod = shippingRateComputationMethods.First(); decimal? fixedRate = shippingRateComputationMethod.Value.GetFixedRate(getShippingOptionRequest); if (fixedRate.HasValue) { //adjust shipping rate shippingTotal = AdjustShippingRate(fixedRate.Value, cart, null, null, out appliedDiscount); } } } if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) shippingTotal = decimal.Zero; //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotal = Math.Round(shippingTotal.Value, 2); shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalTaxed = Math.Round(shippingTotalTaxed.Value, 2); } return shippingTotalTaxed; }
protected virtual void PrepareWishlistModel(WishlistModel model, IList<ShoppingCartItem> cart, bool isEditable = true) { if (cart == null) throw new ArgumentNullException("cart"); if (model == null) throw new ArgumentNullException("model"); //load settings for a chosen store scope var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); var AUConsignorSettings = _settings.LoadSetting<Nop.Plugin.Misc.AUConsignor.Domain.AUConsignorSettings>(storeScope); AUStoreTypeEnum storeType = (AUStoreTypeEnum)AUConsignorSettings.StoreTypeId; model.StoreType = storeType; //needed this beyond IsEditable because if don't come in with customer guid from share wishlist email you //still don;t want them to enter bids if they're a guest if (_workContext.CurrentCustomer.IsGuest()) { model.IsGuest = true; } else { model.IsGuest = false; } model.EmailWishlistEnabled = _shoppingCartSettings.EmailWishlistEnabled; model.IsEditable = isEditable; model.DisplayAddToCart = _permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart); model.DisplayTaxShippingInfo = _catalogSettings.DisplayTaxShippingInfoWishlist; if (cart.Count == 0) return; #region Simple properties var customer = cart.GetCustomer(); model.CustomerGuid = customer.CustomerGuid; model.CustomerFullname = customer.GetFullName(); model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart; model.ShowSku = _catalogSettings.ShowProductSku; //cart warnings var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, "", false); foreach (var warning in cartWarnings) model.Warnings.Add(warning); #endregion #region Cart items foreach (var sci in cart) { var cartItemModel = new WishlistModel.ShoppingCartItemModel { Id = sci.Id, Sku = sci.Product.FormatSku(sci.AttributesXml, _productAttributeParser), ProductId = sci.Product.Id, ProductName = sci.Product.GetLocalized(x => x.Name), ProductSeName = sci.Product.GetSeName(), Quantity = sci.Quantity, AttributeInfo = _productAttributeFormatter.FormatAttributes(sci.Product, sci.AttributesXml), LotBidEntry = _lotService.GetLotBidEntryModel(sci.Product.Id) }; //NJM: count lots as separate from products so can determine if need to show product wishlist and lot wishlist in view if (cartItemModel.LotBidEntry.ProductIsLot) { model.TotalLots += 1; } //TODO: fill in the lot bid entry model in the shopping cart only if auction site //allowed quantities var allowedQuantities = sci.Product.ParseAllowedQuantities(); foreach (var qty in allowedQuantities) { cartItemModel.AllowedQuantities.Add(new SelectListItem { Text = qty.ToString(), Value = qty.ToString(), Selected = sci.Quantity == qty }); } //recurring info if (sci.Product.IsRecurring) cartItemModel.RecurringInfo = string.Format(_localizationService.GetResource("ShoppingCart.RecurringPeriod"), sci.Product.RecurringCycleLength, sci.Product.RecurringCyclePeriod.GetLocalizedEnum(_localizationService, _workContext)); //rental info if (sci.Product.IsRental) { var rentalStartDate = sci.RentalStartDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalStartDateUtc.Value) : ""; var rentalEndDate = sci.RentalEndDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalEndDateUtc.Value) : ""; cartItemModel.RentalInfo = string.Format(_localizationService.GetResource("ShoppingCart.Rental.FormattedDate"), rentalStartDate, rentalEndDate); } //unit prices if (sci.Product.CallForPrice) { cartItemModel.UnitPrice = _localizationService.GetResource("Products.CallForPrice"); } else { decimal taxRate; decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetUnitPrice(sci), out taxRate); decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.UnitPrice = _priceFormatter.FormatPrice(shoppingCartUnitPriceWithDiscount); } //subtotal, discount if (sci.Product.CallForPrice) { cartItemModel.SubTotal = _localizationService.GetResource("Products.CallForPrice"); } else { //sub total Discount scDiscount; decimal shoppingCartItemDiscountBase; decimal taxRate; decimal shoppingCartItemSubTotalWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetSubTotal(sci, true, out shoppingCartItemDiscountBase, out scDiscount), out taxRate); decimal shoppingCartItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemSubTotalWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.SubTotal = _priceFormatter.FormatPrice(shoppingCartItemSubTotalWithDiscount); //display an applied discount amount if (scDiscount != null) { shoppingCartItemDiscountBase = _taxService.GetProductPrice(sci.Product, shoppingCartItemDiscountBase, out taxRate); if (shoppingCartItemDiscountBase > decimal.Zero) { decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency); cartItemModel.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount); } } } //picture if (_shoppingCartSettings.ShowProductImagesOnShoppingCart) { cartItemModel.Picture = PrepareCartItemPictureModel(sci, _mediaSettings.CartThumbPictureSize, true, cartItemModel.ProductName); } //item warnings var itemWarnings = _shoppingCartService.GetShoppingCartItemWarnings( _workContext.CurrentCustomer, sci.ShoppingCartType, sci.Product, sci.StoreId, sci.AttributesXml, sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false); foreach (var warning in itemWarnings) cartItemModel.Warnings.Add(warning); model.Items.Add(cartItemModel); } }
/// <summary> /// Gets a value indicating whether shipping is free /// </summary> /// <param name="cart">Cart</param> /// <returns>A value indicating whether shipping is free</returns> public virtual bool IsFreeShipping(IList <ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); if (customer != null) { //check whether customer is in a customer role with free shipping applied var customerRoles = customer.CustomerRoles.Where(cr => cr.Active); foreach (var customerRole in customerRoles) { if (customerRole.FreeShipping) { return(true); } } } bool shoppingCartRequiresShipping = cart.RequiresShipping(); if (!shoppingCartRequiresShipping) { return(true); } //check whether all shopping cart items are marked as free shipping bool allItemsAreFreeShipping = true; foreach (var sc in cart) { if (sc.IsShipEnabled && !sc.IsFreeShipping) { allItemsAreFreeShipping = false; break; } } if (allItemsAreFreeShipping) { return(true); } //free shipping over $X if (_shippingSettings.FreeShippingOverXEnabled) { //check whether we have subtotal enough to have free shipping decimal subTotalDiscountAmount; Discount subTotalAppliedDiscount; decimal subTotalWithoutDiscountBase; decimal subTotalWithDiscountBase; GetShoppingCartSubTotal(cart, _shippingSettings.FreeShippingOverXIncludingTax, out subTotalDiscountAmount, out subTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); if (subTotalWithDiscountBase > _shippingSettings.FreeShippingOverXValue) { return(true); } } //otherwise, return false return(false); }
/// <summary> /// Adjust shipping rate (free shipping, additional charges, discounts) /// </summary> /// <param name="shippingRate">Shipping rate to adjust</param> /// <param name="cart">Cart</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Adjusted shipping rate</returns> public virtual decimal AdjustShippingRate(decimal shippingRate, IList <ShoppingCartItem> cart, out Discount appliedDiscount) { appliedDiscount = null; //free shipping if (IsFreeShipping(cart)) { return(decimal.Zero); } //additional shipping charges decimal additionalShippingCharge = GetShoppingCartAdditionalShippingCharge(cart); var adjustedRate = shippingRate + additionalShippingCharge; //discount var customer = cart.GetCustomer(); decimal discountAmount = GetShippingDiscount(customer, adjustedRate, out appliedDiscount); adjustedRate = adjustedRate - discountAmount; if (adjustedRate < decimal.Zero) { adjustedRate = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { adjustedRate = RoundingHelper.RoundPrice(adjustedRate); } return(adjustedRate); }
public virtual async Task <ShoppingCartShippingTotal> GetShoppingCartShippingTotalAsync(IList <OrganizedShoppingCartItem> cart, bool?includeTax = null) { Guard.NotNull(cart, nameof(cart)); var includingTax = includeTax ?? (_workContext.TaxDisplayType == TaxDisplayType.IncludingTax); var currency = _workContext.WorkingCurrency; var customer = cart.GetCustomer(); if (await IsFreeShippingAsync(cart)) { return(new ShoppingCartShippingTotal(currency.AsMoney(decimal.Zero))); } var(shippingTotal, appliedDiscount) = await GetAdjustedShippingTotalAsync(cart); if (!shippingTotal.HasValue) { return(new ShoppingCartShippingTotal(null)); } shippingTotal = currency.AsMoney(shippingTotal.Value.Amount, true, true); await PrepareAuxiliaryServicesTaxingInfosAsync(cart); // Commented out because requires several plugins to be updated and migration of Order.OrderShippingTaxRate and Order.PaymentMethodAdditionalFeeTaxRate. //if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.ProRata) //{ // // calculate proRataShipping: get product weightings for cart and multiply them with the shipping amount // shippingTotalTaxed = decimal.Zero; // var tmpTaxRate = decimal.Zero; // var taxRates = new List<decimal>(); // foreach (var item in cart) // { // var proRataShipping = shippingTotal.Value * GetTaxingInfo(item).ProRataWeighting; // shippingTotalTaxed += _taxService.GetShippingPrice(proRataShipping, includingTax, customer, item.Item.Product.TaxCategoryId, out tmpTaxRate); // taxRates.Add(tmpTaxRate); // } // // a tax rate is only defined if all rates are equal. return zero tax rate in all other cases. // if (taxRates.Any() && taxRates.Distinct().Count() == 1) // { // taxRate = taxRates.First(); // } //} //else //{ var taxCategoryId = GetTaxCategoryId(cart, _taxSettings.ShippingTaxClassId); var(shippingTotalTaxed, taxRate) = await _taxService.GetShippingPriceAsync(shippingTotal.Value, includingTax, taxCategoryId, customer); return(new ShoppingCartShippingTotal(currency.AsMoney(shippingTotalTaxed.Amount)) { AppliedDiscount = appliedDiscount, TaxRate = taxRate }); }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <param name="includeCheckoutAttributes">A value indicating whether we should calculate weights of selected checkotu attributes</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetTotalWeight(IList <ShoppingCartItem> cart, bool includeCheckoutAttributes = true) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) { totalWeight += GetShoppingCartItemWeight(shoppingCartItem) * shoppingCartItem.Quantity; } //checkout attributes if (customer != null && includeCheckoutAttributes) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); if (!String.IsNullOrEmpty(checkoutAttributesXml)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); foreach (var caValue in caValues) { totalWeight += caValue.WeightAdjustment; } } } return(totalWeight); }
public virtual async Task <decimal> GetCartTotalWeightAsync(IList <OrganizedShoppingCartItem> cart, bool includeFreeShippingProducts = true) { Guard.NotNull(cart, nameof(cart)); // Cart total weight > products weight * quantity + attributes weight * quantity cart = cart.Where(x => !(!includeFreeShippingProducts && x.Item.Product.IsFreeShipping)).ToList(); var attributesTotalWeight = await GetCartItemsAttributesWeightAsync(cart); var productsTotalWeight = cart.Sum(x => x.Item.Product.Weight * x.Item.Quantity); var cartTotalWeight = attributesTotalWeight + productsTotalWeight; var customer = cart.GetCustomer(); if (customer == null) { return(cartTotalWeight); } // Checkout attributes var attributeSelection = customer.GenericAttributes.CheckoutAttributes; if (attributeSelection.AttributesMap.Any()) { var attributeValues = await _checkoutAttributeMaterializer .MaterializeCheckoutAttributeValuesAsync(attributeSelection); cartTotalWeight += attributeValues.Sum(x => x.WeightAdjustment); } return(cartTotalWeight); }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetShoppingCartTotalWeight(IList <OrganizedShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) { totalWeight += GetShoppingCartItemTotalWeight(shoppingCartItem); } //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); if (!String.IsNullOrEmpty(checkoutAttributesXml)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); foreach (var caValue in caValues) { totalWeight += caValue.WeightAdjustment; } } } return(totalWeight); }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetShoppingCartTotalWeight(IList <ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) { totalWeight += GetShoppingCartItemTotalWeight(shoppingCartItem); } //checkout attributes if (customer != null) { if (!String.IsNullOrEmpty(customer.CheckoutAttributes)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(customer.CheckoutAttributes); foreach (var caValue in caValues) { totalWeight += caValue.WeightAdjustment; } } } return(totalWeight); }
public virtual ShippingOptionRequest CreateShippingOptionRequest(IList <OrganizedShoppingCartItem> cart, Address shippingAddress, int storeId) { var shipping = cart.Where(x => x.Item.IsShippingEnabled); var request = new ShippingOptionRequest { StoreId = storeId, Customer = cart.GetCustomer(), ShippingAddress = shippingAddress, CountryFrom = null, StateProvinceFrom = null, ZipPostalCodeFrom = string.Empty, Items = new List <OrganizedShoppingCartItem>(shipping) }; return(request); }
/// <summary> /// Gets a value indicating whether shipping is free /// </summary> /// <param name="cart">Cart</param> /// <returns>A value indicating whether shipping is free</returns> public virtual bool IsFreeShipping(IList <ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); if (customer != null) { //check whether customer is in a customer role with free shipping applied var customerRoles = customer.CustomerRoles.Where(cr => cr.Active); foreach (var customerRole in customerRoles) { if (customerRole.FreeShipping) { return(true); } } } bool shoppingCartRequiresShipping = cart.RequiresShipping(); if (!shoppingCartRequiresShipping) { return(true); } //check whether all shopping cart items are marked as free shipping bool allItemsAreFreeShipping = true; foreach (var sc in cart) { if (sc.IsShipEnabled && !sc.IsFreeShipping) { allItemsAreFreeShipping = false; break; } } if (allItemsAreFreeShipping) { return(true); } //otherwise, return false return(false); }
protected virtual async Task <(Money?Amount, Discount AppliedDiscount)> GetAdjustedShippingTotalAsync(IList <OrganizedShoppingCartItem> cart) { var currency = _workContext.WorkingCurrency; var storeId = _storeContext.CurrentStore.Id; var customer = cart.GetCustomer(); var shippingOption = customer != null ? customer.GenericAttributes.SelectedShippingOption?.Convert <ShippingOption>() : null; if (shippingOption != null) { // Use last shipping option (get from cache). var shippingMethods = await _shippingService.GetAllShippingMethodsAsync(false, storeId); return(await AdjustShippingRateAsync(cart, new Money(shippingOption.Rate, currency), shippingOption, shippingMethods)); } else { // Use fixed rate (if possible). var shippingAddress = customer?.ShippingAddress ?? null; var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(storeId); if (!shippingRateComputationMethods.Any()) { throw new SmartException(T("Shipping.CouldNotLoadMethod")); } if (shippingRateComputationMethods.Count() == 1) { var shippingRateComputationMethod = shippingRateComputationMethods.First(); var getShippingOptionRequest = _shippingService.CreateShippingOptionRequest(cart, shippingAddress, storeId); var fixedRate = shippingRateComputationMethod.Value.GetFixedRate(getShippingOptionRequest); if (fixedRate.HasValue) { return(await AdjustShippingRateAsync(cart, new Money(fixedRate.Value, currency), null, null)); } } } return(null, null); }
/// <summary> /// Create shipment package from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <returns>Shipment package</returns> public virtual GetShippingOptionRequest CreateShippingOptionRequest(IList <OrganizedShoppingCartItem> cart, Address shippingAddress) { var request = new GetShippingOptionRequest(); request.Customer = cart.GetCustomer(); request.Items = new List <OrganizedShoppingCartItem>(); foreach (var sc in cart) { if (sc.Item.IsShipEnabled) { request.Items.Add(sc); } } request.ShippingAddress = shippingAddress; request.CountryFrom = null; request.StateProvinceFrom = null; request.ZipPostalCodeFrom = string.Empty; return(request); }
public virtual async Task <bool> IsFreeShippingAsync(IList <OrganizedShoppingCartItem> cart) { var customer = cart.GetCustomer(); if (customer != null) { // Check whether customer is in a customer role with free shipping applied. var customerRoles = customer.CustomerRoleMappings .Select(x => x.CustomerRole) .Where(x => x.Active); if (customerRoles.Any(x => x.FreeShipping)) { return(true); } } if (!cart.IsShippingRequired()) { return(true); } // Check whether there is at least one item with chargeable shipping. if (!cart.Any(x => x.Item.IsShippingEnabled && !x.Item.IsFreeShipping)) { return(true); } // Check if the subtotal is large enough for free shipping. if (_shippingSettings.FreeShippingOverXEnabled) { Money subTotalWithDiscount = await GetShoppingCartSubTotalAsync(cart, _shippingSettings.FreeShippingOverXIncludingTax); if (subTotalWithDiscount > _shippingSettings.FreeShippingOverXValue) { return(true); } } return(false); }
public virtual decimal GetShoppingCartTotalWeight(IList <OrganizedShoppingCartItem> cart, bool includeFreeShippingProducts = true) { var totalWeight = decimal.Zero; var customer = cart.GetCustomer(); // shopping cart items foreach (var cartItem in cart) { var product = cartItem.Item.Product; if (product != null) { if (!includeFreeShippingProducts && product.IsFreeShipping) { // skip product } else { totalWeight += GetShoppingCartItemTotalWeight(cartItem); } } } // checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); if (!String.IsNullOrEmpty(checkoutAttributesXml)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); foreach (var caValue in caValues) { totalWeight += caValue.WeightAdjustment; } } } return(totalWeight); }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetShoppingCartTotalWeight(IList<OrganizedShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) totalWeight += GetShoppingCartItemTotalWeight(shoppingCartItem); //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute<string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); if (!String.IsNullOrEmpty(checkoutAttributesXml)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); foreach (var caValue in caValues) totalWeight += caValue.WeightAdjustment; } } return totalWeight; }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal?GetShoppingCartShippingTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out Discount appliedDiscount) { decimal?shippingTotal = null; decimal?shippingTotalTaxed = null; appliedDiscount = null; taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = IsFreeShipping(cart); if (isFreeShipping) { return(decimal.Zero); } ShippingOption shippingOption = null; if (customer != null) { shippingOption = customer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _genericAttributeService, _storeContext.CurrentStore.Id); } if (shippingOption != null) { //use last shipping option (get from cache) //adjust shipping rate shippingTotal = AdjustShippingRate(shippingOption.Rate, cart, out appliedDiscount); } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) { shippingAddress = customer.ShippingAddress; } var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(); if (shippingRateComputationMethods == null || shippingRateComputationMethods.Count == 0) { throw new NasException("Shipping rate computation method could not be loaded"); } if (shippingRateComputationMethods.Count == 1) { var getShippingOptionRequest = _shippingService.CreateShippingOptionRequest(cart, shippingAddress); var shippingRateComputationMethod = shippingRateComputationMethods[0]; decimal?fixedRate = shippingRateComputationMethod.GetFixedRate(getShippingOptionRequest); if (fixedRate.HasValue) { //adjust shipping rate shippingTotal = AdjustShippingRate(fixedRate.Value, cart, out appliedDiscount); } } } if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) { shippingTotal = decimal.Zero; } //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotal = Math.Round(shippingTotal.Value, 2); } shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotalTaxed = Math.Round(shippingTotalTaxed.Value, 2); } } return(shippingTotalTaxed); }
public virtual async Task <ShoppingCartSubTotal> GetShoppingCartSubTotalAsync(IList <OrganizedShoppingCartItem> cart, bool?includeTax = null) { Guard.NotNull(cart, nameof(cart)); var includingTax = includeTax ?? (_workContext.TaxDisplayType == TaxDisplayType.IncludingTax); var result = new ShoppingCartSubTotal(); if (!(cart?.Any() ?? false)) { return(result); } var customer = cart.GetCustomer(); var subTotalExclTaxWithoutDiscount = new Money(_primaryCurrency); var subTotalInclTaxWithoutDiscount = new Money(_primaryCurrency); foreach (var cartItem in cart) { if (cartItem.Item.Product == null) { continue; } var item = cartItem.Item; decimal taxRate = decimal.Zero; Money itemExclTax, itemInclTax; await _productAttributeMaterializer.MergeWithCombinationAsync(item.Product, item.AttributeSelection); if (_primaryCurrency.RoundOrderItemsEnabled) { // Gross > Net RoundFix. var unitPrice = await _priceCalculationService.GetUnitPriceAsync(cartItem, true); // Adaption to eliminate rounding issues. (itemExclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, unitPrice, false, customer : customer); itemExclTax = _primaryCurrency.AsMoney(itemExclTax.Amount * item.Quantity); (itemInclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, unitPrice, true, customer : customer); itemInclTax = _primaryCurrency.AsMoney(itemInclTax.Amount * item.Quantity); } else { var itemSubTotal = await _priceCalculationService.GetSubTotalAsync(cartItem, true); (itemExclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, itemSubTotal, false, customer : customer); (itemInclTax, taxRate) = await _taxService.GetProductPriceAsync(item.Product, itemSubTotal, true, customer : customer); } subTotalExclTaxWithoutDiscount += itemExclTax; subTotalInclTaxWithoutDiscount += itemInclTax; result.TaxRates.Add(taxRate, itemInclTax.Amount - itemExclTax.Amount); } // Checkout attributes. if (customer != null) { var values = await _checkoutAttributeMaterializer.MaterializeCheckoutAttributeValuesAsync(customer.GenericAttributes.CheckoutAttributes); foreach (var value in values) { var(attributePriceExclTax, _) = await _taxService.GetCheckoutAttributePriceAsync(value, false, customer); var(attributePriceInclTax, taxRate) = await _taxService.GetCheckoutAttributePriceAsync(value, true, customer); subTotalExclTaxWithoutDiscount += attributePriceExclTax.Amount; subTotalInclTaxWithoutDiscount += attributePriceInclTax.Amount; result.TaxRates.Add(taxRate, attributePriceInclTax.Amount - attributePriceExclTax.Amount); } } // Subtotal without discount. result.SubTotalWithoutDiscount = _primaryCurrency.AsMoney(includingTax ? subTotalInclTaxWithoutDiscount.Amount : subTotalExclTaxWithoutDiscount.Amount, true, true); // We calculate discount amount on order subtotal excl tax (discount first). var(discountAmountExclTax, appliedDiscount) = await this.GetOrderSubtotalDiscountAsync(subTotalExclTaxWithoutDiscount, customer); result.AppliedDiscount = appliedDiscount; 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>(result.TaxRates); foreach (var kvp in tempTaxRates) { var taxRate = kvp.Key; var taxAmount = kvp.Value; if (taxAmount != decimal.Zero) { // Discount the tax amount that applies to subtotal items. if (subTotalExclTaxWithoutDiscount > decimal.Zero) { var discountTax = result.TaxRates[taxRate] * (discountAmountExclTax.Amount / subTotalExclTaxWithoutDiscount.Amount); discountAmountInclTax += discountTax; taxAmount = _primaryCurrency.RoundIfEnabledFor(result.TaxRates[taxRate] - discountTax); result.TaxRates[taxRate] = taxAmount; } // Subtotal with discount (incl tax). subTotalInclTaxWithDiscount += taxAmount; } } discountAmountInclTax = _primaryCurrency.AsMoney(discountAmountInclTax.Amount); result.DiscountAmount = _primaryCurrency.AsMoney(includingTax ? discountAmountInclTax.Amount : discountAmountExclTax.Amount, false); result.SubTotalWithDiscount = _primaryCurrency.AsMoney(includingTax ? subTotalInclTaxWithDiscount.Amount : subTotalExclTaxWithDiscount.Amount, true, true); return(result); }
public virtual void GetShoppingCartSubTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out Discount appliedDiscount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary <decimal, decimal> taxRates, ProcessPaymentRequest processPaymentRequest) { discountAmount = decimal.Zero; appliedDiscount = null; subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary <decimal, decimal>(); if (cart.Count == 0) { return; } //get the customer Customer customer = cart.GetCustomer(); //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { decimal taxRate = decimal.Zero; decimal sciSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem, true); decimal sciExclTax = _taxService.GetProductPrice(shoppingCartItem.ProductVariant, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetProductPrice(shoppingCartItem.ProductVariant, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(customer.CheckoutAttributes); if (caValues != null) { foreach (var caValue in caValues) { decimal taxRate = decimal.Zero; decimal caExclTax = _taxService.GetCheckoutAttributePrice(caValue, false, customer, out taxRate); decimal caInclTax = _taxService.GetCheckoutAttributePrice(caValue, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } } //subtotal without discount if (includingTax) { subTotalWithoutDiscount = subTotalInclTaxWithoutDiscount; } else { subTotalWithoutDiscount = subTotalExclTaxWithoutDiscount; } if (subTotalWithoutDiscount < decimal.Zero) { subTotalWithoutDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithoutDiscount = Math.Round(subTotalWithoutDiscount, 2); } /*We calculate discount amount on order subtotal excl tax (discount first)*/ //calculate discount amount ('Applied to order subtotal' discount) decimal discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount, out appliedDiscount); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) { discountAmountExclTax = subTotalExclTaxWithoutDiscount; } decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes Dictionary <decimal, decimal> tempTaxRates = new Dictionary <decimal, decimal>(taxRates); foreach (KeyValuePair <decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxValue = Math.Round(taxValue, 2); } taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = Math.Round(discountAmountInclTax, 2); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } //round if (subTotalWithDiscount < decimal.Zero) { subTotalWithDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithDiscount = Math.Round(subTotalWithDiscount, 2); } }
/// <summary> /// Gets tax For each City based on Shipping Address /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="taxRates">Tax rates</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating tax</param> /// <returns>Tax total</returns> public virtual decimal GetTaxTotalByCity(IList<ShoppingCartItem> cart) { if (cart == null) throw new ArgumentNullException("cart"); decimal taxTotal = 0; var customer = cart.GetCustomer(); if (cart[0].Customer.ShippingAddress != null) { var shippingZipcode = cart[0].Customer.ShippingAddress.ZipPostalCode; //string paymentMethodSystemName = ""; List<TaxRatesByZipcode> taxRate = _dbContext.SqlQuery<TaxRatesByZipcode>("exec TaxRate_Load_ByZipcode @zipcode", new System.Data.SqlClient.SqlParameter("@zipcode", shippingZipcode)).ToList(); //var customerIdParameter = _dataProvider.GetParameter(); //customerIdParameter.ParameterName = "CustomerId"; //customerIdParameter.Value = customer.Id; //customerIdParameter.DbType = DbType.Int32; //var taxRates = _dbContext.ExecuteStoredProcedureList<TaxRatesByZipcode>( // "TaxRate_Load_ByZipcode", // customerIdParameter); if (taxRate.Count == 1) //1 row returned { taxTotal = taxRate[0].TaxRate; } } return taxTotal; }
/// <summary> /// Gets shopping cart subtotal /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscount">Applied discount</param> /// <param name="subTotalWithoutDiscount">Sub total (without discount)</param> /// <param name="subTotalWithDiscount">Sub total (with discount)</param> /// <param name="taxRates">Tax rates (of order sub total)</param> public virtual void GetShoppingCartSubTotal(IList<ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out Discount appliedDiscount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary<decimal, decimal> taxRates) { discountAmount = decimal.Zero; appliedDiscount = null; subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary<decimal, decimal>(); if (cart.Count == 0) return; //get the customer Customer customer = cart.GetCustomer(); //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { decimal taxRate = decimal.Zero; decimal sciSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem, true); decimal sciExclTax = _taxService.GetProductPrice(shoppingCartItem.Product, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetProductPrice(shoppingCartItem.Product, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute<string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (caValues!=null) { foreach (var caValue in caValues) { decimal taxRate = decimal.Zero; decimal caExclTax = _taxService.GetCheckoutAttributePrice(caValue, false, customer, out taxRate); decimal caInclTax = _taxService.GetCheckoutAttributePrice(caValue, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } } //subtotal without discount if (includingTax) subTotalWithoutDiscount = subTotalInclTaxWithoutDiscount; else subTotalWithoutDiscount = subTotalExclTaxWithoutDiscount; if (subTotalWithoutDiscount < decimal.Zero) subTotalWithoutDiscount = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) subTotalWithoutDiscount = Math.Round(subTotalWithoutDiscount, 2); /*We calculate discount amount on order subtotal excl tax (discount first)*/ //calculate discount amount ('Applied to order subtotal' discount) decimal discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount, out appliedDiscount); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) discountAmountExclTax = subTotalExclTaxWithoutDiscount; decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes Dictionary<decimal, decimal> tempTaxRates = new Dictionary<decimal, decimal>(taxRates); foreach (KeyValuePair<decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) taxValue = Math.Round(taxValue, 2); taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = Math.Round(discountAmountInclTax, 2); discountAmountExclTax = Math.Round(discountAmountExclTax, 2); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } if (subTotalWithDiscount < decimal.Zero) subTotalWithDiscount = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) subTotalWithDiscount = Math.Round(subTotalWithDiscount, 2); }
/// <summary> /// Adjust shipping rate (free shipping, additional charges, discounts) /// </summary> /// <param name="shippingRate">Shipping rate to adjust</param> /// <param name="cart">Cart</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Adjusted shipping rate</returns> public virtual decimal AdjustShippingRate(decimal shippingRate, IList<ShoppingCartItem> cart, out Discount appliedDiscount) { appliedDiscount = null; //free shipping if (IsFreeShipping(cart)) return decimal.Zero; //additional shipping charges decimal additionalShippingCharge = GetShoppingCartAdditionalShippingCharge(cart); var adjustedRate = shippingRate + additionalShippingCharge; //discount var customer = cart.GetCustomer(); decimal discountAmount = GetShippingDiscount(customer, adjustedRate, out appliedDiscount); adjustedRate = adjustedRate - discountAmount; if (adjustedRate < decimal.Zero) adjustedRate = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) adjustedRate = Math.Round(adjustedRate, 2); return adjustedRate; }
public override decimal? GetShoppingCartShippingTotal(IList<global::Nop.Core.Domain.Orders.ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out global::Nop.Core.Domain.Discounts.Discount appliedDiscount) { if (!_promoSettings.Enabled) return base.GetShoppingCartShippingTotal(cart, includingTax, out taxRate, out appliedDiscount); #region old code BasketResponse basketResponse = _promoUtilities.GetBasketResponse(); decimal? shippingTotal = null; if (basketResponse == null) { return base.GetShoppingCartShippingTotal(cart, includingTax, out taxRate, out appliedDiscount); } taxRate = Decimal.Zero; appliedDiscount = null; var shippingOption = _workContext.CurrentCustomer.GetAttribute<ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id); if (shippingOption == null) { // Where there are items in the basket that are not for shipping, we need to ensure we return a zero. if (cart.Any(sci => sci.IsShipEnabled)) return null; else return Decimal.Zero; } shippingTotal = basketResponse.DeliveryPrice; if ((basketResponse.DeliveryPromotionDiscount > Decimal.Zero)) { if (basketResponse.BasketLevelDiscountIncludesDeliveryAmount()) { shippingTotal = basketResponse.DeliveryOriginalPrice; } else { appliedDiscount = new Discount(); appliedDiscount.DiscountAmount = basketResponse.DeliveryPromotionDiscount; appliedDiscount.Name = basketResponse.DeliveryPromo().PromotionName; } } #endregion #region new code decimal? shippingTotalTaxed = shippingTotal; Customer customer = cart.GetCustomer(); if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) shippingTotal = decimal.Zero; //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotal = RoundingHelper.RoundPrice(shippingTotal.Value); shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalTaxed = RoundingHelper.RoundPrice(shippingTotalTaxed.Value); } #endregion return shippingTotalTaxed; }
/// <summary> /// Create shipment packages (requests) from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param> /// <param name="shippingFromMultipleLocations">Value indicating whether shipping is done from multiple locations (warehouses)</param> /// <returns>Shipment packages (requests)</returns> public virtual IList <GetShippingOptionRequest> CreateShippingOptionRequests(IList <ShoppingCartItem> cart, Address shippingAddress, int storeId, out bool shippingFromMultipleLocations) { //if we always ship from the default shipping origin, then there's only one request //if we ship from warehouses ("ShippingSettings.UseWarehouseLocation" enabled), //then there could be several requests //key - warehouse identifier (0 - default shipping origin) //value - request var requests = new Dictionary <int, GetShippingOptionRequest>(); //a list of requests with products which should be shipped separately var separateRequests = new List <GetShippingOptionRequest>(); foreach (var sci in cart) { if (!sci.IsShipEnabled) { continue; } var product = _productService.GetProductById(sci.ProductId); //warehouses Warehouse warehouse = null; if (_shippingSettings.UseWarehouseLocation) { if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && product.UseMultipleWarehouses) { var allWarehouses = new List <Warehouse>(); //multiple warehouses supported foreach (var pwi in product.ProductWarehouseInventory) { //TODO validate stock quantity when backorder is not allowed? var tmpWarehouse = GetWarehouseById(pwi.WarehouseId); if (tmpWarehouse != null) { allWarehouses.Add(tmpWarehouse); } } warehouse = GetNearestWarehouse(shippingAddress, allWarehouses); } else { //multiple warehouses are not supported warehouse = GetWarehouseById(product.WarehouseId); } } int warehouseId = warehouse != null ? warehouse.Id : 0; if (requests.ContainsKey(warehouseId) && !product.ShipSeparately) { //add item to existing request requests[warehouseId].Items.Add(new GetShippingOptionRequest.PackageItem(sci)); } else { //create a new request var request = new GetShippingOptionRequest(); //store request.StoreId = storeId; //add item request.Items.Add(new GetShippingOptionRequest.PackageItem(sci)); //customer request.Customer = cart.GetCustomer(); //ship to request.ShippingAddress = shippingAddress; //ship from Address originAddress = null; if (warehouse != null) { //warehouse address originAddress = _addressService.GetAddressByIdSettings(warehouse.AddressId); request.WarehouseFrom = warehouse; } if (originAddress == null) { //no warehouse address. in this case use the default shipping origin originAddress = _addressService.GetAddressByIdSettings(_shippingSettings.ShippingOriginAddressId); } if (originAddress != null) { var country = EngineContext.Current.Resolve <ICountryService>().GetCountryById(originAddress.CountryId); var state = EngineContext.Current.Resolve <IStateProvinceService>().GetStateProvinceById(originAddress.StateProvinceId); request.CountryFrom = country; request.StateProvinceFrom = state; request.ZipPostalCodeFrom = originAddress.ZipPostalCode; request.CityFrom = originAddress.City; request.AddressFrom = originAddress.Address1; } if (product.ShipSeparately) { //ship separately separateRequests.Add(request); } else { //usual request requests.Add(warehouseId, request); } } } //multiple locations? //currently we just compare warehouses //but we should also consider cases when several warehouses are located in the same address shippingFromMultipleLocations = requests.Select(x => x.Key).Distinct().Count() > 1; var result = requests.Values.ToList(); result.AddRange(separateRequests); return(result); }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal?GetShoppingCartShippingTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out Discount appliedDiscount) { decimal?shippingTotal = null; decimal?shippingTotalTaxed = null; appliedDiscount = null; taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = IsFreeShipping(cart); if (isFreeShipping) { return(decimal.Zero); } ShippingOption shippingOption = null; if (customer != null) { shippingOption = customer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _genericAttributeService, _storeContext.CurrentStore.Id); } if (shippingOption != null) { //use last shipping option (get from cache) var pickUpInStore = _shippingSettings.AllowPickUpInStore && customer.GetAttribute <bool>(SystemCustomerAttributeNames.SelectedPickUpInStore, _storeContext.CurrentStore.Id); if (pickUpInStore) { //"pick up in store" fee //we do not adjust shipping rate ("AdjustShippingRate" method) for pickup in store shippingTotal = _shippingSettings.PickUpInStoreFee; } else { //adjust shipping rate shippingTotal = AdjustShippingRate(shippingOption.Rate, cart, out appliedDiscount); } } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) { shippingAddress = customer.ShippingAddress; } var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id); if (shippingRateComputationMethods == null || shippingRateComputationMethods.Count == 0) { throw new NopException("Shipping rate computation method could not be loaded"); } if (shippingRateComputationMethods.Count == 1) { var shippingRateComputationMethod = shippingRateComputationMethods[0]; var shippingOptionRequests = _shippingService.CreateShippingOptionRequests(cart, shippingAddress); decimal?fixedRate = null; foreach (var shippingOptionRequest in shippingOptionRequests) { //calculate fixed rates for each request-package var fixedRateTmp = shippingRateComputationMethod.GetFixedRate(shippingOptionRequest); if (fixedRateTmp.HasValue) { if (!fixedRate.HasValue) { fixedRate = decimal.Zero; } fixedRate += fixedRateTmp.Value; } } if (fixedRate.HasValue) { //adjust shipping rate shippingTotal = AdjustShippingRate(fixedRate.Value, cart, out appliedDiscount); } } } if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) { shippingTotal = decimal.Zero; } //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotal = RoundingHelper.RoundPrice(shippingTotal.Value); } shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotalTaxed = RoundingHelper.RoundPrice(shippingTotalTaxed.Value); } } return(shippingTotalTaxed); }
/// <summary> /// Gets shopping cart total /// </summary> /// <param name="cart">Cart</param> /// <param name="appliedGiftCards">Applied gift cards</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscount">Applied discount</param> /// <param name="redeemedRewardPoints">Reward points to redeem</param> /// <param name="redeemedRewardPointsAmount">Reward points amount in primary store currency to redeem</param> /// <param name="ignoreRewardPonts">A value indicating whether we should ignore reward points (if enabled and a customer is going to use them)</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating order total</param> /// <returns>Shopping cart total;Null if shopping cart total couldn't be calculated now</returns> public virtual decimal?GetShoppingCartTotal(IList <ShoppingCartItem> cart, out decimal discountAmount, out Discount appliedDiscount, out List <AppliedGiftCard> appliedGiftCards, out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount, bool ignoreRewardPonts = false, bool usePaymentMethodAdditionalFee = true) { redeemedRewardPoints = 0; redeemedRewardPointsAmount = decimal.Zero; var customer = cart.GetCustomer(); string paymentMethodSystemName = ""; if (customer != null) { paymentMethodSystemName = customer.GetAttribute <string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //subtotal without tax decimal orderSubTotalDiscountAmount; Discount orderSubTotalAppliedDiscount; decimal subTotalWithoutDiscountBase; decimal subTotalWithDiscountBase; GetShoppingCartSubTotal(cart, false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); //subtotal with discount decimal subtotalBase = subTotalWithDiscountBase; //shipping without tax decimal?shoppingCartShipping = GetShoppingCartShippingTotal(cart, false); //payment method additional fee without tax decimal paymentMethodAdditionalFeeWithoutTax = decimal.Zero; if (usePaymentMethodAdditionalFee && !String.IsNullOrEmpty(paymentMethodSystemName)) { decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); paymentMethodAdditionalFeeWithoutTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer); } //tax decimal shoppingCartTax = GetTaxTotal(cart, usePaymentMethodAdditionalFee); //order total decimal resultTemp = decimal.Zero; resultTemp += subtotalBase; if (shoppingCartShipping.HasValue) { resultTemp += shoppingCartShipping.Value; } resultTemp += paymentMethodAdditionalFeeWithoutTax; resultTemp += shoppingCartTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } #region Order total discount discountAmount = GetOrderTotalDiscount(customer, resultTemp, out appliedDiscount); //sub totals with discount if (resultTemp < discountAmount) { discountAmount = resultTemp; } //reduce subtotal resultTemp -= discountAmount; if (resultTemp < decimal.Zero) { resultTemp = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } #endregion #region Applied gift cards //let's apply gift cards now (gift cards that can be used) appliedGiftCards = new List <AppliedGiftCard>(); if (!cart.IsRecurring()) { //we don't apply gift cards for recurring products var giftCards = _giftCardService.GetActiveGiftCardsAppliedByCustomer(customer); if (giftCards != null) { foreach (var gc in giftCards) { if (resultTemp > decimal.Zero) { decimal remainingAmount = gc.GetGiftCardRemainingAmount(); decimal amountCanBeUsed = decimal.Zero; if (resultTemp > remainingAmount) { amountCanBeUsed = remainingAmount; } else { amountCanBeUsed = resultTemp; } //reduce subtotal resultTemp -= amountCanBeUsed; var appliedGiftCard = new AppliedGiftCard(); appliedGiftCard.GiftCard = gc; appliedGiftCard.AmountCanBeUsed = amountCanBeUsed; appliedGiftCards.Add(appliedGiftCard); } } } } #endregion if (resultTemp < decimal.Zero) { resultTemp = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } if (!shoppingCartShipping.HasValue) { //we have errors return(null); } decimal orderTotal = resultTemp; #region Reward points if (_rewardPointsSettings.Enabled && !ignoreRewardPonts && customer.GetAttribute <bool>(SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, _genericAttributeService, _storeContext.CurrentStore.Id)) { int rewardPointsBalance = customer.GetRewardPointsBalance(); if (CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance)) { decimal rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); if (orderTotal > decimal.Zero) { if (orderTotal > rewardPointsBalanceAmount) { redeemedRewardPoints = rewardPointsBalance; redeemedRewardPointsAmount = rewardPointsBalanceAmount; } else { redeemedRewardPointsAmount = orderTotal; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } } } #endregion orderTotal = orderTotal - redeemedRewardPointsAmount; if (_shoppingCartSettings.RoundPricesDuringCalculation) { orderTotal = RoundingHelper.RoundPrice(orderTotal); } return(orderTotal); }
public override void GetShoppingCartSubTotal(IList<global::Nop.Core.Domain.Orders.ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out global::Nop.Core.Domain.Discounts.Discount appliedDiscount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary<decimal, decimal> taxRates) { if (!_promoSettings.Enabled) { base.GetShoppingCartSubTotal(cart, includingTax, out discountAmount, out appliedDiscount, out subTotalWithoutDiscount, out subTotalWithDiscount, out taxRates); return; } BasketResponse basketResponse = _promoUtilities.GetBasketResponse(); if (basketResponse == null) { base.GetShoppingCartSubTotal(cart, includingTax, out discountAmount, out appliedDiscount, out subTotalWithoutDiscount, out subTotalWithDiscount, out taxRates); return; } discountAmount = decimal.Zero; appliedDiscount = null; subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary<decimal, decimal>(); Customer customer = cart.GetCustomer(); if (cart.Count == 0) return; decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { decimal usePrice = _priceCalculationService.GetUnitPrice(shoppingCartItem, false); decimal sciSubTotal = _promosPriceCalculationService.GetSubTotal(shoppingCartItem, true); decimal taxRate; decimal sciExclTax = _taxService.GetProductPrice(shoppingCartItem.Product, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetProductPrice(shoppingCartItem.Product, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } // checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute<string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (attributeValues != null && attributeValues.Count > 0) { foreach (var attributeValue in attributeValues) { decimal taxRate; decimal caExclTax = _taxServiceExtensions.GetCheckoutAttributePrice(attributeValue, false, customer, out taxRate, true); decimal caInclTax = _taxServiceExtensions.GetCheckoutAttributePrice(attributeValue, true, customer, out taxRate, true); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } } if (includingTax) subTotalWithoutDiscount = subTotalInclTaxWithoutDiscount; else subTotalWithoutDiscount = subTotalExclTaxWithoutDiscount; if (subTotalWithoutDiscount < decimal.Zero) subTotalWithoutDiscount = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) subTotalWithoutDiscount = RoundingHelper.RoundPrice(subTotalWithoutDiscount); //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) decimal discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount, out appliedDiscount); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) discountAmountExclTax = subTotalExclTaxWithoutDiscount; decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes var tempTaxRates = new Dictionary<decimal, decimal>(taxRates); foreach (KeyValuePair<decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) taxValue = RoundingHelper.RoundPrice(taxValue); taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } if (subTotalWithDiscount < decimal.Zero) subTotalWithDiscount = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) subTotalWithDiscount = RoundingHelper.RoundPrice(subTotalWithDiscount); }
public override decimal? GetShoppingCartTotal(IList<global::Nop.Core.Domain.Orders.ShoppingCartItem> cart, out decimal discountAmount, out global::Nop.Core.Domain.Discounts.Discount appliedDiscount, out List<AppliedGiftCard> appliedGiftCards, out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount, bool ignoreRewardPonts = false, bool usePaymentMethodAdditionalFee = true) { if (!_promoSettings.Enabled) return base.GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount, ignoreRewardPonts, usePaymentMethodAdditionalFee); BasketResponse basketResponse = _promoUtilities.GetBasketResponse(); if (basketResponse == null || basketResponse.Items == null || basketResponse.Summary == null) { return base.GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount, ignoreRewardPonts, usePaymentMethodAdditionalFee); } if (!basketResponse.Summary.ProcessingResult) { return base.GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount, ignoreRewardPonts, usePaymentMethodAdditionalFee); } Customer customer = cart.GetCustomer(); discountAmount = decimal.Zero; appliedDiscount = null; decimal resultTemp = basketResponse.BasketTotal; #region Applied gift cards appliedGiftCards = new List<AppliedGiftCard>(); if (!cart.IsRecurring()) { //we don't apply gift cards for recurring products var giftCards = _giftCardService.GetActiveGiftCardsAppliedByCustomer(customer); if (giftCards != null) foreach (var gc in giftCards) if (resultTemp > decimal.Zero) { decimal remainingAmount = gc.GetGiftCardRemainingAmount(); decimal amountCanBeUsed = decimal.Zero; if (resultTemp > remainingAmount) amountCanBeUsed = remainingAmount; else amountCanBeUsed = resultTemp; //reduce subtotal resultTemp -= amountCanBeUsed; var appliedGiftCard = new AppliedGiftCard(); appliedGiftCard.GiftCard = gc; appliedGiftCard.AmountCanBeUsed = amountCanBeUsed; appliedGiftCards.Add(appliedGiftCard); } } if (resultTemp < decimal.Zero) resultTemp = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) resultTemp = RoundingHelper.RoundPrice(resultTemp); #endregion redeemedRewardPoints = 0; redeemedRewardPointsAmount = Decimal.Zero; decimal orderTotal = basketResponse.BasketTotal - appliedGiftCards.Sum(agc => agc.AmountCanBeUsed); #region Reward points if (_rewardPointsSettings.Enabled && !ignoreRewardPonts && customer.GetAttribute<bool>(SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, _genericAttributeService, _storeContext.CurrentStore.Id)) { int rewardPointsBalance = customer.GetRewardPointsBalance(); if (CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance)) { decimal rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); if (orderTotal > decimal.Zero) { if (orderTotal > rewardPointsBalanceAmount) { redeemedRewardPoints = rewardPointsBalance; redeemedRewardPointsAmount = rewardPointsBalanceAmount; } else { redeemedRewardPointsAmount = orderTotal; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } } } #endregion var shippingOption = _workContext.CurrentCustomer.GetAttribute<ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id); if (shippingOption == null) { // Where there are items in the basket that are not for shipping, ensure we carry on, otherwise placing orders gets stuck. if(cart.Any(sci => sci.IsShipEnabled)) return null; } discountAmount = basketResponse.OrderDiscountTotal(); if (discountAmount > 0) { appliedDiscount = new Discount() { Name = basketResponse.BasketLevelPromotion().PromotionName, DiscountAmount = discountAmount }; } decimal tax = GetTaxTotal(cart); return basketResponse.BasketTotal + tax - appliedGiftCards.Sum(agc => agc.AmountCanBeUsed) - redeemedRewardPointsAmount; }
/// <summary> /// Adjust shipping rate (free shipping, additional charges, discounts) /// </summary> /// <param name="shippingRate">Shipping rate to adjust</param> /// <param name="cart">Cart</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Adjusted shipping rate</returns> public virtual decimal AdjustShippingRate(decimal shippingRate, IList<OrganizedShoppingCartItem> cart, string shippingMethodName, IList<ShippingMethod> shippingMethods, out Discount appliedDiscount) { appliedDiscount = null; //free shipping if (IsFreeShipping(cart)) return decimal.Zero; decimal adjustedRate = decimal.Zero; decimal bundlePerItemShipping = decimal.Zero; bool ignoreAdditionalShippingCharge = false; ShippingMethod shippingMethod; foreach (var sci in cart) { if (sci.Item.Product != null && sci.Item.Product.ProductType == ProductType.BundledProduct && sci.Item.Product.BundlePerItemShipping) { if (sci.ChildItems != null) { foreach (var childItem in sci.ChildItems.Where(x => x.Item.IsShipEnabled && !x.Item.IsFreeShipping)) bundlePerItemShipping += shippingRate; } } else if (adjustedRate == decimal.Zero) { adjustedRate = shippingRate; } } adjustedRate += bundlePerItemShipping; if (shippingMethodName.HasValue() && shippingMethods != null && (shippingMethod = shippingMethods.FirstOrDefault(x => x.Name.IsCaseInsensitiveEqual(shippingMethodName))) != null) { ignoreAdditionalShippingCharge = shippingMethod.IgnoreCharges; } //additional shipping charges if (!ignoreAdditionalShippingCharge) { decimal additionalShippingCharge = GetShoppingCartAdditionalShippingCharge(cart); adjustedRate += additionalShippingCharge; } //discount var customer = cart.GetCustomer(); decimal discountAmount = GetShippingDiscount(customer, adjustedRate, out appliedDiscount); adjustedRate = adjustedRate - discountAmount; if (adjustedRate < decimal.Zero) adjustedRate = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) adjustedRate = Math.Round(adjustedRate, 2); return adjustedRate; }
protected virtual async Task PrepareAuxiliaryServicesTaxingInfosAsync(IList <OrganizedShoppingCartItem> cart) { // No additional infos required. if (!cart.Any() || _taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.SpecifiedTaxCategory) { return; } // Additional infos already collected. if (cart.First().CustomProperties.ContainsKey(CART_TAXING_INFO_KEY)) { return; } // Instance taxing info objects. cart.Each(x => x.CustomProperties[CART_TAXING_INFO_KEY] = new CartTaxingInfo()); // Collect infos. if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.HighestCartAmount) { // Calculate all subtotals. foreach (var item in cart) { GetTaxingInfo(item).SubTotalWithoutDiscount = await _priceCalculationService.GetSubTotalAsync(item, false); } // Items with the highest subtotal. var highestAmountItems = cart .GroupBy(x => x.Item.Product.TaxCategoryId) .OrderByDescending(x => x.Sum(y => GetTaxingInfo(y).SubTotalWithoutDiscount.Amount)) .First(); // Mark items. highestAmountItems.Each(x => GetTaxingInfo(x).HasHighestCartAmount = true); } else if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.HighestTaxRate) { var customer = cart.GetCustomer(); var maxTaxRate = decimal.Zero; var maxTaxCategoryId = 0; // Get tax category id with the highest rate. foreach (var item in cart) { var product = item.Item.Product; var taxRate = await _taxService.GetTaxRateAsync(product, product.TaxCategoryId, customer); if (taxRate > maxTaxRate) { maxTaxRate = taxRate; maxTaxCategoryId = product.TaxCategoryId; } } // Mark items. cart.Where(x => x.Item.Product.TaxCategoryId == maxTaxCategoryId) .Each(x => GetTaxingInfo(x).HasHighestTaxRate = true); } //else if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.ProRata) //{ // // calculate all subtotals // cart.Each(x => GetTaxingInfo(x).SubTotalWithoutDiscount = _priceCalculationService.GetSubTotal(x, false)); // // sum over all subtotals // var subTotalSum = cart.Sum(x => GetTaxingInfo(x).SubTotalWithoutDiscount); // // calculate pro rata weightings // cart.Each(x => // { // var taxingInfo = GetTaxingInfo(x); // taxingInfo.ProRataWeighting = taxingInfo.SubTotalWithoutDiscount / subTotalSum; // }); //} }
/// <summary> /// Gets tax /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="taxRates">Tax rates</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating tax</param> /// <returns>Tax total</returns> public virtual decimal GetTaxTotal(IList<ShoppingCartItem> cart, out SortedDictionary<decimal, decimal> taxRates, bool usePaymentMethodAdditionalFee = true) { if (cart == null) throw new ArgumentNullException("cart"); taxRates = new SortedDictionary<decimal, decimal>(); var customer = cart.GetCustomer(); string paymentMethodSystemName = ""; if (customer != null) { paymentMethodSystemName = customer.GetAttribute<string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //order sub total (items + checkout attributes) decimal subTotalTaxTotal = decimal.Zero; decimal orderSubTotalDiscountAmount = decimal.Zero; Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; SortedDictionary<decimal, decimal> orderSubTotalTaxRates = null; GetShoppingCartSubTotal(cart, false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase, out orderSubTotalTaxRates); foreach (KeyValuePair<decimal, decimal> kvp in orderSubTotalTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; subTotalTaxTotal += taxValue; if (taxRate > decimal.Zero && taxValue > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) taxRates.Add(taxRate, taxValue); else taxRates[taxRate] = taxRates[taxRate] + taxValue; } } //shipping decimal shippingTax = decimal.Zero; if (_taxSettings.ShippingIsTaxable) { decimal taxRate = decimal.Zero; decimal? shippingExclTax = GetShoppingCartShippingTotal(cart, false, out taxRate); decimal? shippingInclTax = GetShoppingCartShippingTotal(cart, true, out taxRate); if (shippingExclTax.HasValue && shippingInclTax.HasValue) { shippingTax = shippingInclTax.Value - shippingExclTax.Value; //ensure that tax is equal or greater than zero if (shippingTax < decimal.Zero) shippingTax = decimal.Zero; //tax rates if (taxRate > decimal.Zero && shippingTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) taxRates.Add(taxRate, shippingTax); else taxRates[taxRate] = taxRates[taxRate] + shippingTax; } } } //payment method additional fee decimal paymentMethodAdditionalFeeTax = decimal.Zero; if (usePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable) { decimal taxRate = decimal.Zero; decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); decimal paymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer, out taxRate); decimal paymentMethodAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer, out taxRate); paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax; //ensure that tax is equal or greater than zero if (paymentMethodAdditionalFeeTax < decimal.Zero) paymentMethodAdditionalFeeTax = decimal.Zero; //tax rates if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) taxRates.Add(taxRate, paymentMethodAdditionalFeeTax); else taxRates[taxRate] = taxRates[taxRate] + paymentMethodAdditionalFeeTax; } } //add at least one tax rate (0%) if (taxRates.Count == 0) taxRates.Add(decimal.Zero, decimal.Zero); //summarize taxes decimal taxTotal = subTotalTaxTotal + shippingTax + paymentMethodAdditionalFeeTax; //ensure that tax is equal or greater than zero if (taxTotal < decimal.Zero) taxTotal = decimal.Zero; //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) taxTotal = Math.Round(taxTotal, 2); return taxTotal; }
protected virtual void PrepareWishlistModel(WishlistModel model, IList<ShoppingCartItem> cart, bool isEditable = true) { if (cart == null) throw new ArgumentNullException("cart"); if (model == null) throw new ArgumentNullException("model"); model.EmailWishlistEnabled = _shoppingCartSettings.EmailWishlistEnabled; model.IsEditable = isEditable; model.DisplayAddToCart = _permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart); model.DisplayTaxShippingInfo = _catalogSettings.DisplayTaxShippingInfoWishlist; if (cart.Count == 0) return; #region Simple properties var customer = cart.GetCustomer(); model.CustomerGuid = customer.CustomerGuid; model.CustomerFullname = customer.GetFullName(); model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart; model.ShowSku = _catalogSettings.ShowProductSku; //cart warnings var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, "", false); foreach (var warning in cartWarnings) model.Warnings.Add(warning); #endregion #region Cart items foreach (var sci in cart) { var cartItemModel = new WishlistModel.ShoppingCartItemModel { Id = sci.Id, Sku = sci.Product.FormatSku(sci.AttributesXml, _productAttributeParser), ProductId = sci.Product.Id, ProductName = sci.Product.GetLocalized(x => x.Name), ProductSeName = sci.Product.GetSeName(), Quantity = sci.Quantity, AttributeInfo = _productAttributeFormatter.FormatAttributes(sci.Product, sci.AttributesXml), }; //allowed quantities var allowedQuantities = sci.Product.ParseAllowedQuantities(); foreach (var qty in allowedQuantities) { cartItemModel.AllowedQuantities.Add(new SelectListItem { Text = qty.ToString(), Value = qty.ToString(), Selected = sci.Quantity == qty }); } //recurring info if (sci.Product.IsRecurring) cartItemModel.RecurringInfo = string.Format(_localizationService.GetResource("ShoppingCart.RecurringPeriod"), sci.Product.RecurringCycleLength, sci.Product.RecurringCyclePeriod.GetLocalizedEnum(_localizationService, _workContext)); //rental info if (sci.Product.IsRental) { var rentalStartDate = sci.RentalStartDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalStartDateUtc.Value) : ""; var rentalEndDate = sci.RentalEndDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalEndDateUtc.Value) : ""; cartItemModel.RentalInfo = string.Format(_localizationService.GetResource("ShoppingCart.Rental.FormattedDate"), rentalStartDate, rentalEndDate); } //unit prices if (sci.Product.CallForPrice) { cartItemModel.UnitPrice = _localizationService.GetResource("Products.CallForPrice"); } else { decimal taxRate; decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetUnitPrice(sci), out taxRate); decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.UnitPrice = _priceFormatter.FormatPrice(shoppingCartUnitPriceWithDiscount); } //subtotal, discount if (sci.Product.CallForPrice) { cartItemModel.SubTotal = _localizationService.GetResource("Products.CallForPrice"); } else { //sub total Discount scDiscount; decimal shoppingCartItemDiscountBase; decimal taxRate; decimal shoppingCartItemSubTotalWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetSubTotal(sci, true, out shoppingCartItemDiscountBase, out scDiscount), out taxRate); decimal shoppingCartItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemSubTotalWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.SubTotal = _priceFormatter.FormatPrice(shoppingCartItemSubTotalWithDiscount); //display an applied discount amount if (scDiscount != null) { shoppingCartItemDiscountBase = _taxService.GetProductPrice(sci.Product, shoppingCartItemDiscountBase, out taxRate); if (shoppingCartItemDiscountBase > decimal.Zero) { decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency); cartItemModel.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount); } } } //picture if (_shoppingCartSettings.ShowProductImagesOnShoppingCart) { cartItemModel.Picture = PrepareCartItemPictureModel(sci, _mediaSettings.CartThumbPictureSize, true, cartItemModel.ProductName); } //item warnings var itemWarnings = _shoppingCartService.GetShoppingCartItemWarnings( _workContext.CurrentCustomer, sci.ShoppingCartType, sci.Product, sci.StoreId, sci.AttributesXml, sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false); foreach (var warning in itemWarnings) cartItemModel.Warnings.Add(warning); model.Items.Add(cartItemModel); } #endregion }
/// <summary> /// Gets a value indicating whether shipping is free /// </summary> /// <param name="cart">Cart</param> /// <param name="subTotal">Subtotal amount; pass null to calculate subtotal</param> /// <returns>A value indicating whether shipping is free</returns> public virtual bool IsFreeShipping(IList<ShoppingCartItem> cart, decimal? subTotal = null) { if (!cart.RequiresShipping()) return true; //check whether customer is in a customer role with free shipping applied var customer = cart.GetCustomer(); if (customer != null && customer.CustomerRoles.Where(role => role.Active).Any(role => role.FreeShipping)) return true; //check whether all shopping cart items are marked as free shipping if (cart.All(item => item.IsShipEnabled && item.IsFreeShipping)) return true; //free shipping over $X if (_shippingSettings.FreeShippingOverXEnabled) { if (!subTotal.HasValue) { decimal discountAmount; List<Discount> appliedDiscounts; decimal subTotalWithoutDiscount; decimal subTotalWithDiscount; GetShoppingCartSubTotal(cart, _shippingSettings.FreeShippingOverXIncludingTax, out discountAmount, out appliedDiscounts, out subTotalWithoutDiscount, out subTotalWithDiscount); subTotal = subTotalWithDiscount; } //check whether we have subtotal enough to have free shipping if (subTotal.Value > _shippingSettings.FreeShippingOverXValue) return true; } return false; }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal? GetShoppingCartShippingTotal(IList<ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out Discount appliedDiscount) { decimal? shippingTotalWithoutDiscount = null; decimal? shippingTotalWithDiscount = null; decimal? shippingTotalWithDiscountTaxed = null; appliedDiscount = null; taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = _shippingService.IsFreeShipping(cart); if (isFreeShipping) return decimal.Zero; //free shipping over $X if (_shippingSettings.FreeShippingOverXEnabled) { //check whether we have subtotal enough to have free shipping decimal subTotalDiscountAmount = decimal.Zero; Discount subTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; GetShoppingCartSubTotal(cart, includingTax, out subTotalDiscountAmount, out subTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); if (subTotalWithDiscountBase > _shippingSettings.FreeShippingOverXValue) return decimal.Zero; } ShippingOption lastShippingOption = null; if (customer != null) lastShippingOption = customer.GetAttribute<ShippingOption>(SystemCustomerAttributeNames.LastShippingOption); if (lastShippingOption != null) { //use last shipping option (get from cache) //we have already discounted cache value shippingTotalWithoutDiscount = lastShippingOption.Rate; //discount decimal discountAmount = GetShippingDiscount(customer, shippingTotalWithoutDiscount.Value, out appliedDiscount); shippingTotalWithDiscount = shippingTotalWithoutDiscount - discountAmount; if (shippingTotalWithDiscount < decimal.Zero) shippingTotalWithDiscount = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalWithDiscount = Math.Round(shippingTotalWithDiscount.Value, 2); } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) shippingAddress = customer.ShippingAddress; var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(); if (shippingRateComputationMethods == null || shippingRateComputationMethods.Count == 0) throw new NopException("Shipping rate computation method could not be loaded"); if (shippingRateComputationMethods.Count == 1) { var getShippingOptionRequest = _shippingService.CreateShippingOptionRequest(cart, shippingAddress); var shippingRateComputationMethod = shippingRateComputationMethods[0]; decimal? fixedRate = shippingRateComputationMethod.GetFixedRate(getShippingOptionRequest); if (fixedRate.HasValue) { decimal additionalShippingCharge = _shippingService.GetShoppingCartAdditionalShippingCharge(cart); shippingTotalWithoutDiscount = fixedRate.Value + additionalShippingCharge; if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalWithoutDiscount = Math.Round(shippingTotalWithoutDiscount.Value, 2); decimal shippingTotalDiscount = GetShippingDiscount(customer, shippingTotalWithoutDiscount.Value, out appliedDiscount); shippingTotalWithDiscount = shippingTotalWithoutDiscount.Value - shippingTotalDiscount; if (shippingTotalWithDiscount.Value < decimal.Zero) shippingTotalWithDiscount = decimal.Zero; } } } if (shippingTotalWithDiscount.HasValue) { shippingTotalWithDiscountTaxed = _taxService.GetShippingPrice(shippingTotalWithDiscount.Value, includingTax, customer, out taxRate); if (_shoppingCartSettings.RoundPricesDuringCalculation) shippingTotalWithDiscountTaxed = Math.Round(shippingTotalWithDiscountTaxed.Value, 2); } return shippingTotalWithDiscountTaxed; }
/// <summary> /// Create shipment packages (requests) from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <returns>Shipment packages (requests)</returns> public virtual IList <GetShippingOptionRequest> CreateShippingOptionRequests(IList <ShoppingCartItem> cart, Address shippingAddress) { //if we always ship from the default shipping original, then there's only one request //if we ship from warehouses, then there could be several requests //key - warehouse identifier (0 - default shipping origin) //value - request var requests = new Dictionary <int, GetShippingOptionRequest>(); foreach (var sci in cart) { if (!sci.IsShipEnabled) { continue; } Warehouse warehouse = null; if (_shippingSettings.UseWarehouseLocation) { warehouse = GetWarehouseById(sci.Product.WarehouseId); } GetShippingOptionRequest request = null; if (requests.ContainsKey(warehouse != null ? warehouse.Id : 0)) { request = requests[warehouse != null ? warehouse.Id : 0]; //add item request.Items.Add(sci); } else { request = new GetShippingOptionRequest(); //add item request.Items.Add(sci); //customer request.Customer = cart.GetCustomer(); //ship to request.ShippingAddress = shippingAddress; //ship from Address originAddress = null; if (warehouse != null) { //warehouse address originAddress = _addressService.GetAddressById(warehouse.AddressId); } if (originAddress == null) { //no warehouse address. in this case use the default hipping origin originAddress = _addressService.GetAddressById(_shippingSettings.ShippingOriginAddressId); } if (originAddress != null) { request.CountryFrom = originAddress.Country; request.StateProvinceFrom = originAddress.StateProvince; request.ZipPostalCodeFrom = originAddress.ZipPostalCode; request.CityFrom = originAddress.City; request.AddressFrom = originAddress.Address1; } requests.Add(warehouse != null ? warehouse.Id : 0, request); } } return(requests.Values.ToList()); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</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 GetShippingOptionResponse GetShippingOptions(IList<ShoppingCartItem> cart, Address shippingAddress, string allowedShippingRateComputationMethodSystemName = "", int storeId = 0) { if (cart == null) throw new ArgumentNullException("cart"); var result = new GetShippingOptionResponse(); //create a package bool shippingFromMultipleLocations; var shippingOptionRequests = CreateShippingOptionRequests(cart, shippingAddress, storeId, out shippingFromMultipleLocations); result.ShippingFromMultipleLocations = shippingFromMultipleLocations; var shippingRateComputationMethods = LoadActiveShippingRateComputationMethods(storeId); //filter by system name if (!String.IsNullOrWhiteSpace(allowedShippingRateComputationMethodSystemName)) { shippingRateComputationMethods = shippingRateComputationMethods .Where(srcm => allowedShippingRateComputationMethodSystemName.Equals(srcm.PluginDescriptor.SystemName, StringComparison.InvariantCultureIgnoreCase)) .ToList(); } if (shippingRateComputationMethods.Count == 0) throw new NopException("Shipping rate computation method could not be loaded"); //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 = srcm.GetShippingOptions(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 (string error in getShippingOptionResponse.Errors) { result.AddError(error); _logger.Warning(string.Format("Shipping ({0}). {1}", 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) { foreach (var so in srcmShippingOptions) { so.ShippingRateComputationMethodSystemName = srcm.PluginDescriptor.SystemName; if (_shoppingCartSettings.RoundPricesDuringCalculation) so.Rate = RoundingHelper.RoundPrice(so.Rate); //if free shipping exist in customer benefit table, then set so.rate = 0.00 //var customer = cart.CustomerId; var customerid = cart.GetCustomer().Id; List<int> freeShipping = _dbContext.SqlQuery<int>("exec CustomerBenefit_Load @CustomerId", new System.Data.SqlClient.SqlParameter("@CustomerId", customerid)).ToList(); //string gcCode = _giftCardService.GetCustomerGiftCard(cart.GetCustomer()); if (freeShipping.Count > 0 && freeShipping[0] != 0) { so.Rate = RoundingHelper.RoundPrice(0); } result.ShippingOptions.Add(so); } } } if (_shippingSettings.ReturnValidOptionsIfThereAreAny) { //return valid options if there are any (no matter of the errors returned by other shipping rate compuation methods). if (result.ShippingOptions.Count > 0 && result.Errors.Count > 0) result.Errors.Clear(); } //no shipping options loaded if (result.ShippingOptions.Count == 0 && result.Errors.Count == 0) result.Errors.Add(_localizationService.GetResource("Checkout.ShippingOptionCouldNotBeLoaded")); return result; }
/// <summary> /// Gets total price /// </summary> /// <param name="cart">Shipping cart items</param> /// <returns>Total price</returns> public virtual decimal GetTotalPrice(IList<ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); decimal totalPrice = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) totalPrice += GetShoppingCartItemPrice(shoppingCartItem) * shoppingCartItem.Quantity; return totalPrice; }
protected virtual OrderTotalsModel PrepareOrderTotalsModel(IList<ShoppingCartItem> cart, bool isEditable, bool blnApplyGiftCard = false) { 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; //Find total taxes from products in cart var taxRate = _orderTotalCalculationService.GetTaxTotalByCity(cart); decimal totalTax = 0; foreach (var item in cart) { if (item.Product.IsEnabledAreaRate) { //totalTax = totalTax + (taxRate * item.Product.Price); totalTax = totalTax + (item.Product.Price * item.Quantity); } } totalTax = Math.Round(totalTax * taxRate, 2); model.Tax = totalTax.ToString(); //apply gift card var customer = cart.GetCustomer(); string gcCode = _giftCardService.GetCustomerGiftCard(customer); if (gcCode.Length > 0) customer.ApplyGiftCardCouponCode(gcCode); //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); if (shoppingCartTotalBase.HasValue) { decimal shoppingCartTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, _workContext.WorkingCurrency); model.OrderTotal = _priceFormatter.FormatPrice(shoppingCartTotal, true, false); } //discount if (orderTotalDiscountAmountBase > decimal.Zero) { decimal orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotalDiscountAmountBase, _workContext.WorkingCurrency); model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderTotalDiscountAmount, true, false); model.AllowRemovingOrderTotalDiscount = orderTotalAppliedDiscount != null && orderTotalAppliedDiscount.RequiresCouponCode && !String.IsNullOrEmpty(orderTotalAppliedDiscount.CouponCode) && model.IsEditable; } //gift cards if (appliedGiftCards != null && appliedGiftCards.Count > 0 && blnApplyGiftCard) { foreach (var appliedGiftCard in appliedGiftCards) { var gcModel = new OrderTotalsModel.GiftCard { Id = appliedGiftCard.GiftCard.Id, CouponCode = appliedGiftCard.GiftCard.GiftCardCouponCode, }; decimal amountCanBeUsed = _currencyService.ConvertFromPrimaryStoreCurrency(appliedGiftCard.AmountCanBeUsed, _workContext.WorkingCurrency); gcModel.Amount = _priceFormatter.FormatPrice(-amountCanBeUsed, true, false); decimal remainingAmountBase = appliedGiftCard.GiftCard.GetGiftCardRemainingAmount() - appliedGiftCard.AmountCanBeUsed; decimal remainingAmount = _currencyService.ConvertFromPrimaryStoreCurrency(remainingAmountBase, _workContext.WorkingCurrency); gcModel.StartingBalance = appliedGiftCard.GiftCard.GetGiftCardRemainingAmount(); gcModel.Remaining = _priceFormatter.FormatPrice(remainingAmount, true, false); model.GiftCards.Add(gcModel); } } //reward points to be spent (redeemed) if (redeemedRewardPointsAmount > decimal.Zero) { decimal redeemedRewardPointsAmountInCustomerCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(redeemedRewardPointsAmount, _workContext.WorkingCurrency); model.RedeemedRewardPoints = redeemedRewardPoints; model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-redeemedRewardPointsAmountInCustomerCurrency, true, false); } //reward points to be earned if (_rewardPointsSettings.Enabled && _rewardPointsSettings.DisplayHowMuchWillBeEarned && shoppingCartTotalBase.HasValue) { model.WillEarnRewardPoints = _orderTotalCalculationService .CalculateRewardPoints(_workContext.CurrentCustomer, shoppingCartTotalBase.Value); } //model.Tax = //model.TaxRates.Add(new OrderTotalsModel.TaxRate //{ // Rate = _priceFormatter.FormatTaxRate(tr.Key), // Value = _priceFormatter.FormatPrice(_currencyService.ConvertFromPrimaryStoreCurrency(tr.Value, _workContext.WorkingCurrency), true, false), //}); } //decimal tax = Decimal.Parse(model.Tax); //decimal ordersubtotal = Decimal.Parse(model.SubTotal.Substring(1)); //decimal totalWithTaxes = tax + ordersubtotal; //model.OrderTotal = totalWithTaxes.ToString(); return model; }
/// <summary> /// Gets shopping cart shipping total /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="taxRate">Applied tax rate</param> /// <param name="appliedDiscount">Applied discount</param> /// <returns>Shipping total</returns> public virtual decimal?GetShoppingCartShippingTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal taxRate, out List <Discount> appliedDiscounts) { decimal?shippingTotal = null; decimal?shippingTotalTaxed = null; appliedDiscounts = new List <Discount>(); taxRate = decimal.Zero; var customer = cart.GetCustomer(); bool isFreeShipping = IsFreeShipping(cart); if (isFreeShipping) { return(decimal.Zero); } ShippingOption shippingOption = null; if (customer != null) { shippingOption = customer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id); } if (shippingOption != null) { shippingTotal = AdjustShippingRate(shippingOption.Rate, cart, out appliedDiscounts); } else { //use fixed rate (if possible) Address shippingAddress = null; if (customer != null) { shippingAddress = customer.ShippingAddress; } var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id, cart); if (!shippingRateComputationMethods.Any() && !_shippingSettings.AllowPickUpInStore) { throw new GrandException("Shipping rate computation method could not be loaded"); } if (shippingRateComputationMethods.Count == 1) { var shippingRateComputationMethod = shippingRateComputationMethods[0]; bool shippingFromMultipleLocations; var shippingOptionRequests = _shippingService.CreateShippingOptionRequests(cart, shippingAddress, _storeContext.CurrentStore.Id, out shippingFromMultipleLocations); decimal?fixedRate = null; foreach (var shippingOptionRequest in shippingOptionRequests) { //calculate fixed rates for each request-package var fixedRateTmp = shippingRateComputationMethod.GetFixedRate(shippingOptionRequest); if (fixedRateTmp.HasValue) { if (!fixedRate.HasValue) { fixedRate = decimal.Zero; } fixedRate += fixedRateTmp.Value; } } if (fixedRate.HasValue) { //adjust shipping rate shippingTotal = AdjustShippingRate(fixedRate.Value, cart, out appliedDiscounts); } } } if (shippingTotal.HasValue) { if (shippingTotal.Value < decimal.Zero) { shippingTotal = decimal.Zero; } //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotal = RoundingHelper.RoundPrice(shippingTotal.Value); } shippingTotalTaxed = _taxService.GetShippingPrice(shippingTotal.Value, includingTax, customer, out taxRate); //round if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotalTaxed = RoundingHelper.RoundPrice(shippingTotalTaxed.Value); } } return(shippingTotalTaxed); }
/// <summary> /// Update order totals /// </summary> /// <param name="updateOrderParameters">Parameters for the updating order</param> /// <param name="restoredCart">Shopping cart</param> public virtual void UpdateOrderTotals(UpdateOrderParameters updateOrderParameters, IList<ShoppingCartItem> restoredCart) { var updatedOrder = updateOrderParameters.UpdatedOrder; var updatedOrderItem = updateOrderParameters.UpdatedOrderItem; //get the customer var customer = restoredCart.GetCustomer(); #region Sub total var subTotalExclTax = decimal.Zero; var subTotalInclTax = decimal.Zero; var subTotalTaxRates = new SortedDictionary<decimal, decimal>(); foreach (var shoppingCartItem in restoredCart) { var itemSubTotalExclTax = decimal.Zero; var itemSubTotalInclTax = decimal.Zero; var taxRate = decimal.Zero; var itemDiscounts = new List<Discount>(); //calculate subtotal for the updated order item if (shoppingCartItem.Id == updatedOrderItem.Id) { //update order item updatedOrderItem.UnitPriceExclTax = updateOrderParameters.PriceExclTax; updatedOrderItem.UnitPriceInclTax = updateOrderParameters.PriceInclTax; updatedOrderItem.DiscountAmountExclTax = updateOrderParameters.DiscountAmountExclTax; updatedOrderItem.DiscountAmountInclTax = updateOrderParameters.DiscountAmountInclTax; updatedOrderItem.PriceExclTax = itemSubTotalExclTax = updateOrderParameters.SubTotalExclTax; updatedOrderItem.PriceInclTax = itemSubTotalInclTax = updateOrderParameters.SubTotalInclTax; updatedOrderItem.Quantity = shoppingCartItem.Quantity; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } else { //get the already calculated subtotal from the order item itemSubTotalExclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceExclTax; itemSubTotalInclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceInclTax; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } foreach (var discount in itemDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); subTotalExclTax += itemSubTotalExclTax; subTotalInclTax += itemSubTotalInclTax; //tax rates var itemTaxValue = itemSubTotalInclTax - itemSubTotalExclTax; if (taxRate > decimal.Zero && itemTaxValue > decimal.Zero) { if (!subTotalTaxRates.ContainsKey(taxRate)) subTotalTaxRates.Add(taxRate, itemTaxValue); else subTotalTaxRates[taxRate] = subTotalTaxRates[taxRate] + itemTaxValue; } } if (subTotalExclTax < decimal.Zero) subTotalExclTax = decimal.Zero; if (subTotalInclTax < decimal.Zero) subTotalInclTax = decimal.Zero; //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) List<Discount> subTotalDiscounts; var discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTax, out subTotalDiscounts); if (subTotalExclTax < discountAmountExclTax) discountAmountExclTax = subTotalExclTax; var discountAmountInclTax = discountAmountExclTax; //add tax for shopping items var tempTaxRates = new Dictionary<decimal, decimal>(subTotalTaxRates); foreach (var kvp in tempTaxRates) { if (kvp.Value != decimal.Zero && subTotalExclTax > decimal.Zero) { var discountTaxValue = kvp.Value * (discountAmountExclTax / subTotalExclTax); discountAmountInclTax += discountTaxValue; subTotalTaxRates[kvp.Key] = kvp.Value - discountTaxValue; } } //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalExclTax = RoundingHelper.RoundPrice(subTotalExclTax); subTotalInclTax = RoundingHelper.RoundPrice(subTotalInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); } updatedOrder.OrderSubtotalExclTax = subTotalExclTax; updatedOrder.OrderSubtotalInclTax = subTotalInclTax; updatedOrder.OrderSubTotalDiscountExclTax = discountAmountExclTax; updatedOrder.OrderSubTotalDiscountInclTax = discountAmountInclTax; foreach (var discount in subTotalDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); #endregion #region Shipping var shippingTotalExclTax = decimal.Zero; var shippingTotalInclTax = decimal.Zero; var shippingTaxRate = decimal.Zero; if (restoredCart.RequiresShipping()) { if (!IsFreeShipping(restoredCart, _shippingSettings.FreeShippingOverXIncludingTax ? subTotalInclTax : subTotalExclTax)) { var shippingTotal = decimal.Zero; if (!string.IsNullOrEmpty(updatedOrder.ShippingRateComputationMethodSystemName)) { //in the updated order were shipping items if (updatedOrder.PickUpInStore) { //customer chose pickup in store method, try to get chosen pickup point if (_shippingSettings.AllowPickUpInStore) { var pickupPointsResponse = _shippingService.GetPickupPoints(updatedOrder.BillingAddress, updatedOrder.ShippingRateComputationMethodSystemName, _storeContext.CurrentStore.Id); if (pickupPointsResponse.Success) { var selectedPickupPoint = pickupPointsResponse.PickupPoints.FirstOrDefault(point => updatedOrder.ShippingMethod.Contains(point.Name)); if (selectedPickupPoint != null) shippingTotal = selectedPickupPoint.PickupFee; else updateOrderParameters.Warnings.Add(string.Format("Shipping method {0} could not be loaded", updatedOrder.ShippingMethod)); } else updateOrderParameters.Warnings.AddRange(pickupPointsResponse.Errors); } else updateOrderParameters.Warnings.Add("Pick up in store is not available"); } else { //customer chose shipping to address, try to get chosen shipping option var shippingOptionsResponse = _shippingService.GetShippingOptions(restoredCart, updatedOrder.ShippingAddress, updatedOrder.ShippingRateComputationMethodSystemName, _storeContext.CurrentStore.Id); if (shippingOptionsResponse.Success) { var shippingOption = shippingOptionsResponse.ShippingOptions.FirstOrDefault(option => updatedOrder.ShippingMethod.Contains(option.Name)); if (shippingOption != null) shippingTotal = shippingOption.Rate; else updateOrderParameters.Warnings.Add(string.Format("Shipping method {0} could not be loaded", updatedOrder.ShippingMethod)); } else updateOrderParameters.Warnings.AddRange(shippingOptionsResponse.Errors); } } else { //before updating order was without shipping if (_shippingSettings.AllowPickUpInStore) { //try to get the cheapest pickup point var pickupPointsResponse = _shippingService.GetPickupPoints(updatedOrder.BillingAddress, null, _storeContext.CurrentStore.Id); if (pickupPointsResponse.Success) { updateOrderParameters.PickupPoint = pickupPointsResponse.PickupPoints.OrderBy(point => point.PickupFee).First(); shippingTotal = updateOrderParameters.PickupPoint.PickupFee; } else updateOrderParameters.Warnings.AddRange(pickupPointsResponse.Errors); } else updateOrderParameters.Warnings.Add("Pick up in store is not available"); if (updateOrderParameters.PickupPoint == null) { //or try to get the cheapest shipping option for the shipping to the customer address var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id); if (shippingRateComputationMethods.Any()) { var shippingOptionsResponse = _shippingService.GetShippingOptions(restoredCart, customer.ShippingAddress, null, _storeContext.CurrentStore.Id); if (shippingOptionsResponse.Success) { var shippingOption = shippingOptionsResponse.ShippingOptions.OrderBy(option => option.Rate).First(); updatedOrder.ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName; updatedOrder.ShippingMethod = shippingOption.Name; updatedOrder.ShippingAddress = (Address)customer.ShippingAddress.Clone(); shippingTotal = shippingOption.Rate; } else updateOrderParameters.Warnings.AddRange(shippingOptionsResponse.Errors); } else updateOrderParameters.Warnings.Add("Shipping rate computation method could not be loaded"); } } //additional shipping charge shippingTotal += restoredCart.Where(item => item.IsShipEnabled && !item.IsFreeShipping).Sum(item => item.Product.AdditionalShippingCharge); //shipping discounts List<Discount> shippingTotalDiscounts; shippingTotal -= GetShippingDiscount(customer, shippingTotal, out shippingTotalDiscounts); if (shippingTotal < decimal.Zero) shippingTotal = decimal.Zero; shippingTotalExclTax = _taxService.GetShippingPrice(shippingTotal, false, customer); shippingTotalInclTax = _taxService.GetShippingPrice(shippingTotal, true, customer, out shippingTaxRate); //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotalExclTax = RoundingHelper.RoundPrice(shippingTotalExclTax); shippingTotalInclTax = RoundingHelper.RoundPrice(shippingTotalInclTax); } //change shipping status if (updatedOrder.ShippingStatus == ShippingStatus.ShippingNotRequired || updatedOrder.ShippingStatus == ShippingStatus.NotYetShipped) updatedOrder.ShippingStatus = ShippingStatus.NotYetShipped; else updatedOrder.ShippingStatus = ShippingStatus.PartiallyShipped; foreach (var discount in shippingTotalDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); } } else updatedOrder.ShippingStatus = ShippingStatus.ShippingNotRequired; updatedOrder.OrderShippingExclTax = shippingTotalExclTax; updatedOrder.OrderShippingInclTax = shippingTotalInclTax; #endregion #region Tax rates var taxRates = new SortedDictionary<decimal, decimal>(); //order subtotal taxes var subTotalTax = decimal.Zero; foreach (var kvp in subTotalTaxRates) { subTotalTax += kvp.Value; if (kvp.Key > decimal.Zero && kvp.Value > decimal.Zero) { if (!taxRates.ContainsKey(kvp.Key)) taxRates.Add(kvp.Key, kvp.Value); else taxRates[kvp.Key] = taxRates[kvp.Key] + kvp.Value; } } //shipping taxes var shippingTax = decimal.Zero; if (_taxSettings.ShippingIsTaxable) { shippingTax = shippingTotalInclTax - shippingTotalExclTax; if (shippingTax < decimal.Zero) shippingTax = decimal.Zero; if (shippingTaxRate > decimal.Zero && shippingTax > decimal.Zero) { if (!taxRates.ContainsKey(shippingTaxRate)) taxRates.Add(shippingTaxRate, shippingTax); else taxRates[shippingTaxRate] = taxRates[shippingTaxRate] + shippingTax; } } //payment method additional fee tax var paymentMethodAdditionalFeeTax = decimal.Zero; if (_taxSettings.PaymentMethodAdditionalFeeIsTaxable) { paymentMethodAdditionalFeeTax = updatedOrder.PaymentMethodAdditionalFeeInclTax - updatedOrder.PaymentMethodAdditionalFeeExclTax; if (paymentMethodAdditionalFeeTax < decimal.Zero) paymentMethodAdditionalFeeTax = decimal.Zero; if (updatedOrder.PaymentMethodAdditionalFeeExclTax > decimal.Zero) { var paymentTaxRate = Math.Round(100 * paymentMethodAdditionalFeeTax / updatedOrder.PaymentMethodAdditionalFeeExclTax, 3); if (paymentTaxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(paymentTaxRate)) taxRates.Add(paymentTaxRate, paymentMethodAdditionalFeeTax); else taxRates[paymentTaxRate] = taxRates[paymentTaxRate] + paymentMethodAdditionalFeeTax; } } } //add at least one tax rate (0%) if (!taxRates.Any()) taxRates.Add(decimal.Zero, decimal.Zero); //summarize taxes var taxTotal = subTotalTax + shippingTax + paymentMethodAdditionalFeeTax; if (taxTotal < decimal.Zero) taxTotal = decimal.Zero; //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) taxTotal = RoundingHelper.RoundPrice(taxTotal); updatedOrder.OrderTax = taxTotal; updatedOrder.TaxRates = taxRates.Aggregate(string.Empty, (current, next) => string.Format("{0}{1}:{2}; ", current, next.Key.ToString(CultureInfo.InvariantCulture), next.Value.ToString(CultureInfo.InvariantCulture))); #endregion #region Total var total = (subTotalExclTax - discountAmountExclTax) + shippingTotalExclTax + updatedOrder.PaymentMethodAdditionalFeeExclTax + taxTotal; //get discounts for the order total List<Discount> orderAppliedDiscounts; var discountAmountTotal = GetOrderTotalDiscount(customer, total, out orderAppliedDiscounts); if (total < discountAmountTotal) discountAmountTotal = total; total -= discountAmountTotal; //applied giftcards foreach (var giftCard in _giftCardService.GetAllGiftCards(usedWithOrderId: updatedOrder.Id)) { if (total > decimal.Zero) { var remainingAmount = giftCard.GiftCardUsageHistory.Where(history => history.UsedWithOrderId == updatedOrder.Id).Sum(history => history.UsedValue); var amountCanBeUsed = total > remainingAmount ? remainingAmount : total; total -= amountCanBeUsed; } } //reward points var rewardPointsOfOrder = _rewardPointService.GetRewardPointsHistory(customer.Id, true).FirstOrDefault(history => history.UsedWithOrder == updatedOrder); if (rewardPointsOfOrder != null) { var rewardPoints = -rewardPointsOfOrder.Points; var rewardPointsAmount = ConvertRewardPointsToAmount(rewardPoints); if (total < rewardPointsAmount) { rewardPoints = ConvertAmountToRewardPoints(total); rewardPointsAmount = total; } if (total > decimal.Zero) total -= rewardPointsAmount; //uncomment here for the return unused reward points if new order total less redeemed reward points amount //if (rewardPoints < -rewardPointsOfOrder.Points) // _rewardPointService.AddRewardPointsHistoryEntry(customer, -rewardPointsOfOrder.Points - rewardPoints, _storeContext.CurrentStore.Id, "Return unused reward points"); if (rewardPointsAmount != rewardPointsOfOrder.UsedAmount) { rewardPointsOfOrder.UsedAmount = rewardPointsAmount; rewardPointsOfOrder.Points = -rewardPoints; _rewardPointService.UpdateRewardPointsHistoryEntry(rewardPointsOfOrder); } } //rounding if (total < decimal.Zero) total = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) total = RoundingHelper.RoundPrice(total); updatedOrder.OrderDiscount = discountAmountTotal; updatedOrder.OrderTotal = total; foreach (var discount in orderAppliedDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); #endregion }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetShoppingCartTotalWeight(IList<ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) totalWeight += GetShoppingCartItemTotalWeight(shoppingCartItem); //checkout attributes if (customer != null) { if (!String.IsNullOrEmpty(customer.CheckoutAttributes)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(customer.CheckoutAttributes); foreach (var caValue in caValues) totalWeight += caValue.WeightAdjustment; } } return totalWeight; }
/// <summary> /// Gets shopping cart weight /// </summary> /// <param name="cart">Cart</param> /// <param name="includeCheckoutAttributes">A value indicating whether we should calculate weights of selected checkotu attributes</param> /// <returns>Shopping cart weight</returns> public virtual decimal GetTotalWeight(IList<ShoppingCartItem> cart, bool includeCheckoutAttributes = true) { Customer customer = cart.GetCustomer(); decimal totalWeight = decimal.Zero; //shopping cart items foreach (var shoppingCartItem in cart) totalWeight += GetShoppingCartItemWeight(shoppingCartItem) * shoppingCartItem.Quantity; //checkout attributes if (customer != null && includeCheckoutAttributes) { var checkoutAttributesXml = customer.GetAttribute<string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); if (!String.IsNullOrEmpty(checkoutAttributesXml)) { var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); foreach (var caValue in caValues) totalWeight += caValue.WeightAdjustment; } } return totalWeight; }
/// <summary> /// Create shipment package from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <returns>Shipment package</returns> public virtual GetShippingOptionRequest CreateShippingOptionRequest(IList<ShoppingCartItem> cart, Address shippingAddress) { var request = new GetShippingOptionRequest(); request.Customer = cart.GetCustomer(); request.Items = new List<ShoppingCartItem>(); foreach (var sc in cart) if (sc.IsShipEnabled) request.Items.Add(sc); request.ShippingAddress = shippingAddress; request.CountryFrom = null; request.StateProvinceFrom = null; request.ZipPostalCodeFrom = string.Empty; return request; }
/// <summary> /// Gets a value indicating whether shipping is free /// </summary> /// <param name="cart">Cart</param> /// <returns>A value indicating whether shipping is free</returns> public virtual bool IsFreeShipping(IList<ShoppingCartItem> cart) { Customer customer = cart.GetCustomer(); if (customer != null) { //check whether customer is in a customer role with free shipping applied var customerRoles = customer.CustomerRoles.Where(cr => cr.Active); foreach (var customerRole in customerRoles) if (customerRole.FreeShipping) return true; } bool shoppingCartRequiresShipping = cart.RequiresShipping(); if (!shoppingCartRequiresShipping) return true; //check whether all shopping cart items are marked as free shipping bool allItemsAreFreeShipping = true; foreach (var sc in cart) { if (sc.IsShipEnabled && !sc.IsFreeShipping) { allItemsAreFreeShipping = false; break; } } if (allItemsAreFreeShipping) return true; //otherwise, return false return false; }
/// <summary> /// Gets shopping cart subtotal /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscounts">Applied discounts</param> /// <param name="subTotalWithoutDiscount">Sub total (without discount)</param> /// <param name="subTotalWithDiscount">Sub total (with discount)</param> /// <param name="taxRates">Tax rates (of subscription sub total)</param> public virtual void GetShoppingCartSubTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary <decimal, decimal> taxRates) { discountAmount = decimal.Zero; subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary <decimal, decimal>(); if (!cart.Any()) { return; } //get the customer Customer customer = cart.GetCustomer(); //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { decimal sciSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem); decimal taxRate; decimal sciExclTax = _taxService.GetArticlePrice(shoppingCartItem.Article, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetArticlePrice(shoppingCartItem.Article, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (attributeValues != null) { foreach (var attributeValue in attributeValues) { decimal taxRate; decimal caExclTax = _taxService.GetCheckoutAttributePrice(attributeValue, false, customer, out taxRate); decimal caInclTax = _taxService.GetCheckoutAttributePrice(attributeValue, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { 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 = RoundingHelper.RoundPrice(subTotalWithoutDiscount); } //We calculate discount amount on subscription subtotal excl tax (discount first) //calculate discount amount ('Applied to subscription subtotal' discount) decimal discountAmountExclTax = GetSubscriptionSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) { discountAmountExclTax = subTotalExclTaxWithoutDiscount; } decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes var tempTaxRates = new Dictionary <decimal, decimal>(taxRates); foreach (KeyValuePair <decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxValue = RoundingHelper.RoundPrice(taxValue); } taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } if (subTotalWithDiscount < decimal.Zero) { subTotalWithDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithDiscount = RoundingHelper.RoundPrice(subTotalWithDiscount); } }
/// <summary> /// Create shipment packages (requests) from shopping cart /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="shippingAddress">Shipping address</param> /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param> /// <param name="shippingFromMultipleLocations">Value indicating whether shipping is done from multiple locations (warehouses)</param> /// <returns>Shipment packages (requests)</returns> public virtual IList<GetShippingOptionRequest> CreateShippingOptionRequests(IList<ShoppingCartItem> cart, Address shippingAddress, int storeId, out bool shippingFromMultipleLocations) { //if we always ship from the default shipping origin, then there's only one request //if we ship from warehouses ("ShippingSettings.UseWarehouseLocation" enabled), //then there could be several requests //key - warehouse identifier (0 - default shipping origin) //value - request var requests = new Dictionary<int, GetShippingOptionRequest>(); //a list of requests with products which should be shipped separately var separateRequests = new List<GetShippingOptionRequest>(); foreach (var sci in cart) { if (!sci.IsShipEnabled) continue; var product = sci.Product; //warehouses Warehouse warehouse = null; if (_shippingSettings.UseWarehouseLocation) { if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && product.UseMultipleWarehouses) { var allWarehouses = new List<Warehouse>(); //multiple warehouses supported foreach (var pwi in product.ProductWarehouseInventory) { //TODO validate stock quantity when backorder is not allowed? var tmpWarehouse = GetWarehouseById(pwi.WarehouseId); if (tmpWarehouse != null) allWarehouses.Add(tmpWarehouse); } warehouse = GetNearestWarehouse(shippingAddress, allWarehouses); } else { //multiple warehouses are not supported warehouse = GetWarehouseById(product.WarehouseId); } } int warehouseId = warehouse != null ? warehouse.Id : 0; if (requests.ContainsKey(warehouseId) && !product.ShipSeparately) { //add item to existing request requests[warehouseId].Items.Add(new GetShippingOptionRequest.PackageItem(sci)); } else { //create a new request var request = new GetShippingOptionRequest(); //store request.StoreId = storeId; //add item request.Items.Add(new GetShippingOptionRequest.PackageItem(sci)); //customer request.Customer = cart.GetCustomer(); //ship to request.ShippingAddress = shippingAddress; //ship from Address originAddress = null; if (warehouse != null) { //warehouse address originAddress = _addressService.GetAddressById(warehouse.AddressId); request.WarehouseFrom = warehouse; } if (originAddress == null) { //no warehouse address. in this case use the default shipping origin originAddress = _addressService.GetAddressById(_shippingSettings.ShippingOriginAddressId); } if (originAddress != null) { request.CountryFrom = originAddress.Country; request.StateProvinceFrom = originAddress.StateProvince; request.ZipPostalCodeFrom = originAddress.ZipPostalCode; request.CityFrom = originAddress.City; request.AddressFrom = originAddress.Address1; } if (product.ShipSeparately) { //ship separately separateRequests.Add(request); } else { //usual request requests.Add(warehouseId, request); } } } //multiple locations? //currently we just compare warehouses //but we should also consider cases when several warehouses are located in the same address shippingFromMultipleLocations = requests.Select(x => x.Key).Distinct().Count() > 1; var result = requests.Values.ToList(); result.AddRange(separateRequests); return result; }
/// <summary> /// Update subscription totals /// </summary> /// <param name="updateSubscriptionParameters">Parameters for the updating subscription</param> /// <param name="restoredCart">Shopping cart</param> public virtual void UpdateSubscriptionTotals(UpdateSubscriptionParameters updateSubscriptionParameters, IList <ShoppingCartItem> restoredCart) { var updatedSubscription = updateSubscriptionParameters.UpdatedSubscription; var updatedSubscriptionItem = updateSubscriptionParameters.UpdatedSubscriptionItem; //get the customer var customer = restoredCart.GetCustomer(); #region Sub total var subTotalExclTax = decimal.Zero; var subTotalInclTax = decimal.Zero; var subTotalTaxRates = new SortedDictionary <decimal, decimal>(); foreach (var shoppingCartItem in restoredCart) { var itemSubTotalExclTax = decimal.Zero; var itemSubTotalInclTax = decimal.Zero; var taxRate = decimal.Zero; //calculate subtotal for the updated subscription item if (shoppingCartItem.Id == updatedSubscriptionItem.Id) { //update subscription item updatedSubscriptionItem.UnitPriceExclTax = updateSubscriptionParameters.PriceExclTax; updatedSubscriptionItem.UnitPriceInclTax = updateSubscriptionParameters.PriceInclTax; updatedSubscriptionItem.DiscountAmountExclTax = updateSubscriptionParameters.DiscountAmountExclTax; updatedSubscriptionItem.DiscountAmountInclTax = updateSubscriptionParameters.DiscountAmountInclTax; updatedSubscriptionItem.PriceExclTax = itemSubTotalExclTax = updateSubscriptionParameters.SubTotalExclTax; updatedSubscriptionItem.PriceInclTax = itemSubTotalInclTax = updateSubscriptionParameters.SubTotalInclTax; updatedSubscriptionItem.Quantity = shoppingCartItem.Quantity; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } else { //get the already calculated subtotal from the subscription item itemSubTotalExclTax = updatedSubscription.SubscriptionItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceExclTax; itemSubTotalInclTax = updatedSubscription.SubscriptionItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceInclTax; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } subTotalExclTax += itemSubTotalExclTax; subTotalInclTax += itemSubTotalInclTax; //tax rates var itemTaxValue = itemSubTotalInclTax - itemSubTotalExclTax; if (taxRate > decimal.Zero && itemTaxValue > decimal.Zero) { if (!subTotalTaxRates.ContainsKey(taxRate)) { subTotalTaxRates.Add(taxRate, itemTaxValue); } else { subTotalTaxRates[taxRate] = subTotalTaxRates[taxRate] + itemTaxValue; } } } if (subTotalExclTax < decimal.Zero) { subTotalExclTax = decimal.Zero; } if (subTotalInclTax < decimal.Zero) { subTotalInclTax = decimal.Zero; } //We calculate discount amount on subscription subtotal excl tax (discount first) //calculate discount amount ('Applied to subscription subtotal' discount) //add tax for shopping items var tempTaxRates = new Dictionary <decimal, decimal>(subTotalTaxRates); foreach (var kvp in tempTaxRates) { if (kvp.Value != decimal.Zero && subTotalExclTax > decimal.Zero) { subTotalTaxRates[kvp.Key] = kvp.Value; } } //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalExclTax = RoundingHelper.RoundPrice(subTotalExclTax); subTotalInclTax = RoundingHelper.RoundPrice(subTotalInclTax); } updatedSubscription.SubscriptionSubtotalExclTax = subTotalExclTax; updatedSubscription.SubscriptionSubtotalInclTax = subTotalInclTax; #endregion #region Tax rates var taxRates = new SortedDictionary <decimal, decimal>(); //subscription subtotal taxes var subTotalTax = decimal.Zero; foreach (var kvp in subTotalTaxRates) { subTotalTax += kvp.Value; if (kvp.Key > decimal.Zero && kvp.Value > decimal.Zero) { if (!taxRates.ContainsKey(kvp.Key)) { taxRates.Add(kvp.Key, kvp.Value); } else { taxRates[kvp.Key] = taxRates[kvp.Key] + kvp.Value; } } } //payment method additional fee tax var paymentMethodAdditionalFeeTax = decimal.Zero; if (_taxSettings.PaymentMethodAdditionalFeeIsTaxable) { paymentMethodAdditionalFeeTax = updatedSubscription.PaymentMethodAdditionalFeeInclTax - updatedSubscription.PaymentMethodAdditionalFeeExclTax; if (paymentMethodAdditionalFeeTax < decimal.Zero) { paymentMethodAdditionalFeeTax = decimal.Zero; } if (updatedSubscription.PaymentMethodAdditionalFeeExclTax > decimal.Zero) { var paymentTaxRate = Math.Round(100 * paymentMethodAdditionalFeeTax / updatedSubscription.PaymentMethodAdditionalFeeExclTax, 3); if (paymentTaxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(paymentTaxRate)) { taxRates.Add(paymentTaxRate, paymentMethodAdditionalFeeTax); } else { taxRates[paymentTaxRate] = taxRates[paymentTaxRate] + paymentMethodAdditionalFeeTax; } } } } //add at least one tax rate (0%) if (!taxRates.Any()) { taxRates.Add(decimal.Zero, decimal.Zero); } //summarize taxes var taxTotal = subTotalTax + paymentMethodAdditionalFeeTax; if (taxTotal < decimal.Zero) { taxTotal = decimal.Zero; } //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxTotal = RoundingHelper.RoundPrice(taxTotal); } updatedSubscription.SubscriptionTax = taxTotal; updatedSubscription.TaxRates = taxRates.Aggregate(string.Empty, (current, next) => string.Format("{0}{1}:{2}; ", current, next.Key.ToString(CultureInfo.InvariantCulture), next.Value.ToString(CultureInfo.InvariantCulture))); #endregion #region Total var total = (subTotalExclTax) + updatedSubscription.PaymentMethodAdditionalFeeExclTax + taxTotal; //reward points var rewardPointsOfSubscription = _rewardPointService.GetRewardPointsHistory(customer.Id, true).FirstOrDefault(history => history.UsedWithSubscription == updatedSubscription); if (rewardPointsOfSubscription != null) { var rewardPoints = -rewardPointsOfSubscription.Points; var rewardPointsAmount = ConvertRewardPointsToAmount(rewardPoints); if (total < rewardPointsAmount) { rewardPoints = ConvertAmountToRewardPoints(total); rewardPointsAmount = total; } if (total > decimal.Zero) { total -= rewardPointsAmount; } //uncomment here for the return unused reward points if new subscription total less redeemed reward points amount //if (rewardPoints < -rewardPointsOfSubscription.Points) // _rewardPointService.AddRewardPointsHistoryEntry(customer, -rewardPointsOfSubscription.Points - rewardPoints, _storeContext.CurrentStore.Id, "Return unused reward points"); if (rewardPointsAmount != rewardPointsOfSubscription.UsedAmount) { rewardPointsOfSubscription.UsedAmount = rewardPointsAmount; rewardPointsOfSubscription.Points = -rewardPoints; _rewardPointService.UpdateRewardPointsHistoryEntry(rewardPointsOfSubscription); } } //rounding if (total < decimal.Zero) { total = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { total = RoundingHelper.RoundPrice(total); } #endregion }
public virtual async Task <(Money Amount, TaxRatesDictionary taxRates)> GetTaxTotalAsync(IList <OrganizedShoppingCartItem> cart, bool includePaymentAdditionalFee = true) { Guard.NotNull(cart, nameof(cart)); var customer = cart.GetCustomer(); var taxRates = new TaxRatesDictionary(); var taxTotal = new Money(_primaryCurrency); var subTotalTax = new Money(_primaryCurrency); var shippingTax = new Money(_primaryCurrency); var paymentFeeTax = new Money(_primaryCurrency); //// (VATFIX) if (await _taxService.IsVatExemptAsync(customer, null)) { taxRates.Add(decimal.Zero, decimal.Zero); return(taxTotal, taxRates); } //// (VATFIX) // Order subtotal (cart items + checkout attributes). var subTotal = await GetShoppingCartSubTotalAsync(cart, false); foreach (var pair in subTotal.TaxRates) { subTotalTax += pair.Value; taxRates.Add(pair.Key, pair.Value); } // Shipping tax amount. if (_taxSettings.ShippingIsTaxable && !await IsFreeShippingAsync(cart)) { var(shippingTotal, _) = await GetAdjustedShippingTotalAsync(cart); if (shippingTotal.HasValue) { shippingTotal = _primaryCurrency.AsMoney(shippingTotal.Value.Amount, true, true); await PrepareAuxiliaryServicesTaxingInfosAsync(cart); // Commented out because requires several plugins to be updated and migration of Order.OrderShippingTaxRate and Order.PaymentMethodAdditionalFeeTaxRate. //if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.ProRata) //{ // // Calculate proRataShipping: get product weightings for cart and multiply them with the shipping amount. // foreach (var item in cart) // { // var proRataShipping = shippingTotal.Value * GetTaxingInfo(item).ProRataWeighting; // shippingTax += GetShippingTaxAmount(proRataShipping, customer, item.Item.Product.TaxCategoryId, taxRates); // } //} //else //{ var taxCategoryId = GetTaxCategoryId(cart, _taxSettings.ShippingTaxClassId); var(shippingExclTax, _) = await _taxService.GetShippingPriceAsync(shippingTotal.Value, false, taxCategoryId, customer); var(shippingInclTax, taxRate) = await _taxService.GetShippingPriceAsync(shippingTotal.Value, true, taxCategoryId, customer); var tmpShippingTax = Math.Max(shippingInclTax.Amount - shippingExclTax.Amount, decimal.Zero); taxRates.Add(taxRate, tmpShippingTax); shippingTax = _primaryCurrency.AsMoney(tmpShippingTax); } } // Payment fee tax amount. if (includePaymentAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable && customer != null) { var provider = _providerManager.GetProvider <IPaymentMethod>(customer.GenericAttributes.SelectedPaymentMethod); if (provider != null) { var paymentFee = await provider.Value.GetAdditionalHandlingFeeAsync(cart); paymentFee = _primaryCurrency.AsMoney(paymentFee.Amount); await PrepareAuxiliaryServicesTaxingInfosAsync(cart); // Commented out because requires several plugins to be updated and migration of Order.OrderShippingTaxRate and Order.PaymentMethodAdditionalFeeTaxRate. //if (_taxSettings.AuxiliaryServicesTaxingType == AuxiliaryServicesTaxType.ProRata) //{ // // Calculate proRataShipping: get product weightings for cart and multiply them with the shipping amount. // foreach (var item in cart) // { // var proRataPaymentFees = paymentFee * GetTaxingInfo(item).ProRataWeighting; // paymentFeeTax += GetPaymentFeeTaxAmount(proRataPaymentFees, customer, item.Item.Product.TaxCategoryId, taxRates); // } //} //else //{ var taxCategoryId = GetTaxCategoryId(cart, _taxSettings.PaymentMethodAdditionalFeeTaxClassId); var(paymentFeeExclTax, _) = await _taxService.GetPaymentMethodAdditionalFeeAsync(paymentFee, false, taxCategoryId, customer); var(paymentFeeInclTax, taxRate) = await _taxService.GetPaymentMethodAdditionalFeeAsync(paymentFee, true, taxCategoryId, customer); // Can be less zero (code differs)! paymentFeeTax = paymentFeeInclTax - paymentFeeExclTax; if (taxRate > decimal.Zero && paymentFeeTax != decimal.Zero) { if (taxRates.ContainsKey(taxRate)) { taxRates[taxRate] = taxRates[taxRate] + paymentFeeTax.Amount; } else { taxRates.Add(taxRate, paymentFeeTax.Amount); } } } } // Add at least one tax rate (0%). if (!taxRates.Any()) { taxRates.Add(decimal.Zero, decimal.Zero); } taxTotal = _primaryCurrency.AsMoney(subTotalTax.Amount + shippingTax.Amount + paymentFeeTax.Amount, true, true); return(taxTotal, taxRates); }
/// <summary> /// Gets tax /// </summary> /// <param name="cart">Shopping cart</param> /// <param name="taxRates">Tax rates</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating tax</param> /// <returns>Tax total</returns> public virtual decimal GetTaxTotal(IList <ShoppingCartItem> cart, out SortedDictionary <decimal, decimal> taxRates, bool usePaymentMethodAdditionalFee = true) { if (cart == null) { throw new ArgumentNullException("cart"); } taxRates = new SortedDictionary <decimal, decimal>(); var customer = cart.GetCustomer(); string paymentMethodSystemName = ""; if (customer != null) { paymentMethodSystemName = customer.GetAttribute <string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //subscription sub total (items + checkout attributes) decimal subTotalTaxTotal = decimal.Zero; decimal subscriptionSubTotalDiscountAmount; decimal subTotalWithoutDiscountBase; decimal subTotalWithDiscountBase; SortedDictionary <decimal, decimal> subscriptionSubTotalTaxRates; GetShoppingCartSubTotal(cart, false, out subscriptionSubTotalDiscountAmount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase, out subscriptionSubTotalTaxRates); foreach (KeyValuePair <decimal, decimal> kvp in subscriptionSubTotalTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; subTotalTaxTotal += taxValue; if (taxRate > decimal.Zero && taxValue > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, taxValue); } else { taxRates[taxRate] = taxRates[taxRate] + taxValue; } } } //payment method additional fee decimal paymentMethodAdditionalFeeTax = decimal.Zero; if (usePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable) { decimal taxRate; decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); decimal paymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer, out taxRate); decimal paymentMethodAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer, out taxRate); paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax; //ensure that tax is equal or greater than zero if (paymentMethodAdditionalFeeTax < decimal.Zero) { paymentMethodAdditionalFeeTax = decimal.Zero; } //tax rates if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, paymentMethodAdditionalFeeTax); } else { taxRates[taxRate] = taxRates[taxRate] + paymentMethodAdditionalFeeTax; } } } //add at least one tax rate (0%) if (!taxRates.Any()) { taxRates.Add(decimal.Zero, decimal.Zero); } //summarize taxes decimal taxTotal = subTotalTaxTotal + paymentMethodAdditionalFeeTax; //ensure that tax is equal or greater than zero if (taxTotal < decimal.Zero) { taxTotal = decimal.Zero; } //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxTotal = RoundingHelper.RoundPrice(taxTotal); } return(taxTotal); }
public virtual async Task <(Money Amount, Discount AppliedDiscount)> AdjustShippingRateAsync( IList <OrganizedShoppingCartItem> cart, Money shippingRate, ShippingOption shippingOption, IList <ShippingMethod> shippingMethods) { Guard.NotNull(cart, nameof(cart)); Guard.NotNull(shippingRate, nameof(shippingRate)); Guard.NotNull(shippingRate.Currency, nameof(shippingRate.Currency)); if (await IsFreeShippingAsync(cart)) { return(new(), null); } var customer = cart.GetCustomer(); var ignoreAdditionalShippingCharge = false; var bundlePerItemShipping = new Money(_primaryCurrency); var adjustedRate = new Money(_primaryCurrency); foreach (var cartItem in cart) { var item = cartItem.Item; if (item.Product != null && item.Product.ProductType == ProductType.BundledProduct && item.Product.BundlePerItemShipping) { foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.IsShippingEnabled && !x.Item.IsFreeShipping)) { bundlePerItemShipping += shippingRate; } } else if (adjustedRate == decimal.Zero) { adjustedRate = shippingRate; } } adjustedRate += bundlePerItemShipping; if (shippingOption != null && shippingMethods != null) { var shippingMethod = shippingMethods.FirstOrDefault(x => x.Id == shippingOption.ShippingMethodId); if (shippingMethod != null) { ignoreAdditionalShippingCharge = shippingMethod.IgnoreCharges; } } // Additional shipping charges. if (!ignoreAdditionalShippingCharge) { var additionalShippingCharge = await GetShoppingCartAdditionalShippingChargeAsync(cart); adjustedRate += additionalShippingCharge; } // Discount. var(discountAmount, discount) = await this.GetShippingDiscountAsync(adjustedRate, customer); var amount = _primaryCurrency.AsMoney(adjustedRate.Amount - discountAmount.Amount, true, true); return(amount, discount); }
/// <summary> /// Gets shopping cart total /// </summary> /// <param name="cart">Cart</param> /// <param name="appliedGiftCards">Applied gift cards</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscounts">Applied discounts</param> /// <param name="redeemedRewardPoints">Reward points to redeem</param> /// <param name="redeemedRewardPointsAmount">Reward points amount in primary store currency to redeem</param> /// <param name="useRewardPoints">A value indicating reward points should be used; null to detect current choice of the customer</param> /// <param name="usePaymentMethodAdditionalFee">A value indicating whether we should use payment method additional fee when calculating subscription total</param> /// <returns>Shopping cart total;Null if shopping cart total couldn't be calculated now</returns> public virtual decimal?GetShoppingCartTotal(IList <ShoppingCartItem> cart, out decimal discountAmount, out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount, bool?useRewardPoints = null, bool usePaymentMethodAdditionalFee = true) { redeemedRewardPoints = 0; redeemedRewardPointsAmount = decimal.Zero; var customer = cart.GetCustomer(); string paymentMethodSystemName = ""; if (customer != null) { paymentMethodSystemName = customer.GetAttribute <string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //subtotal without tax decimal subscriptionSubTotalDiscountAmount; decimal subTotalWithoutDiscountBase; decimal subTotalWithDiscountBase; GetShoppingCartSubTotal(cart, false, out subscriptionSubTotalDiscountAmount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); //subtotal with discount decimal subtotalBase = subTotalWithDiscountBase; //payment method additional fee without tax decimal paymentMethodAdditionalFeeWithoutTax = decimal.Zero; if (usePaymentMethodAdditionalFee && !String.IsNullOrEmpty(paymentMethodSystemName)) { decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); paymentMethodAdditionalFeeWithoutTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer); } //tax decimal shoppingCartTax = GetTaxTotal(cart, usePaymentMethodAdditionalFee); //subscription total decimal resultTemp = decimal.Zero; resultTemp += subtotalBase; resultTemp += paymentMethodAdditionalFeeWithoutTax; resultTemp += shoppingCartTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } #region Subscription total discount discountAmount = GetSubscriptionTotalDiscount(customer, resultTemp); //sub totals with discount if (resultTemp < discountAmount) { discountAmount = resultTemp; } //reduce subtotal resultTemp -= discountAmount; if (resultTemp < decimal.Zero) { resultTemp = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } #endregion if (resultTemp < decimal.Zero) { resultTemp = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { resultTemp = RoundingHelper.RoundPrice(resultTemp); } decimal subscriptionTotal = resultTemp; #region Reward points if (_rewardPointsSettings.Enabled) { if (!useRewardPoints.HasValue) { useRewardPoints = customer.GetAttribute <bool>(SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, _genericAttributeService, _storeContext.CurrentStore.Id); } if (useRewardPoints.Value) { int rewardPointsBalance = _rewardPointService.GetRewardPointsBalance(customer.Id, _storeContext.CurrentStore.Id); if (CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance)) { decimal rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); if (subscriptionTotal > decimal.Zero) { if (subscriptionTotal > rewardPointsBalanceAmount) { redeemedRewardPoints = rewardPointsBalance; redeemedRewardPointsAmount = rewardPointsBalanceAmount; } else { redeemedRewardPointsAmount = subscriptionTotal; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } } } } #endregion subscriptionTotal = subscriptionTotal - redeemedRewardPointsAmount; if (_shoppingCartSettings.RoundPricesDuringCalculation) { subscriptionTotal = RoundingHelper.RoundPrice(subscriptionTotal); } return(subscriptionTotal); }
public virtual async Task <ShoppingCartTotal> GetShoppingCartTotalAsync( IList <OrganizedShoppingCartItem> cart, bool includeRewardPoints = true, bool includePaymentAdditionalFee = true, bool includeCreditBalance = true) { Guard.NotNull(cart, nameof(cart)); var store = _storeContext.CurrentStore; var customer = cart.GetCustomer(); var paymentMethodSystemName = customer != null ? customer.GenericAttributes.SelectedPaymentMethod : string.Empty; var subTotal = await GetShoppingCartSubTotalAsync(cart, false); // Subtotal with discount. var subtotalBase = subTotal.SubTotalWithDiscount; // Shipping without tax. Money?shoppingCartShipping = await GetShoppingCartShippingTotalAsync(cart, false); // Payment method additional fee without tax. var paymentFeeWithoutTax = new Money(_primaryCurrency); if (includePaymentAdditionalFee && paymentMethodSystemName.HasValue()) { var provider = _providerManager.GetProvider <IPaymentMethod>(paymentMethodSystemName); var paymentFee = await provider?.Value?.GetAdditionalHandlingFeeAsync(cart); (paymentFeeWithoutTax, _) = await _taxService.GetPaymentMethodAdditionalFeeAsync(paymentFee, false, customer : customer); } // Tax. var(shoppingCartTax, _) = await GetTaxTotalAsync(cart, includePaymentAdditionalFee); // Order total. var resultTemp = subtotalBase; if (shoppingCartShipping.HasValue) { resultTemp += shoppingCartShipping.Value; } resultTemp += paymentFeeWithoutTax; resultTemp += shoppingCartTax; // Round: resultTemp = _primaryCurrency.AsMoney(resultTemp.Amount); // Order total discount. var(discountAmount, appliedDiscount) = await GetDiscountAmountAsync(resultTemp, DiscountType.AssignedToOrderTotal, customer); // Subtotal with discount. if (resultTemp < discountAmount) { discountAmount = resultTemp; } // Reduce subtotal. resultTemp = _primaryCurrency.AsMoney((resultTemp - discountAmount).Amount, true, true); // Applied gift cards. var appliedGiftCards = new List <AppliedGiftCard>(); if (!cart.IncludesMatchingItems(x => x.IsRecurring)) { // TODO: (ms) (core) Gift card usage in OrderCalculationService needs to be tested extensively as the gift card code has been fundamentally changed. var giftCards = await _giftCardService.GetValidGiftCardsAsync(store.Id, customer); foreach (var gc in giftCards) { if (resultTemp > decimal.Zero) { var usableAmount = resultTemp > gc.UsableAmount ? gc.UsableAmount : resultTemp; // Reduce subtotal. resultTemp -= usableAmount; appliedGiftCards.Add(new() { GiftCard = gc.GiftCard, UsableAmount = usableAmount }); } } } // Reward points. var redeemedRewardPoints = 0; var redeemedRewardPointsAmount = new Money(_primaryCurrency); if (_rewardPointsSettings.Enabled && includeRewardPoints && resultTemp > decimal.Zero && customer != null && customer.GenericAttributes.UseRewardPointsDuringCheckout) { var rewardPointsBalance = customer.GetRewardPointsBalance(); var rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); if (resultTemp > rewardPointsBalanceAmount) { redeemedRewardPointsAmount = rewardPointsBalanceAmount; redeemedRewardPoints = rewardPointsBalance; } else { redeemedRewardPointsAmount = resultTemp; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } resultTemp = _primaryCurrency.AsMoney(resultTemp.Amount, true, true); // Return null if we have errors: Money?orderTotal = shoppingCartShipping.HasValue ? resultTemp : null; var orderTotalConverted = orderTotal; var appliedCreditBalance = new Money(_primaryCurrency); var toNearestRounding = new Money(_primaryCurrency); var toNearestRoundingConverted = new Money(_primaryCurrency); if (orderTotal.HasValue) { orderTotal = orderTotal.Value - redeemedRewardPointsAmount; // Credit balance. if (includeCreditBalance && customer != null && orderTotal > decimal.Zero) { var creditBalance = _primaryCurrency.AsMoney(customer.GenericAttributes.UseCreditBalanceDuringCheckout, false); if (creditBalance > decimal.Zero) { if (creditBalance > orderTotal) { // Normalize used amount. appliedCreditBalance = orderTotal.Value; customer.GenericAttributes.UseCreditBalanceDuringCheckout = orderTotal.Value.Amount; await _db.SaveChangesAsync(); } else { appliedCreditBalance = creditBalance; } } } orderTotal = _primaryCurrency.AsMoney(orderTotal.Value.Amount - appliedCreditBalance.Amount); orderTotalConverted = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotal.Value, store); // Round order total to nearest (cash rounding). if (_primaryCurrency.RoundOrderTotalEnabled && paymentMethodSystemName.HasValue()) { var paymentMethod = await _db.PaymentMethods.AsNoTracking().FirstOrDefaultAsync(x => x.PaymentMethodSystemName == paymentMethodSystemName); if (paymentMethod?.RoundOrderTotalEnabled ?? false) { orderTotal = _primaryCurrency.RoundToNearest(orderTotal.Value, out toNearestRounding); orderTotalConverted = _primaryCurrency.RoundToNearest(orderTotalConverted.Value, out toNearestRoundingConverted); } } } var result = new ShoppingCartTotal(orderTotal) { ToNearestRounding = toNearestRounding, DiscountAmount = discountAmount, AppliedDiscount = appliedDiscount, RedeemedRewardPoints = redeemedRewardPoints, RedeemedRewardPointsAmount = redeemedRewardPointsAmount, CreditBalance = appliedCreditBalance, AppliedGiftCards = appliedGiftCards, ConvertedAmount = new ShoppingCartTotal.ConvertedAmounts { Total = orderTotalConverted, ToNearestRounding = toNearestRoundingConverted } }; return(result); }
public PaymentDetailsType[] GetPaymentDetails(IList <ShoppingCartItem> cart) { var currencyCode = _payPalCurrencyCodeParser.GetCurrencyCodeType(_workContext.WorkingCurrency); decimal orderTotalDiscountAmount; List <DiscountForCaching> appliedDiscounts; int redeemedRewardPoints; decimal redeemedRewardPointsAmount; List <AppliedGiftCard> appliedGiftCards; var orderTotalWithDiscount = _payPalCartItemService.GetCartTotal(cart, out orderTotalDiscountAmount, out appliedDiscounts, out redeemedRewardPoints, out redeemedRewardPointsAmount, out appliedGiftCards); decimal subTotalWithDiscount; decimal subTotalWithoutDiscount; List <DiscountForCaching> subTotalAppliedDiscounts; decimal subTotalDiscountAmount; var itemTotalWithDiscount = _payPalCartItemService.GetCartItemTotal(cart, out subTotalDiscountAmount, out subTotalAppliedDiscounts, out subTotalWithoutDiscount, out subTotalWithDiscount); var giftCardsAmount = appliedGiftCards.Sum(x => x.AmountCanBeUsed); itemTotalWithDiscount = itemTotalWithDiscount - orderTotalDiscountAmount - giftCardsAmount; var taxTotal = _payPalCartItemService.GetTax(cart); var shippingTotal = _payPalCartItemService.GetShippingTotal(cart); var items = GetPaymentDetailsItems(cart); // checkout attributes var customer = cart.GetCustomer(); if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (caValues != null) { foreach (var caValue in caValues) { if (caValue.PriceAdjustment > 0) { var checkoutAttrItem = new PaymentDetailsItemType { Name = caValue.Name, Amount = caValue.PriceAdjustment.GetBasicAmountType(currencyCode), Quantity = "1" }; items.Add(checkoutAttrItem); } } } } if (orderTotalDiscountAmount > 0 || subTotalDiscountAmount > 0) { var discountItem = new PaymentDetailsItemType { Name = "Discount", Amount = (-orderTotalDiscountAmount + -subTotalDiscountAmount).GetBasicAmountType( currencyCode), Quantity = "1" }; items.Add(discountItem); } foreach (var appliedGiftCard in appliedGiftCards) { var giftCardItem = new PaymentDetailsItemType { Name = string.Format("Gift Card ({0})", appliedGiftCard.GiftCard.GiftCardCouponCode), Amount = (-appliedGiftCard.AmountCanBeUsed).GetBasicAmountType(currencyCode), Quantity = "1" }; items.Add(giftCardItem); } return(new[] { new PaymentDetailsType { OrderTotal = orderTotalWithDiscount.GetBasicAmountType(currencyCode), ItemTotal = itemTotalWithDiscount.GetBasicAmountType(currencyCode), TaxTotal = taxTotal.GetBasicAmountType(currencyCode), ShippingTotal = shippingTotal.GetBasicAmountType(currencyCode), PaymentDetailsItem = items.ToArray(), PaymentAction = _payPalExpressCheckoutPaymentSettings.PaymentAction, PaymentActionSpecified = true, ButtonSource = PayPalHelper.BnCode } }); }