{"record":{"id":"ca54c8ff428be954","repo":"nopSolutions/nopCommerce","slug":"shopping-cart-total-couldn-t-be-calculated-now","errorCode":null,"errorMessage":"Shopping cart total couldn't be calculated now","messagePattern":"Shopping cart total couldn't be calculated now","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"error","filePath":"src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs","lineNumber":557,"sourceCode":"    /// A task that represents the asynchronous operation\n    /// The task result contains the order amount with breakdown\n    /// </returns>\n    private async Task<OrderMoney> PrepareOrderMoneyAsync(CartDetails details, List<Item> items)\n    {\n        //in some rare cases we need an additional item to adjust the order total\n        //this can happen due to complex discounts or a large order and related to rounding in calculations\n        //PayPal uses two decimal places, while nopCommerce can use more complex types of rounding (configured for each currency separately) \n        var adjustmentName = await _localizationService.GetResourceAsync(\"Plugins.Payments.PayPalCommerce.Order.Adjustment.Name\");\n        var adjustmentDescription = await _localizationService.GetResourceAsync(\"Plugins.Payments.PayPalCommerce.Order.Adjustment.Description\");\n        if (items.FirstOrDefault(item => adjustmentName.Equals(item.Name) && adjustmentDescription.Equals(item.Description)) is Item adjustmentItem)\n            items.Remove(adjustmentItem);\n\n        var (total, _, _, _, _, _) = await _orderTotalCalculationService\n            .GetShoppingCartTotalAsync(details.Cart, usePaymentMethodAdditionalFee: false);\n        if (total is null)\n        {\n            if (details.Placement == ButtonPlacement.PaymentMethod)\n                throw new NopException(\"Shopping cart total couldn't be calculated now\");\n\n            //on product and cart pages the total is not yet calculated, so use subtotal here\n            var (_, _, subTotal, _, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(details.Cart, includingTax: false);\n            total = subTotal;\n        }\n        var orderTotal = PrepareMoney(total.Value, details.CurrencyCode);\n\n        var (shippingTotal, _, _) = await _orderTotalCalculationService\n            .GetShoppingCartShippingTotalAsync(details.Cart, includingTax: _taxSettings.ShippingPriceIncludesTax);\n        var orderShippingTotal = PrepareMoney(shippingTotal ?? decimal.Zero, details.CurrencyCode);\n\n        var (taxTotal, _) = await _orderTotalCalculationService.GetTaxTotalAsync(details.Cart, usePaymentMethodAdditionalFee: false);\n        var orderTaxTotal = PrepareMoney(taxTotal, details.CurrencyCode);\n\n        var itemAdjustment = decimal.Zero;\n        var itemTotal = items.Sum(item => ConvertMoney(item.UnitAmount) * int.Parse(item.Quantity));\n        var discountTotal = itemTotal + ConvertMoney(orderTaxTotal) + ConvertMoney(orderShippingTotal) - ConvertMoney(orderTotal);\n        if (discountTotal < decimal.Zero)","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs#L539-L575","documentation":"Thrown when GetShoppingCartTotalAsync returns null for the cart total during order preparation on the payment method page. This happens when nopCommerce's order total calculation cannot produce a final total, typically due to complex discount/tax/rounding configurations. On product and cart pages the code falls back to subtotal, but on the payment method page it throws.","triggerScenarios":"PreparePurchaseUnitAsync calls GetShoppingCartTotalAsync with usePaymentMethodAdditionalFee=false, the result total is null, and details.Placement == ButtonPlacement.PaymentMethod.","commonSituations":"Complex discount combinations (e.g., percentage + fixed discounts on the same order) that cause rounding conflicts between nopCommerce's currency-specific rounding and PayPal's two-decimal-place requirement; tax calculation configuration that produces unresolvable totals; gift card or store credit that drives the total calculation to an indeterminate state.","solutions":["Review active discount combinations for rounding conflicts; simplify or disable conflicting discount rules","Check currency rounding configuration in nopCommerce (Configuration > Currencies) to ensure consistent decimal places","Verify tax calculation settings do not produce null totals (Configuration > Tax Settings)","Test the cart total calculation independently via GetShoppingCartTotalAsync to identify which configuration causes the null result","If using custom discount or tax providers, verify their output is non-null for all cart combinations"],"exampleFix":"// before\nvar (total, _, _, _, _, _) = await _orderTotalCalculationService\n    .GetShoppingCartTotalAsync(details.Cart, usePaymentMethodAdditionalFee: false);\nif (total is null)\n    throw new NopException(\"Shopping cart total couldn't be calculated now\");\n\n// after\nvar (total, _, _, _, _, _) = await _orderTotalCalculationService\n    .GetShoppingCartTotalAsync(details.Cart, usePaymentMethodAdditionalFee: false);\nif (total is null)\n{\n    //log details for diagnosis\n    await _logger.InformationAsync($\"Cart total was null for customer {details.Customer.Id}, placement {details.Placement}\");\n    var (_, _, subTotal, _, _) = await _orderTotalCalculationService\n        .GetShoppingCartSubTotalAsync(details.Cart, includingTax: false);\n    total = subTotal;\n}","handlingStrategy":"fallback","validationCode":"// Pre-check cart total calculation independently\nvar (testTotal, _, _, _, _, _) = await _orderTotalCalculationService\n    .GetShoppingCartTotalAsync(cart, usePaymentMethodAdditionalFee: false);\nif (testTotal is null && placement == ButtonPlacement.PaymentMethod)\n{\n    //investigate discount/tax configuration before proceeding\n    _logger.Warning(\"Cart total returned null — check discount and tax configuration\");\n    return Error(\"Unable to calculate order total. Please review your discount and tax settings.\");\n}","typeGuard":null,"tryCatchPattern":"var (order, error) = await manager.CreateOrderAsync(settings, placement, paymentSource, cardId, saveCard);\nif (!string.IsNullOrEmpty(error))\n{\n    if (error.Contains(\"total couldn't be calculated\"))\n    {\n        //guide user to simplify cart or contact support\n        return View(\"CartTotalError\");\n    }\n}","preventionTips":["Audit discount combinations for rounding conflicts with PayPal's two-decimal-place format","Test cart total calculation with various discount and tax scenarios","Ensure currency decimal place configuration is consistent with payment processor requirements","Monitor logs for null cart total occurrences to catch configuration issues early"],"tags":["order-total","rounding","discounts","tax","paypal-commerce","nopcommerce","calculation"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}