Wiki
Pricing Engine
How QuoteNode's deterministic pricing engine calculates offer totals, applies discounts, and handles multi-currency and VAT.
Pricing Engine
QuoteNode uses a deterministic pricing engine that guarantees reproducible, auditable calculations. Every price, discount, and tax amount follows a defined evaluation order and is stored for verification.
Calculation Order
The engine processes prices in this exact sequence:
- Line unit price — base price from catalog (or manually entered for custom items)
- Pricing rule evaluation — automatic adjustments based on customer or customer group rules
- Quantity multiplication — unit_price × quantity = line_subtotal
- Line-level discount — percentage or fixed amount subtracted from line_subtotal = line_net
- Line VAT — line_net × VAT_rate = line_vat (per line, from the product’s VAT group)
- Line gross — line_net + line_vat = line_gross
- Subtotal — sum of all line_net values
- Offer-level discount — percentage or fixed amount subtracted from subtotal
- Shipping — added to discounted subtotal (NET value)
- Total NET — discounted subtotal + shipping
- Total VAT — sum of per-line VAT amounts (recalculated after offer discount if applicable)
- Total GROSS — total_net + total_vat
Pricing Rules
Pricing rules allow automatic price adjustments based on customer relationships:
Rule Targets
- Per customer — applies to a specific customer (e.g., “ACME Corp gets -10%”)
- Per customer group — applies to all customers in a group (e.g., “VIP customers get -15%“)
Rule Scope
- All products — the rule applies to every product in the catalog
- Specific product group — the rule only applies to products in a named group (e.g., “Services” or “Hardware”)
Rule Types
- Percentage discount — subtracts a percentage from the base price (e.g., -10%)
- Percentage markup — adds a percentage to the base price (e.g., +5%)
- Fixed amount discount — subtracts a fixed amount per unit (e.g., -20 PLN)
- Fixed amount markup — adds a fixed amount per unit
Priority & Conflicts
When multiple rules match the same product-customer combination:
- Rules are sorted by priority (higher number = higher priority)
- The highest-priority matching rule wins
- Rules do not stack — only one rule is applied per product-customer pair
Validity
Each rule has an optional date range (valid_from, valid_to) and an active flag. Only active rules within their validity period are evaluated.
Multi-Currency
QuoteNode supports creating offers in any configured currency:
- Base currency — the tenant’s default currency (e.g., PLN), used for all reporting
- Offer currency — the currency selected for a specific offer (e.g., EUR, USD)
- FX rate — the exchange rate between the offer currency and base currency
When an offer is created in a non-base currency:
- Product prices are stored in the base currency in the catalog
- At offer creation, the current FX rate is applied to convert prices
- The FX rate used is stored in the offer snapshot (immutable)
- Pipeline reports convert all offer values back to the base currency using the stored rate
FX rates are currently managed manually by administrators. Automatic NBP/ECB integration is planned.
VAT Handling
VAT Groups
VAT groups define the available tax rates for the tenant:
- Standard rates: 23%, 8%, 5%, 0%
- Exempt (no VAT)
- Custom rates for specific jurisdictions
Each product is assigned to a VAT group. One VAT group is marked as the default (applied to new products and custom line items).
Per-Line VAT
VAT is calculated per line item, not as a flat percentage on the total. This is critical for offers containing products with different VAT rates.
The offer totals include a VAT breakdown table showing the total amount per rate:
VAT 23%: 1,230.00 PLN
VAT 8%: 160.00 PLN
VAT 0%: 0.00 PLN
─────────────────────────
Total VAT: 1,390.00 PLN
Price Display Modes
Each offer can use one of three price display modes:
- NET — all prices shown as NET values only
- GROSS — all prices shown as GROSS values only
- NET + VAT + GROSS — full breakdown showing all three values per line and in totals
The mode is configurable per offer and affects both the PDF template and the public offer page.
Discounts
Line-Level Discounts
Each line item can have an individual discount:
- Percentage — e.g., -10% off the line subtotal
- Fixed amount — e.g., -50 PLN off the line subtotal
Line discounts are applied after quantity multiplication but before VAT.
Offer-Level Discount
A global discount can be applied to the entire offer:
- Percentage — e.g., -5% off the subtotal
- Fixed amount — e.g., -200 PLN off the subtotal
The offer discount is applied after all line totals are summed but before shipping and VAT.
Discount Display
The template system supports three discount display modes:
- BAKED_IN (default) — discounts are pre-applied; the client sees only the final price
- SHOW_COLUMN — a dedicated discount column shows the original price and the discount applied
- HIDDEN — discounts are applied but not shown in a separate column
Rounding
All monetary calculations use HALF_UP rounding (banker’s rounding is configurable). Rounding is applied:
- Per line item (after discount, before VAT)
- Per VAT amount (per line)
- Per offer total
The rounding mode is consistent across the entire calculation to ensure that line totals always sum to the offer total.
Stored Totals
Calculated totals are stored in a denormalized offer_totals table for:
- Fast querying in reports and list views
- Audit verification (recalculation can be validated against stored values)
- Historical accuracy (totals are snapshotted and preserved even if pricing rules change later)