How a quote gets priced
An auto-draft RFQ has resolved line items: catalog SKUs, quantities, a destination, a deadline. Pricing is the part that’s temptingly easy for an LLM to do badly. The setup here doesn’t use a model for any of it. Every line runs through a five-stage pipeline of plain Python, each stage reading the catalog or the rules doc, each stage citing the passage that produced its number. By the time the cover-paragraph composer sees the priced quote, the prices are already settled and traceable.
Key takeaways
- Five stages run per line, in order: base price, tier discount, volume break, regional, bundle.
- None of the stages call a model. All of them read the catalog or the rules doc.
- Every applied rule writes back the section that produced it. The cover paragraph cites them.
- Discounts above a configurable cap raise a flag for the rep but don’t block the draft.
- The engine never invents a number. A missing rule means no rule applied, never a guess.
The pricing pipeline, per line
Stage 1: base price
The line arrives with a resolved SKU. The engine reads that SKU’s row from a small in-memory index of the catalog — a direct lookup, no model and no vector search. The index refreshes whenever the rules folder changes. Base price comes from the row’s price column, in the unit listed there. The citation is “catalog § SKU.” If the row is missing a price, the engine doesn’t guess. The line is flagged for manual handling and stops there. This shouldn’t happen in a healthy catalog. When it does, it’s usually a row someone added without filling in the price. The flag lands in the rep’s queue with a message naming the row.
Stage 2: tier discount
The engine looks up the customer’s tier from your CRM, keyed on the buyer’s email domain. Tiers are configured in the rules doc — typical setups have three or four (new prospect, standard, preferred, contract). If the email domain doesn’t match a known customer, the engine defaults to new prospect. The rules doc says, in plain prose, what each tier gets: “preferred customers receive a 5% discount on all standard SKUs.” The engine applies that discount and writes the citation: “rules § tiers, preferred.”
If the buyer’s email domain is in your CRM but no tier is set on the contact, the engine treats them as standard — not as preferred. A missing tier is different from a tier of “preferred not yet set.” Defaulting to standard keeps the engine from accidentally giving away a discount because somebody forgot to update a contact record.
Stage 3: volume break
The rules doc has a small table for each SKU that ships in tiered quantities: “A-12: 50–199 units, list price; 200–499, 4% off; 500+, 7% off.” The engine reads the table for the line’s quantity and applies the deepest break that qualifies. Whether volume discounts stack with the tier discount is a rules-doc decision, not an engine decision. The default in the rules doc is yes, so a preferred customer ordering 250 units gets 5% (tier) plus 4% (volume) — 9% off list in total. The citation is “rules § volume, A-12 row 2.”
If the line came through with a quantity range from the extractor (the buyer wrote “200 to 500”), the engine doesn’t price it. A range that spans two volume-break tiers is exactly the kind of thing the move-picker should have caught and turned into the clarify move. If the engine still sees a range here, it’s a bug. The line is flagged and parked.
Stage 4: regional pricing and freight
The destination decides two things: any regional adjustment to the unit price (some products cost more in regions that require compliance certification) and the freight estimate. Both come from the rules doc. The regional adjustment is a percentage on the running unit price. The freight estimate is a per-line number plus a per-shipment fixed amount. Regional rules are strict: a destination either matches a defined region or it doesn’t. If it doesn’t, the engine keeps the standard unit price and marks freight as “needs rep confirmation” rather than guessing the cost of shipping somewhere the rules doc doesn’t know about.
Stage 5: bundles (when they apply)
Most RFQs don’t hit this stage. A few do. The rules doc’s bundles section defines combinations: “A-12 + A-12L + A-mount-bracket, any quantities ≥ 100 of A-12, the set is priced at $X per A-12 with the others included.” If the RFQ has line items that together match a bundle definition, the engine replaces those lines with one bundle row. The citation: “rules § bundles, A-12 + A-12L + A-mount-bracket.” The rep sees both the bundle row and a small note showing what individual lines went into it.
Bundles are a common source of customer confusion (“why didn’t I get the bundle price?”), so the engine writes a small note when a bundle didn’t apply because the quantity threshold wasn’t met — not on the customer-facing quote, but in the audit row the rep sees. If the buyer would have qualified by ordering thirty more of A-12, the rep can mention it on follow-up.
The discount-cap watcher
After all five stages, the engine adds up the total discount across all applied rules and compares it to a cap you set (often 15%, sometimes 20% for preferred customers, occasionally 0% for new prospects on first orders). If the total goes over the cap, the line gets a requires_manager_approval = true flag. The line still drafts. The quote still renders. The rep still sees it. But the flag is visible at the top of the draft and on every flagged line, and the “Approve and send” button on the rep’s screen is replaced by “Send to manager for approval.” The customer never sees a quote until somebody with authority signs off.
Next post: how the draft stays honest on its way to the rep — the four guardrails that sit between the model output and the queue, and why a draft never auto-sends.
All posts