Repository navigation
Pass an explicit context to pricing, tax and checkout calculations - #931
Merged
KrzysztofPajak merged 21 commits intoOct 16, 2026
Merged
Conversation
added 12 commits
October 16, 2026 16:00
The handlers cache the ACL-filtered result under keys shared by many customers. A query without a customer would authorize nothing and cache the empty list for all of them. Also pins DeleteCategory detaching its children and restores a negative assertion to any customer and store.
Every other amount in the order email is formatted in the currency the order was placed in; the tax rates used whatever currency the request that sent the email was working in, which for background sending is not the customer's.
added 9 commits
October 16, 2026 16:38
…or/business-explicit-context-pricing
…stomer for hidden records GetPersonalizedProductsQuery and GetSuggestedProductsQuery read the customer id and tags from Customer instead of separate fields that could disagree with it. The product mapping and child category lookups no longer read the customer or store when showHidden is set, so admin callers pass null. Methods that authorize through IAclService throw on a missing customer instead of returning nothing.
The admin cart and wishlist details, the customer edit page's cart tab and the attribute price adjustments priced another customer's items with the logged-in admin's groups, discounts and tax. They now use the customer whose cart it is and the store the item was added in.
ConvertLoyaltyPointsToAmount returns an amount in the primary store currency, but rounded it in the working currency, so a zero-decimal working currency rounded 4.95 USD to 5 before conversion. The currency parameter added for that rounding is dropped again; the amount is rounded in the primary store currency.
The cart, mini cart, order totals and payment method handlers priced their lines from the request but their totals from the ambient context. They now build one context from the request fields, which no longer needs the context accessor. GetPaymentMethod carries the tax display type like the other cart requests. ShoppingCartTotalAmountValidatorRecord and ValidateMinShoppingCartSubtotalAmountCommand carried a customer and a currency next to a context holding the same; they now read both from the context.
The catalog read services took a customer, a store id and a showHidden flag whose meaning depended on each other: the customer had to be null exactly when hidden records were asked for. CatalogAccess.For(customer, storeId) and CatalogAccess.IncludingHidden(storeId) make that choice one argument. The store limitation now applies whenever a store id is set, so the back office passes IncludingHidden() where it ignored the store before. The storefront builds its access from the request with IContextAccessor.CatalogAccess().
…xt-catalog' into refactor/business-explicit-context-pricing # Conflicts: # src/Web/Grand.Web/Features/Handlers/Products/GetProductDetailsPageHandler.cs
…explicit-context-pricing
KrzysztofPajak
changed the base branch from
refactor/business-explicit-context-catalog
to
develop
October 16, 2026 19:34
This was referenced Oct 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type: feature
Issue
PricingService,TaxService,PriceFormatter,ShoppingCartSubTotalServiceandOrderCalculationServiceread the customer, store, working currency and tax display fromWorkContext/StoreContext. Prices, taxes and cart totals therefore depended on who called. Outside a request (background messages, scheduled tasks, the API module) the values were wrong or missing. Follows #930 (M1 PR 1, Catalog read paths); this branch is stacked on it.Solution
CalculationContext(Customer, Store, Currency, TaxDisplayType)record inGrand.Business.Core.Utilities.Checkout. Web builds it with_contextAccessor.CalculationContext()(Grand.Web.Common.Extensions).IOrderCalculationServiceandIShoppingCartSubTotalServicetake the context as the second parameter of every calculation method.ConvertLoyaltyPointsToAmounttakes the currency.ITaxService: the overloads that read the tax display, customer or store are removed. Callers use the overloads withincludingTax, customer, store.LoadActiveTaxProvider(customer, storeId).IPricingService:GetUnitPrice(ShoppingCartItem, Product, Customer, Store, Currency, includeDiscounts),GetSubTotal(…, customer, store, currency, …)andGetProductAttributeValuePriceAdjustment(value, customer, store, currency).IPriceFormatter.FormatPrice(double)is removed. Callers pass the currency.IContextAccessor. Web callers pass exactly what the services used to read. Web handlers whose request has no tax display getIContextAccessor.PlaceOrderCommandHandlerandShoppingCartValidator(next PR) build the context from their own ambient values, marked TODO.Two deliberate fixes:
GetUnitPrice(product, customer, store, currency, …)they now use the given customer, store and currency instead of the ambient ones. For Web callers the values are the same. For the discount rule's spent-amount query, which prices in the primary currency, attribute adjustments are no longer converted into the working currency.Not in this PR:
ProductAttributeFormatter, which also needs the working language and the request host (follow-up PR).Breaking changes
ValidateMinShoppingCartSubtotalAmountCommand.Contextis required: the handler throws without it.ShoppingCartTotalAmountValidatorRecordhas an extraContextfield.IContextAccessor. Several Web handlers, AdminShoppingCartController, andGetMerchandiseReturns(newCurrencyproperty) changed too.Testing
dotnet build GrandNode.slnxdotnet test GrandNode.slnx: green. Customers and Marketing fail only in the parallel run and pass when run alone.CalculationContextExtensionsTestsGetOrderTokensCommandHandlerTests.Handle_FormatsTaxRatesInTheOrderCurrencyTaxServiceTests.LoadActiveTaxProvider_FallsBackToProvidersOfGivenCustomerAndStorePriceServiceTests.GetSubTotal_PricesTheItemForTheGivenCustomerStoreAndCurrencyPriceServiceTests.GetProductAttributeValuePriceAdjustment_ConvertsToTheGivenCurrency(pins the adjustment method itself)OrderCalculationServiceTests.IsFreeShipping_UsesTheCustomerOfTheContextOrderCalculationServiceTests.GetShoppingCartSubTotal_PricesItemsForTheContextCustomerStoreAndCurrencyNot done: a manual pass through cart and checkout.