Added support for discounts in the POS checkout process, allowing operators to apply either a fixed amount or a percentage off the gross total. Updated the state management to include discount details and modified the receipt and cart rendering to display pre- and post-discount values. Enhanced the checkout API to handle discount inputs and ensure proper calculations. Updated relevant tests to cover new discount logic.
18 KiB
Approver / Supervisor — SOP
Owns: the approvals queue, pricing/markup policy, escalations from Quote and Order Operators, weekly KPI reviews, and the health of the system overall.
Tools: /quotes/approvals, all operator routes (read),
/dashboard, /customers, /suppliers, /settings,
/api/v1/... admin endpoints, the daily summary call.
Handoffs:
- From Quote Operator → quote in
approval_pending. - To Quote Operator → approved / rejected / change-requested.
- From Order Operator → escalations (cancellation, refund, discount > 15%, supplier issue).
- To Order Operator → decision + instruction.
- From Collection Driver → escalations (refusal, damage dispute, customer relationship issue).
- To everyone → policy updates, training, weekly review.
1. Daily / Weekly Checklist
Every working day (start of shift, 08:00 SAST)
- Open
/quotes/approvals. Clear the queue. Anything older than 4 working hours needs a decision today. - Open
/dashboard. Quick scan:- Approval Rate gauge — should be > 70% on a healthy pipeline.
- Quote Pipeline donut — too much in
newfor >2 days is a Quote Operator capacity problem. - Follow-ups Due — count should be trending down.
- Concentric rings (quote pipeline depth) — if the "Approved" ring is growing while the "Sent" ring is shrinking, the email send flow has a problem.
- Check
#quote-opsand#order-opschannels. Triage any escalations posted overnight. - Skim
/orders— Cancelled tab. A spike in cancellations = supplier problem or pricing problem. Investigate.
Every working day (mid-day, 13:00 SAST)
- Re-check
/quotes/approvals. Anything still inapproval_pendingfrom this morning is now a process bug. - Triage any pending escalations. Quote Operators and Order Operators should be unblocked by lunch.
- Review one random operator action (audit). Pick an order or quote at random, walk through the action log. Calibrates your understanding of the team's actual work.
Every working day (end of shift, 17:00 SAST)
- Clear the day's escalations. Every escalation should have either a decision or a clear next step.
- Review today's KPI snapshot. Any operator trending red? Send them a 1-line note (not a formal message — keep it human).
Every Monday morning (90 min block)
- Pull the weekly KPI one-pager for each Quote and Order Operator (and the Collection Driver's app-export).
- Hold the weekly standup (15 min):
- Each operator: 1 number (their worst KPI) + 1 win.
- You: 1 policy reminder + 1 system change coming this week.
- Update pricing policy if any of these moved:
- Supplier price list changes (cost-side).
- Competitor pricing (market-side).
- Currency moves (ZAR volatility).
- A new strategic account needs a standing discount.
Every Friday afternoon
- Write the 1-page weekly summary. Distribution: owner
(you), the 4 operators, the invoicing clerk (if separate),
and the owner / MD if you have one. Sections:
- Pipeline health (counts by status, vs last week).
- Top 3 wins (one per operator, named).
- Top 3 issues (with an owner + deadline).
- 1 thing we changed (a process, a policy, a system tweak).
- Next week's risks.
- Forecast cash collection for the next 30 days. Pull
deliveredorders not yetinvoiced, sum theirselling_price. This is the cash-in number the owner wants.
Every month (1st, 60 min)
- Monthly 1-on-1 with each operator. 30 min each.
Agenda (use the 1-page review you wrote):
- Their KPIs vs target.
- Their 30-day improvement action.
- What they need from you (training, tools, headcount).
- What they want to keep doing.
- Catalogue coverage review. What % of quote items this month were matched in the catalogue? If < 50%, the Pricelist Curator needs to upload more supplier lists.
- Supplier performance review. Late deliveries, cost-mismatch rate, damage rate. Note any supplier that should be replaced or have terms renegotiated.
Every quarter
- Strategic review. 2-hour session with the owner. Topics: revenue trend, margin trend, customer concentration risk, supplier concentration risk, system gaps.
- Operator tier reviews. Who's eligible for markup- authority / trusted-buyer / senior-driver tier?
- System roadmap input. What 1-2 features would unlock the most operator capacity?
2. Step-by-Step Procedures
2.1 Approve a quote
When: a quote lands in approval_pending.
- Open
/quotes/approvals. The queue is sorted by age, oldest first. - Click a quote. Review:
- Customer + rep — known account? Standing discount?
- All lines priced (every line has
selling_price > 0). - Markup — does the markup meet the policy for this category / customer?
- Validity — is the validity date realistic?
- Supplier — do we have a healthy relationship with this supplier? Any open POs with them?
- Decide:
- Approve → click Approve. Status flips to
approved. The Quote Operator can now send. - Request changes → add a comment in the change-
request field. Status stays in
approval_pending(or reverts toprocessedif it was a pricing issue). The Quote Operator re-submits. - Reject → add a reason. Status flips to
rejected. The Quote Operator may revise or close the quote.
- Approve → click Approve. Status flips to
- Log the decision in
quote.notes(auto-stamped by the system, but add context if it's non-obvious — e.g. "Approved at 18% markup, customer's standing discount from June 2026 contract").
Don't:
- Don't approve without reading the full quote. A 30-second review misses the wrong SKU, the wrong qty, the wrong customer.
- Don't reject without a reason. "No" is demoralising; "No, because the JEI prices are below cost" is a teachable moment.
2.2 Set / change a pricing policy
When: cost or market conditions change.
- Identify the affected scope. Is it a category (e.g. "all FASTENERS"), a customer (e.g. "Account XYZ"), or a supplier (e.g. "all JEI lines")?
- Pull the data. What is the current avg markup for that scope? What are competitors charging? What's the supplier cost trend?
- Propose the new policy. Document:
- Scope (which customers / categories / SKUs).
- New markup range.
- Effective date.
- Reason (market move, supplier cost, strategic account).
- Communicate. Post in
#quote-ops, mention in the Monday standup, and pin in/settings(if there's a pricing-policy field there). - Audit after 2 weeks. Pull the avg markup for the scope — is the team applying the new policy? If not, retrain.
2.3 Handle an escalation from a Quote Operator
When: a Quote Operator pings you with a question (markup override, customer relationship, stuck item).
- Read the full context before responding. Don't respond to a 1-line ping with a 1-line answer.
- Categorise:
- Pricing → see §2.2. Likely a one-off override.
- Customer relationship → call the customer yourself if strategic; delegate back if not.
- System / data → the system has a gap. File a
feature request in
src/app/api/mcp/FEATURE-REQUESTS.md(or whatever the current backlog file is). - Process → the SOP is unclear. Update the relevant SOP (and tell the team).
- Respond with a decision + a why. The operator needs to learn from the decision, not just execute it.
- Follow up next day. Verify the decision was applied.
2.4 Handle an escalation from an Order Operator
When: an Order Operator pings you with cancellation, refund, discount > 15%, supplier dispute, customer complaint.
- Same triage as §2.3, but the stakes are usually higher (real money, real relationships).
- For customer complaints — get the customer's side of the story first. Don't take the operator's word at face value; don't take the customer's at face value either.
- For supplier disputes — pull the PO + delivery evidence (photos, signed notes). Make the call based on the contract, not the relationship.
- Document the decision in the order's
notesand your private escalation log.
2.5 Run a weekly KPI review
When: every Monday.
- Pull the one-pager. Each operator has 4-6 KPIs. The report highlights who's red, who's yellow, who's green.
- For each red operator:
- Look at the underlying data. Is it a process issue, a capacity issue, or a skill issue?
- Process → fix the SOP, retrain.
- Capacity → redistribute the load or accept the miss.
- Skill → 1-on-1 coaching, shadow a senior operator.
- For each green operator:
- Find the win. Mention it in the standup.
- If they're consistently green, consider the tier bump.
- Write the 1-page weekly summary. (See §1 Friday.)
2.6 Audit a random operator action
When: mid-day, when you have 10 minutes.
- Pick a random order or quote from the last 24 hours.
- Walk the action log: who touched it, when, what changed.
- Look for:
- Status transitions that don't match the SOP (e.g.
pending→deliveredskipping the intermediate states). - Pricing changes without a
pricing_notesbreadcrumb. - Items stuck in a state longer than the SLA.
- Status transitions that don't match the SOP (e.g.
- If you find a real issue: message the operator privately, not in public. Coaching, not blame.
- If you find a SOP gap: update the SOP.
3. Decision Tree
3.1 Should I approve this discount?
What's the customer's standing discount (per the customer
record / contract)?
├── Matches → approve at face value
└── Doesn't match
├── Is the difference small (< 3%)? → approve, log the
│ reason (e.g.
│ "volume uplift
│ from Q3 contract").
├── Is the difference medium (3-10%)? → approve if
│ the customer
│ is strategic
│ OR the deal
│ is a one-off
│ (large order,
│ end-of-line
│ stock, etc).
│ Otherwise,
│ ask the
│ operator to
│ split the
│ margin with
│ the customer
│ themselves.
└── Is the difference large (> 10%)? → talk to the
customer
yourself.
Strategic
pricing is a
relationship
call, not a
quote.
3.2 Supplier wants to renegotiate terms
Is the supplier a strategic dependency (> 20% of our spend)?
├── Yes → call the supplier yourself. Don't delegate.
│ Renegotiation is a relationship call.
└── No
├── Will the new terms save us money or improve
│ service? → accept, log in the supplier record.
└── Will they cost more or worsen service? → decline,
keep the
relationship
professional
(don't burn
the bridge).
3.3 Customer escalates a quality issue
Is the issue real (defect, wrong item, damaged in transit)?
├── Yes
├── Was the issue caused by us (wrong pick, late
│ delivery, damaged in our care)?
│ ├── Yes → own it. Replace or refund, no argument.
│ │ Don't ask the customer to prove the
│ │ damage.
│ └── No (supplier defect, customer mishandling)
│ ├── Defect is our supplier's → call them, get
│ │ a credit or
│ │ replacement, pass
│ │ it on.
│ └── Customer mishandling → politely decline.
│ Offer a goodwill
│ discount at your
│ discretion.
└── What's the cost of fixing vs losing the customer?
├── Customer is strategic → fix, no matter the
│ cost. Relationships
│ > margins.
└── Customer is transactional → fix only if it's
cheaper than
losing them. Most
one-off customers
aren't worth a
free replacement.
3.4 An operator is consistently missing a KPI
How long have they been missing it?
├── < 2 weeks → noise. Mention in the 1-on-1, move on.
├── 2-4 weeks → pattern. Diagnose:
│ ├── Process gap (unclear SOP) → update the SOP,
│ │ retrain.
│ ├── Capacity gap (too much load) → redistribute.
│ └── Skill gap (doesn't know how) → pair with a
│ senior operator for
│ a week.
└── > 4 weeks → performance issue. Formal conversation.
Set a 30-day improvement target with consequences
if missed.
3.5 A quote is in approval_pending for > 1 working day
Who submitted it?
├── Quote Operator on shift → ping them directly. "Why is
│ this still in my queue?"
└── Quote Operator off shift / on leave → reassign to
another operator
OR approve it
yourself if
straightforward.
3.6 The system is misbehaving (data loss, wrong status, etc.)
Is the issue isolated to one record?
├── Yes → fix the record directly via the admin tools or
│ `pb-helpers.ts` / service layer. Document the
│ fix.
└── No (multiple records, or a pattern)
├── Stop the workflow that's causing the damage.
│ (e.g. pause the n8n email intake if it's creating
│ bad quotes.)
├── Page the dev. Don't try to fix the code yourself
│ unless you ARE the dev.
├── Communicate to the team: "stop doing X until
│ further notice."
└── After the fix: write up the post-mortem. What
happened, what we did, what we'll do to prevent
it. Share with the team.
3.7 Strategic account wants terms we don't usually offer
What's the customer's annual spend with us?
├── Top 10% → call the owner / MD. Strategic accounts
│ can have bespoke terms; it's a relationship
│ call.
├── 10-25% → decide yourself. Document the terms in the
│ customer record, in a contract if material.
└── Bottom 75% → decline. Standardise. Bespoke terms
for non-strategic accounts erode
margin and create admin overhead.
4. KPIs
The supervisor's KPIs are different from the operators' — they're about the team's health, not the supervisor's own output.
| KPI | Target | How it's measured |
|---|---|---|
| Approval turnaround | < 4 working hours median | approved_at - submitted_at on quotes/approvals |
| Escalation response time | < 2 working hours | decision_at - escalation_at on the escalation log |
| Team KPI attainment | > 80% of operator KPIs at target | weekly one-pager summary |
| Quote → order conversion | > 35% trailing 90 days | orders / emailed quotes |
| On-time delivery rate | > 90% trailing 30 days | orders delivered by delivery_date / total delivered |
| Catalogue coverage | > 60% of quote items matched | sprint items with matched_price_list_id / total sprint items |
| Supplier cost-mismatch rate | < 3% trailing 30 days | cost_mismatch verdicts / total receives |
| Customer concentration risk | top customer < 30% of revenue | revenue by customer over trailing 90 days |
| System uptime | > 99% trailing 30 days | uptime of WFDASH + PB + n8n (monitor externally) |
| Team tenure | trending up | months since each operator's start date |
How the supervisor's KPIs feed into YOUR review
- Weekly: the owner / MD sees the weekly summary. Your team KPIs are the headline.
- Monthly: 1-on-1 with the owner / MD. Focus on strategic accounts, concentration risk, and system gaps.
- Quarterly: strategic review. This is where you push for the headcount / tools / process changes the team needs.
What the system does NOT measure (yet)
- Operator morale (no internal NPS yet)
- Customer satisfaction (no external NPS yet)
- Operator skill growth (no per-operator skill matrix yet)
If a KPI is unfair, raise it. The owner can adjust targets, but the metric stays.