Pricing
What the baseline proves about pricing without a line of custom code, what only works with the optional provider compiled, and the one currency row that will silently make every price wrong by a factor of 100.
What the baseline guarantees
Layers: base 3.2.1 (currencies, VAT), feature-pricing 1.0.0 (the price rows).
Currencies (base, replace/_sql/EcomCurrencies, 170 rows = 10 currencies x 17 languages):
EUR is the default in EVERY language row (CurrencyIsDefault true on all 16 EUR$$<lang>
rows). This is deliberate and load-bearing: DW's ProductIndexBuilder resolves the default
currency PER LANGUAGE CONTEXT. base 3.1.1 set only EUR$$ENU default, the builder's non-ENU
context threw on GetDefaultCurrency(), and the Products index aborted at 0/28 documents —
an empty storefront. 3.1.2 reverted it. Do not "tidy" this to one global default.
EUR$$ENU: CurrencyRate 100, CultureInfo de-DE.
USD$$ENU: CurrencyRate 1, CultureInfo en-US, IsDefault false.
** CurrencyRate is relative to the default, and the default is 100. A rate of 1 on USD
means 1 USD = 0.01 EUR. If this demo is re-based onto USD, the new default currency must be
rate 100 and every other rate set relative to it. **
VAT (base): EcomVatGroups 2 rows ("VAT Default", "Moms") + EcomVatCountryRelations.
Area setting AreaEcomPricesWithVat is "False".
Price rows (feature-pricing 1.0.0, all PACK-RPP-* keyed):
PACK-RPP-0001 PACK-RPP-PROD1, qty 5, unit 4500 EUR (base 4995)
PACK-RPP-0002 PACK-RPP-PROD1, qty 10, unit 4200 EUR
PACK-RPP-0003 PACK-RPP-PROD1, qty 25, unit 3900 EUR
PACK-RPP-0004 PACK-RPP-PROD2, qty 1, unit 1399 EUR (base 1599),
scoped by PriceUserCustomerNumber 98745621
What works with ZERO custom code: the customer-contract row (PACK-RPP-0004). Dynamicweb's
stock DefaultPriceProvider resolves and charges it end-to-end.
What does NOT work uncompiled: the quantity tiers. They ship as data and render on
tier-aware surfaces, but the stock cart resolver ignores tier quantities at cart time, so the
cart charges the base price. Compiling
feature-pricing/src/ReorderingPricingQtyBreakProvider.cs (a PriceProvider, discovered by
assembly scan, HandlePricesExclusively=false) ADDS cart-time tier enforcement. Contract
pricing is identical either way.
** On THIS site, customer number 98745621 belongs to no user. ** That user (IMCUser, id 1328)
ships in the sample-data layer's identities.sql, which this composition does not activate.
The contract price row is therefore inert until you create a user with that customer number
or repoint PriceUserCustomerNumber at a user you author.
One ceiling to know before promising a B2B price beat: MCP `save_prices` exposes no
`PriceUserGroupId`. A DC-scoped or customer-group-scoped contract price is a different column
from the customer-number-scoped one this layer ships, and it is not reachable from the MCP
tool set (dw-commerce-b2b/references/dc-scoping.md:62-77). Which skill covers it
dw-commerce-catalog (dynamo: true) — currency handling and price writes. dw-commerce-orders (dynamo: true) — references/promotions-engines.md for discounts and vouchers (two coexisting engines); references/checkout-configuration.md. dw-data-write-effects (dynamo: true) — SKILL.md:62: "Price rows, currency changes, price-affecting discount or customer-group edits -> force_price_recalculation".
Which MCP tools brand it
save_currencies (set the new default to rate 100 FIRST) -> save_vat_group / save_vat_group_country_relation -> save_prices -> force_price_recalculation Discounts: get_discount_condition_types + get_discount_reward_types -> create_adjustment_discounts -> save_conditions_to_discounts -> save_rewards_to_discounts -> recalculate_discounts.
Verify
MCP: get_currencies -> exactly one row per language context has IsDefault true, and its Rate is 100. get_prices_by_product_id on PACK-RPP-PROD1 returns the three tier rows. Storefront, and this is the assert that matters: add PACK-RPP-PROD2 qty 1 to a cart AS THE SIGNED-IN CONTRACT CUSTOMER and assert the line amount is 1399, not 1599 (feature-pricing's own behaviour probe). force_price_recalculation recomputes WITHOUT a frontend user price context, so it can never prove a customer-scoped price — verify in the storefront cart as the signed-in user (dw-commerce-catalog/references/catalog-publishing.md:189-191).