Wholesaler: Customer Price Lists, Repeat Orders, and Price-Override Approval
Back to blog
product·September 6, 2026·5 min read·By Yehonatan Saadia

Wholesaler: Customer Price Lists, Repeat Orders, and Price-Override Approval

A six-rule price resolution ladder, what happens when a contract costs more than a campaign, an override approval matrix, and what a repeat order re-resolves.

Key takeaways

  • A customer price is the output of a ladder of rules, not a stored field. Six rules compete for the same line and exactly one wins.
  • The winning rule identifier is stored on the order line. Without a `price_rule_id` there is no answer to "why did they get that price" two months later.
  • A customer contract can be more expensive than a general campaign. That is not a bug, and it is a decision that must be written down in advance: strict precedence, or lowest-wins.
  • Going below the resolved price is not a technical exception but an approval request, with a band, an approver and a reason. A margin floor derived from cost cannot be quietly overridden.
  • A repeat order copies items and quantities and never copies prices. Price is re-resolved at the new order date, and an unusual difference from last time is flagged.

In a wholesale business almost every customer has their own price for the same SKU, so the question is never "what is the price" but "which rule won". A system that returns a number without recording the rule that produced it cannot explain a single line, and cannot reproduce that price on the next order.

The price ladder: six rules, one winner

The price for an order line is resolved by walking six possible sources, ordered from the most specific to the most general:

  1. Contract price for this customer and this SKU - an agreed price with a date range, usually from a signed engagement.
  2. Customer-specific price list - a price table belonging to one customer only.
  3. Group or channel price list - distributors, chains, institutions. A customer belongs to exactly one group at any moment.
  4. Quantity break on the applicable list - a break is not a separate list but a rule applied to the list already selected.
  5. Campaign price - a dated price that does not depend on the customer.
  6. Base list price - the default, and what is shown when nothing else applies.

Each rule carries an identifier, a start date, an end date and an owner. The rule that won is recorded, and so are the rules that were evaluated and lost, in one resolution record. The same principle of a price as a dated row rather than a field on the product is covered in one price list for your website and your quotes.

Which price wins when a contract is worse than the campaign?

This is the question that breaks pricing systems, and it has two legitimate answers that must never be mixed.

A worked case: customer C-0412, SKU WH-4180, an order for 600 units on 2026-04-12.

RuleUnit priceValidityApplies
Base list38.00StandingYes
Distributor group list33.50StandingYes
Contract for C-041231.002026-01-01 to 2026-12-31Yes
Quantity break from 500 units30.90StandingYes
Spring campaign29.902026-04-01 to 2026-04-30Yes

Under strict precedence the contract wins at 31.00. Under a lowest-wins policy the campaign wins at 29.90. The difference on this order is 660, and it falls on the customer who signed a contract. Both policies are defensible, but only one can be in force; it lives in an organisation-level price_policy field, and it carries a version number.

The practical rule: if the contract contains an explicit undertaking that the customer never pays more than a promotional price, the policy is lowest-wins and there is nothing to debate. Where no such undertaking exists, strict precedence produces predictable behaviour, provided the salesperson can see the price the customer missed and can request an override.

Order-line fields that turn a price into an explanation

FieldExampleWhat it answers
list_price38.00What the price would be with no rule at all
price_sourcecustomer_contractWhich kind of rule won
price_rule_idCTR-0412-4180Which record exactly
resolved_price31.00The ladder output, before any human intervention
override_price30.00The price actually charged, if it was changed
override_pct3.23The size of the deviation from the resolved price
override_reasoncompetitor_matchA code from a closed list
approved_byU-014Who approved it, not who typed it
resolved_at2026-04-12T09:41:00+03:00The moment the ladder ran
price_policy_versionv3Which policy was in force

The field most systems drop is resolved_price when an override exists. Without it only the final price survives, and there is no way to measure how much money was given away below list, which is usually the number most worth knowing.

The approval matrix: who may go below the resolved price

The margin floor is derived from landed cost and a minimum margin percentage, never from the list price. For SKU WH-4180 at a landed cost of 24.80 and a 15% minimum margin, the floor is 29.18. How that cost is calculated is set out in landed-cost calculation for an importer.

Deviation from the resolved priceApproverWhat is recorded
Up to 2%The salespersonReason code
Over 2% and up to 8%Sales managerReason code and a free-text note
Over 8%OwnerReason, note and a time-limited validity
Any price below the floorOwner onlyA separate approval, however small the deviation

