Tobacco & liquor store buyer - cash / net-terms / rebate quote converter - single-file web page, three quotes for the same product in, true per-bottle cost and annualized capital cost out; volume rebates are computed on the volume you'll actually do, and the cash spent chasing the threshold is flagged separately
You are a coding agent building a tool for a
tobacco & liquor store buyer. Build a single-file
HTML tool (all inline, no external dependencies,
no network calls, opens by double-click): a true
cost converter for three supplier quote types.
The buyer's problem, stated in the tool's
positioning: the rep offers three quotes on one
product - cash, net terms, volume rebate. They
can't be compared directly: cash is cheapest but
the money leaves today, terms cost more but pay
later, the rebate looks beautiful but the
threshold may be unreachable. Picking by gut,
mostly wrong.
Input section:
- Product and baseline: product name, list
unit price
- Quote 1 - cash: cash unit price, payment
timing (on delivery / prepaid)
- Quote 2 - net terms: terms unit price, terms
length (days to pay), any preconditions
- Quote 3 - rebate: purchase unit price
(usually list), rebate threshold (spend
within the period), rebate rate, settlement
timing (quarter-end / year-end)
- My volume and money: expected purchase
volume or spend within the period, my annual
opportunity cost of capital (loan rate or
forgone yield), the product's normal monthly
movement in my store
Calculations and output:
1. True per-bottle cost, three cards side by
side:
- Cash true cost = cash price x (1 +
annualized opportunity cost x days tied
up / 365) - the cash discount isn't free;
fronted money accrues by the day
- Terms true cost = terms price x (1 -
annualized opportunity cost x terms days
/ 365) - the float the supplier grants
gets credited back
- Rebate true cost = purchase price x (1 -
true rebate rate). The true rebate rate
uses the volume I'll actually do: expected
spend >= threshold, use the stated rate;
below threshold, the rate is zero - a
rebate you can't reach isn't a discount,
it's bait
One verdict line under the cards: at my
current expected volume, which is cheapest,
and by how much
2. The crossover: the purchase spend at which
the rebate's true cost starts beating cash -
drawn on a line next to my expected spend,
so the distance to the threshold is visible
at a glance
3. Threshold-chasing flag (its own card,
distinct color): if I lift my spend from
"expected" to "threshold" to reach the
rebate, the uplift x (rebate cost - best
cost) / unit price approximates what the
chase costs, and my normal monthly movement
converts those extra bottles into weeks of
supply - goods bought to chase a rebate are
capital, not profit
4. Method notes: every formula printed on the
page, every number moving with its inputs
Boundaries (printed on the page):
- Market-price risk stays out of the formulas
but must be said: liquor has a market, and a
price drop during the holding period can cost
more than any quote spread - fixed line: "this
tool compares quotes, not market risk"
- The tool does arithmetic, not selection - the
three structures carry different risks (cash
carries market risk, terms carries the
supplier's credit, rebates carry completion
risk); choosing is a human act
- Rebate settlement beyond a quarter out gets
a printed nudge - "the further away the
payout, the more it deserves a haircut" - a
working heuristic about payout reliability,
flagged but never folded into the math
Hard requirements:
- Data stays local (localStorage), exportable,
resettable
- Preloaded sample data so the three cards are
visible on open
- Multiple products storable side by side for
negotiating a whole order sheet
Why it is written this way
"True rebate rate uses expected volume; below threshold it's zero" is the tool's least negotiable line. Volume rebates are the most engineered of the three quote types: the threshold sits just above your natural order size, close enough to feel reachable - and the stretch it induces is usually the entire price of the rebate. The tool draws the crossover line right next to your expected spend so "how far away is it" reads in one glance; the threshold-chasing card goes further, pricing the stretch itself in extra cash and extra weeks of supply. Chasing points stops being a clever illusion and becomes a line-item loss on the table.
Putting the time value of money into the math makes the three quotes comparable for the first time. Cash and terms prices look like two numbers; they're actually two payment dates - comparing the unit prices directly treats today's money and sixty-days-later money as the same thing. Discounting with the buyer's own opportunity-cost rate (their loan rate or forgone yield) adds the carry to cash and credits the float to terms, and only then do the three cards share a ruler. The rate is deliberately user-entered rather than built in: the cost of capital differs wildly between shops, and the act of filling it in forces the buyer to answer "what does my money cost me" - a question worth asking once a year even if the answer never changes.
Market-price risk is explicitly excluded from the formulas yet printed on the page - the tool's honesty boundary. Price risk can't be compressed into a formula, but it's precisely the largest hidden cost of the cash and threshold-chasing structures: stock sitting through a two-point market drop swamps any quote spread. Pretending to compute it would invite the buyer to outsource market judgment to a calculator; saying nothing would let them stare at quote spreads alone. The compromise is a fixed caution - the tool compares quotes; you judge the market - keeping arithmetic and judgment in their separate lanes.
Variables
| Variable | Description |
|---|---|
| Opportunity cost rate | The annual rate at which your money is valued - your loan rate if you carry debt, otherwise your actual achievable yield; set it low and the tool systematically favors the cash quote |
| Expected period spend | The rebate card's key input - fill it from normal movement plus locked orders, never from "a push might reach the threshold"; that number is a conclusion, not an input |