Part 4 of 7 · Quote drafter series ~5 min read

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

Five-stage pricing pipeline per line item A vertical pipeline diagram. At the top, an input box "Resolved line item" with the SKU, quantity, and destination. Below it, five stage boxes stacked vertically, each labelled with its stage and a small tag of where it gets grounded. Stage 1: Base price — reads the catalog row for the SKU; emits unit price and citation pointing to "catalog § SKU row." Stage 2: Tier discount — reads the rules doc for the customer's tier (looked up from the CRM by email domain, defaulting to "new prospect" if no match); applies the percentage off; emits running unit price and citation pointing to "rules § tiers." Stage 3: Volume break — reads the rules doc for any per-SKU volume tables; applies the deepest qualifying break; emits running unit price and citation pointing to "rules § volume." Stage 4: Regional — reads the rules doc for the destination region; applies any regional surcharge or discount and computes a freight estimate; emits final unit price plus freight and citation pointing to "rules § regional." Stage 5: Bundle — only fires if the RFQ has multiple line items that together match a bundle definition in the rules doc; if it does, replaces the relevant lines with a bundle row; emits final lines and citation pointing to "rules § bundles." After the five stages, an output box "Priced line" with: SKU, qty, unit price, line total, every applied rule, and the citations. To the right of the pipeline, a smaller dashed-border box labelled "Discount cap watcher" with an arrow into stage 5: at the end, total discount across all rules is compared to the configurable cap; if above, the line gets a manager-approval-required flag visible to the rep but the line still drafts. A note at the bottom: every number on the quote ties back to one passage in the catalog or rules doc — a rep can audit any line in one click. Resolved line item SKU · quantity · destination Stage 1 Base price cites catalog § SKU row Stage 2 Tier discount cites rules § tiers Stage 3 Volume break cites rules § volume tables Stage 4 Regional cites rules § regional + freight Stage 5 Bundle cites rules § bundles (optional) Priced line SKU · qty · unit price · line total every applied rule + citation Discount cap total off > cap? flag for manager, don’t block draft Every number on the quote ties back to one passage in the catalog or rules doc — auditable in one click.
Fig 4. Five stages run per line, in order. Each reads the catalog or the rules doc, applies its rule, and writes back the section that produced its number. The discount-cap watcher flags lines for manager review without blocking the draft.

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