On a resolved price of 31.00 that means: down to 30.38 sits inside the salesperson's own authority, down to 28.52 needs a manager, and anything under 29.18 is blocked regardless because it breaches the floor. Note that the bands overlap, so the written rule is that the stricter of the two limits governs.

  • The reason code is a closed list: competitor match, new customer opening, service-failure compensation, stock clearance, correcting an earlier quote.
  • Approval attaches to a line, not to an order. A ten-line order with one deviating line needs one approval, not ten.
  • Approvals expire. An override approved six months ago does not justify the same price on today's order.

What does a repeat order actually copy?

It copies what the customer asked for, not what the customer paid. That separation is the whole difference between a convenient repeat order and one that perpetuates a mistake:

  • Copied: the SKU list, quantities, unit of measure, delivery address, contact, shipping notes.
  • Re-resolved: every price, every quantity break, every campaign, and the availability status of each item.
  • Never copied: approved price overrides, because the approval was given for the circumstances of that day.
  • Blocked: a SKU that is discontinued or no longer on this customer's list. It is surfaced as a line requiring a decision, never dropped silently.

After re-resolution the order shows a comparison: previous price, new price, and the difference as a percentage, per line. Any line that moved by more than five percent is flagged. That flag catches the two common cases - a campaign that ended and a contract price that expired - before the order goes out rather than after the customer receives an invoice.

A structure like this assumes the order, the delivery note and the invoice share one identifier, as described in quote, order and invoice under one identifier.

What actually breaks

  • A percentage discount on the order header. Nobody can tell which SKU absorbed it, so item-level margin becomes unmeasurable.
  • A price list as a file. A spreadsheet emailed out and saved on a salesperson's laptop produces two versions of the truth inside a week.
  • A price stored on the customer card. With no start and end date, nobody knows when it took effect or who decided it.
  • A quantity break evaluated per line only. A customer ordering the same SKU across three lines never reaches the break, and to them it looks like a fault.
  • A campaign with no end date. It stays live for two years and is discovered in a margin report.
  • A verbal approval. A price agreed on the phone and never recorded becomes a precedent that cannot be withdrawn.

What to have ready before building it

  • A written decision between strict precedence and lowest-wins, with a version number and an effective date.
  • A closed list of customer groups, and a rule that a customer belongs to exactly one at a time.
  • A minimum margin percentage per category, and a decision on which cost it is derived from.
  • A list of override reason codes, short enough that people actually use it.
  • A decision on what a repeat order does with a discontinued SKU: propose a replacement, or stop for review.

Sources

#wholesale#customer price lists#discount approval#repeat orders#B2B pricing#margin floor

Frequently asked questions

Does every customer need their own price list?

Almost never. Most customers should sit on a group list, and only those with a signed contract get dedicated rows. A per-customer list produces hundreds of tables nobody maintains, and within a year the differences between them reflect who asked loudest rather than any policy.

How do you handle a customer demanding the campaign price despite a contract?

By deciding the answer at policy level rather than in the conversation. Under strict precedence the salesperson sees in the interface that the campaign is cheaper and can request an approved override. The customer then gets a consistent answer, and the business can measure how much was given away this way.

What do you do when cost rises mid-contract?

Recalculate the margin floor and flag every contract line that now sits below it. The contract does not change by itself, but that list is precisely what a conversation with the customer, or a decision to absorb the increase, needs. Without it the loss surfaces only in the quarterly report.

How long should price history be kept?

At least as long as an invoice from that period can be reopened, and in practice indefinitely, because the records are small. What is kept is not just the price but the resolution record: the rules evaluated, the rule that won, the policy version and any approved override. That is what lets a line be reconstructed rather than argued over.

Keep reading

Related service

MVP Development

Turn an idea into a validated product in weeks, not months.

Learn more →←

About the author

Yehonatan Saadia

Freelance automation, web & MVP developer

I'm Yehonatan Saadia, a senior developer who builds business automation, custom websites, and MVPs for small and mid-sized companies across the US, Europe, and Israel. These guides come from real client work, not theory.

Work with me

Have a project like this?

Tell me what you're trying to automate or build. I reply within 24 business hours with a few targeted questions, then we walk through it on a free 30-minute call, with no commitment. You come away with a scope, a timeline and a fixed price - or a straight answer that it isn't worth building.