public async Task <IViewComponentResult> InvokeAsync(bool isEditable = false) { var orderTotalsEvent = new RenderingOrderTotalsEvent(); await Services.EventPublisher.PublishAsync(orderTotalsEvent); var currency = Services.WorkContext.WorkingCurrency; var customer = orderTotalsEvent.Customer ?? Services.WorkContext.CurrentCustomer; var storeId = orderTotalsEvent.StoreId ?? Services.StoreContext.CurrentStore.Id; var cart = await _shoppingCartService.GetCartItemsAsync(customer, ShoppingCartType.ShoppingCart, storeId); var model = new OrderTotalsModel { IsEditable = isEditable }; if (!cart.Any()) { return(View(model)); } model.Weight = decimal.Zero; foreach (var cartItem in cart) { model.Weight += cartItem.Item.Product.Weight * cartItem.Item.Quantity; } var measureWeight = await _db.MeasureWeights.FindByIdAsync(_measureSettings.BaseWeightId, false); if (measureWeight != null) { model.WeightMeasureUnitName = measureWeight.GetLocalized(x => x.Name); } // SubTotal var cartSubTotal = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart); var subTotalConverted = _currencyService.ConvertFromPrimaryCurrency(cartSubTotal.SubtotalWithoutDiscount.Amount, currency); model.SubTotal = subTotalConverted; if (cartSubTotal.DiscountAmount > decimal.Zero) { var subTotalDiscountAmountConverted = _currencyService.ConvertFromPrimaryCurrency(cartSubTotal.DiscountAmount.Amount, currency); model.SubTotalDiscount = subTotalDiscountAmountConverted * -1; model.AllowRemovingSubTotalDiscount = cartSubTotal.AppliedDiscount != null && cartSubTotal.AppliedDiscount.RequiresCouponCode && cartSubTotal.AppliedDiscount.CouponCode.HasValue() && model.IsEditable; } // Shipping info // TODO: (ms) (core) Re-implement when any payment method has been implemented model.RequiresShipping = false;// cart.IsShippingRequired(); if (model.RequiresShipping) { var shippingTotal = await _orderCalculationService.GetShoppingCartShippingTotalAsync(cart); if (shippingTotal.ShippingTotal.HasValue) { var shippingTotalConverted = _currencyService.ConvertFromPrimaryCurrency(shippingTotal.ShippingTotal.Value.Amount, currency); model.Shipping = shippingTotalConverted.ToString(); // Selected shipping method var shippingOption = customer.GenericAttributes.SelectedShippingOption; if (shippingOption != null) { model.SelectedShippingMethod = shippingOption.Name; } } } // Payment method fee var paymentFee = await _orderCalculationService.GetShoppingCartPaymentFeeAsync(cart, customer.GenericAttributes.SelectedPaymentMethod); var paymentFeeTax = await _taxCalculator.CalculatePaymentFeeTaxAsync(paymentFee.Amount, customer : customer); if (paymentFeeTax.Price != 0m) { var convertedPaymentFeeTax = _currencyService.ConvertFromPrimaryCurrency(paymentFeeTax.Price, currency); model.PaymentMethodAdditionalFee = convertedPaymentFeeTax; } // Tax var displayTax = true; var displayTaxRates = true; if (_taxSettings.HideTaxInOrderSummary && Services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax) { displayTax = false; displayTaxRates = false; } else { (Money Price, TaxRatesDictionary TaxRates)cartTaxBase = (new Money(1.19m, currency), new TaxRatesDictionary()); //await _orderCalculationService.GetShoppingCartTaxTotalAsync(cart); var cartTax = _currencyService.ConvertFromPrimaryCurrency(cartTaxBase.Price.Amount, currency); if (cartTaxBase.Price == decimal.Zero && _taxSettings.HideZeroTax) { displayTax = false; displayTaxRates = false; } else { displayTaxRates = _taxSettings.DisplayTaxRates && cartTaxBase.TaxRates.Count > 0; displayTax = !displayTaxRates; model.Tax = cartTax.ToString(true); foreach (var taxRate in cartTaxBase.TaxRates) { var rate = _taxService.FormatTaxRate(taxRate.Key); var labelKey = "ShoppingCart.Totals.TaxRateLine" + (Services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "Incl" : "Excl"); model.TaxRates.Add(new OrderTotalsModel.TaxRate { Rate = rate, Value = _currencyService.ConvertFromPrimaryCurrency(taxRate.Value, currency), Label = _localizationService.GetResource(labelKey).FormatCurrent(rate) }); } } } model.DisplayTaxRates = displayTaxRates; model.DisplayTax = displayTax; model.DisplayWeight = _shoppingCartSettings.ShowWeight; model.ShowConfirmOrderLegalHint = _shoppingCartSettings.ShowConfirmOrderLegalHint; // Cart total // TODO: (ms) (core) Re-implement when any payment method has been implemented //var cartTotal = await _orderCalculationService.GetShoppingCartTotalAsync(cart); var cartTotal = new ShoppingCartTotal { Total = new(decimal.Zero, currency), ToNearestRounding = new(decimal.Zero, currency), DiscountAmount = new(15, currency), AppliedDiscount = (await _db.Discounts.FirstOrDefaultAsync()) ?? new(), RedeemedRewardPoints = 10, RedeemedRewardPointsAmount = new(10, currency), CreditBalance = new(decimal.Zero, currency), AppliedGiftCards = new() { new() { GiftCard = (await _db.GiftCards.Include(x => x.GiftCardUsageHistory).FirstOrDefaultAsync()) ?? new(), UsableAmount = new(50m, _currencyService.PrimaryCurrency) } }, ConvertedAmount = new ShoppingCartTotal.ConvertedAmounts { Total = new(decimal.Zero, currency), ToNearestRounding = new(decimal.Zero, currency) } }; if (cartTotal.ConvertedAmount.Total.HasValue) { model.OrderTotal = cartTotal.ConvertedAmount.Total.Value; if (cartTotal.ConvertedAmount.ToNearestRounding != decimal.Zero) { model.OrderTotalRounding = cartTotal.ConvertedAmount.ToNearestRounding; } } // Discount if (cartTotal.DiscountAmount > decimal.Zero) { var orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryCurrency(cartTotal.DiscountAmount.Amount, currency); model.OrderTotalDiscount = orderTotalDiscountAmount * -1; model.AllowRemovingOrderTotalDiscount = cartTotal.AppliedDiscount != null && cartTotal.AppliedDiscount.RequiresCouponCode && cartTotal.AppliedDiscount.CouponCode.HasValue() && model.IsEditable; } // Gift cards if (!cartTotal.AppliedGiftCards.IsNullOrEmpty()) { foreach (var appliedGiftCard in cartTotal.AppliedGiftCards) { if (appliedGiftCard?.GiftCard == null) { continue; } var gcModel = new OrderTotalsModel.GiftCard { Id = appliedGiftCard.GiftCard.Id, CouponCode = appliedGiftCard.GiftCard.GiftCardCouponCode, }; var amountCanBeUsed = _currencyService.ConvertFromPrimaryCurrency(appliedGiftCard.UsableAmount.Amount, currency); gcModel.Amount = amountCanBeUsed * -1; var remainingAmountBase = _giftCardService.GetRemainingAmount(appliedGiftCard.GiftCard) - appliedGiftCard.UsableAmount; var remainingAmount = _currencyService.ConvertFromPrimaryCurrency(remainingAmountBase.Amount, currency); gcModel.Remaining = remainingAmount; model.GiftCards.Add(gcModel); } } // Reward points if (cartTotal.RedeemedRewardPointsAmount > decimal.Zero) { var redeemedRewardPointsAmountInCustomerCurrency = _currencyService.ConvertFromPrimaryCurrency(cartTotal.RedeemedRewardPointsAmount.Amount, currency); model.RedeemedRewardPoints = cartTotal.RedeemedRewardPoints; model.RedeemedRewardPointsAmount = (redeemedRewardPointsAmountInCustomerCurrency * -1).ToString(true); } // Credit balance. if (cartTotal.CreditBalance > decimal.Zero) { var convertedCreditBalance = _currencyService.ConvertFromPrimaryCurrency(cartTotal.CreditBalance.Amount, currency); model.CreditBalance = (convertedCreditBalance * -1).ToString(true); } return(View(model)); }
public virtual async Task <ShoppingCartTotal> GetShoppingCartTotalAsync( IList <OrganizedShoppingCartItem> cart, bool includeRewardPoints = true, bool includePaymentFee = 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(_, subTotalWithDiscount, _, _, _) = await GetCartSubTotalAsync(cart, false); // Subtotal with discount. var subTotalBase = subTotalWithDiscount; // Shipping without tax. var(shoppingCartShipping, _, _) = await GetCartShippingTotalAsync(cart, false); // Payment method additional fee without tax. var paymentFeeWithoutTax = decimal.Zero; if (includePaymentFee && paymentMethodSystemName.HasValue()) { var paymentFee = await GetShoppingCartPaymentFeeAsync(cart, paymentMethodSystemName); if (paymentFee != decimal.Zero) { var paymentFeeExclTax = await _taxCalculator.CalculatePaymentFeeTaxAsync(paymentFee.Amount, false, customer : customer); paymentFeeWithoutTax = paymentFeeExclTax.Price; } } // Tax. var(shoppingCartTax, _) = await GetCartTaxTotalAsync(cart, includePaymentFee); // Order total. var resultTemp = subTotalBase; if (shoppingCartShipping.HasValue) { resultTemp += shoppingCartShipping.Value; } resultTemp = _workingCurrency.RoundIfEnabledFor(resultTemp + paymentFeeWithoutTax + shoppingCartTax); // Order total discount. var(discountAmount, appliedDiscount) = await GetDiscountAmountAsync(resultTemp, DiscountType.AssignedToOrderTotal, customer); // Subtotal with discount. if (resultTemp < discountAmount) { discountAmount = resultTemp; } // Reduce subtotal. resultTemp = _workingCurrency.RoundIfEnabledFor(Math.Max(resultTemp - discountAmount, decimal.Zero)); // 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.Amount ? gc.UsableAmount.Amount : resultTemp; // Reduce subtotal. resultTemp -= usableAmount; appliedGiftCards.Add(new() { GiftCard = gc.GiftCard, UsableAmount = new(usableAmount, _primaryCurrency) }); } } } // Reward points. var redeemedRewardPoints = 0; var redeemedRewardPointsAmount = decimal.Zero; if (_rewardPointsSettings.Enabled && includeRewardPoints && resultTemp > decimal.Zero && customer != null && customer.GenericAttributes.UseRewardPointsDuringCheckout) { var rewardPointsBalance = customer.GetRewardPointsBalance(); var rewardPointsBalanceAmount = ConvertRewardPointsToAmountCore(rewardPointsBalance); if (resultTemp > rewardPointsBalanceAmount) { redeemedRewardPointsAmount = rewardPointsBalanceAmount; redeemedRewardPoints = rewardPointsBalance; } else { redeemedRewardPointsAmount = resultTemp; redeemedRewardPoints = ConvertAmountToRewardPoints(redeemedRewardPointsAmount); } } resultTemp = _workingCurrency.RoundIfEnabledFor(Math.Max(resultTemp, decimal.Zero)); // Return null if we have errors: decimal?orderTotal = shoppingCartShipping.HasValue ? resultTemp : null; var orderTotalConverted = orderTotal; var appliedCreditBalance = decimal.Zero; var toNearestRounding = decimal.Zero; var toNearestRoundingConverted = decimal.Zero; if (orderTotal.HasValue) { orderTotal = orderTotal.Value - redeemedRewardPointsAmount; // Credit balance. if (includeCreditBalance && customer != null && orderTotal > decimal.Zero) { var creditBalance = customer.GenericAttributes.UseCreditBalanceDuringCheckout; if (creditBalance > decimal.Zero) { if (creditBalance > orderTotal) { // Normalize used amount. appliedCreditBalance = orderTotal.Value; customer.GenericAttributes.UseCreditBalanceDuringCheckout = orderTotal.Value; await _db.SaveChangesAsync(); } else { appliedCreditBalance = creditBalance; } } } orderTotal = _workingCurrency.RoundIfEnabledFor(orderTotal.Value - appliedCreditBalance); orderTotalConverted = _currencyService.ConvertToWorkingCurrency(orderTotal.Value).Amount; // Round order total to nearest (cash rounding). if (_workingCurrency.RoundOrderTotalEnabled && paymentMethodSystemName.HasValue()) { var paymentMethod = await _db.PaymentMethods.AsNoTracking().FirstOrDefaultAsync(x => x.PaymentMethodSystemName == paymentMethodSystemName); if (paymentMethod?.RoundOrderTotalEnabled ?? false) { orderTotal = _workingCurrency.RoundToNearest(orderTotal.Value, out toNearestRounding); orderTotalConverted = _workingCurrency.RoundToNearest(orderTotalConverted.Value, out toNearestRoundingConverted); } } } var result = new ShoppingCartTotal { Total = orderTotal.HasValue ? new(orderTotal.Value, _primaryCurrency) : null, ToNearestRounding = new(toNearestRounding, _primaryCurrency), DiscountAmount = new(discountAmount, _primaryCurrency), AppliedDiscount = appliedDiscount, RedeemedRewardPoints = redeemedRewardPoints, RedeemedRewardPointsAmount = new(redeemedRewardPointsAmount, _primaryCurrency), CreditBalance = new(appliedCreditBalance, _primaryCurrency), AppliedGiftCards = appliedGiftCards, ConvertedAmount = new ShoppingCartTotal.ConvertedAmounts { Total = orderTotalConverted.HasValue ? new(orderTotalConverted.Value, _workingCurrency) : null, ToNearestRounding = new(toNearestRoundingConverted, _workingCurrency) } }; return(result); }