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.
439 lines
18 KiB
Markdown
439 lines
18 KiB
Markdown
# 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 `new` for >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-ops` and `#order-ops`** channels. 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 in
|
|
`approval_pending` from 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
|
|
`delivered` orders not yet `invoiced`, sum their
|
|
`selling_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`.
|
|
|
|
1. Open `/quotes/approvals`. The queue is sorted by age,
|
|
oldest first.
|
|
2. 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?
|
|
3. **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 to `processed` if 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.
|
|
4. **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.
|
|
|
|
1. **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")?
|
|
2. **Pull the data.** What is the current avg markup for
|
|
that scope? What are competitors charging? What's the
|
|
supplier cost trend?
|
|
3. **Propose the new policy.** Document:
|
|
- Scope (which customers / categories / SKUs).
|
|
- New markup range.
|
|
- Effective date.
|
|
- Reason (market move, supplier cost, strategic account).
|
|
4. **Communicate.** Post in `#quote-ops`, mention in the
|
|
Monday standup, and pin in `/settings` (if there's a
|
|
pricing-policy field there).
|
|
5. **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).
|
|
|
|
1. **Read the full context** before responding. Don't
|
|
respond to a 1-line ping with a 1-line answer.
|
|
2. **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).
|
|
3. **Respond with a decision + a why.** The operator needs
|
|
to learn from the decision, not just execute it.
|
|
4. **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.
|
|
|
|
1. **Same triage as §2.3**, but the stakes are usually
|
|
higher (real money, real relationships).
|
|
2. **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.
|
|
3. **For supplier disputes** — pull the PO + delivery
|
|
evidence (photos, signed notes). Make the call based on
|
|
the contract, not the relationship.
|
|
4. **Document the decision** in the order's `notes` and
|
|
your private escalation log.
|
|
|
|
### 2.5 Run a weekly KPI review
|
|
|
|
**When:** every Monday.
|
|
|
|
1. **Pull the one-pager.** Each operator has 4-6 KPIs. The
|
|
report highlights who's red, who's yellow, who's green.
|
|
2. **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.
|
|
3. **For each green operator:**
|
|
- Find the win. Mention it in the standup.
|
|
- If they're consistently green, consider the tier
|
|
bump.
|
|
4. **Write the 1-page weekly summary.** (See §1 Friday.)
|
|
|
|
### 2.6 Audit a random operator action
|
|
|
|
**When:** mid-day, when you have 10 minutes.
|
|
|
|
1. Pick a random order or quote from the last 24 hours.
|
|
2. Walk the action log: who touched it, when, what
|
|
changed.
|
|
3. **Look for:**
|
|
- Status transitions that don't match the SOP (e.g.
|
|
`pending` → `delivered` skipping the intermediate
|
|
states).
|
|
- Pricing changes without a `pricing_notes` breadcrumb.
|
|
- Items stuck in a state longer than the SLA.
|
|
4. **If you find a real issue:** message the operator
|
|
privately, not in public. Coaching, not blame.
|
|
5. **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.
|