384 lines
15 KiB
Markdown
384 lines
15 KiB
Markdown
|
|
# Collection Driver — SOP
|
||
|
|
|
||
|
|
**Owns:** picking up goods from suppliers, delivering to customers,
|
||
|
|
capturing proof of collection and delivery. Runs on the
|
||
|
|
**WFDASHDRIVER-APP** (mobile) and `/collection-confirm` (browser
|
||
|
|
fallback).
|
||
|
|
|
||
|
|
**Tools (mobile):** WFDASHDRIVER-APP, `/collection-confirm`.
|
||
|
|
**Tools (office view):** `/collection-pool`, `/collection-map`.
|
||
|
|
|
||
|
|
**Handoffs:**
|
||
|
|
- **From Order Operator** → PO is `po_generated`, item is in
|
||
|
|
`collection_pool` or `assigned` to you.
|
||
|
|
- **To Order Operator** → you mark `collected` on the way back
|
||
|
|
to the office, or on delivery.
|
||
|
|
- **To Stock Controller** → surplus or damaged goods need to be
|
||
|
|
booked.
|
||
|
|
|
||
|
|
**Note:** `drv_status` and `drv_id` are the driver-side fields on
|
||
|
|
`order_items`. The status used here is the item-level
|
||
|
|
`item_status` (see Decision Tree for the exact mapping).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Daily / Weekly Checklist
|
||
|
|
|
||
|
|
### Every working day (start of shift, 07:00 SAST)
|
||
|
|
|
||
|
|
- [ ] **Open WFDASHDRIVER-APP — Today's Run.** Review the
|
||
|
|
supplier list, the order of pickups, and any urgent adds from
|
||
|
|
the Order Operator.
|
||
|
|
- [ ] **Check the truck:** fuel, waybills, blank GRN books,
|
||
|
|
packing tape, camera (phone), and a power bank.
|
||
|
|
- [ ] **Confirm any special instructions** on items (oversize,
|
||
|
|
fragile, supplier with restricted hours).
|
||
|
|
- [ ] **Phone the first supplier** if you haven't worked with
|
||
|
|
them in a while. Confirm they're open and the order is ready.
|
||
|
|
|
||
|
|
### Every working day (mid-day, 12:00 SAST — or at lunch)
|
||
|
|
|
||
|
|
- [ ] **Triage anything blocking you.** Phone the Order Operator
|
||
|
|
if a supplier can't fulfil today, if a customer can't receive,
|
||
|
|
or if you have a route problem.
|
||
|
|
- [ ] **Update the app** with any deviations (supplier short,
|
||
|
|
customer closed, etc).
|
||
|
|
|
||
|
|
### Every working day (end of shift, 17:00 SAST)
|
||
|
|
|
||
|
|
- [ ] **Mark all today's items with their final status.** No
|
||
|
|
item should be left "in flight" overnight. If a customer can't
|
||
|
|
receive, mark `assigned` (not `delivered`) and add a note.
|
||
|
|
- [ ] **Park any surplus / damage** with the Stock Controller.
|
||
|
|
Don't leave it on the truck.
|
||
|
|
- [ ] **Sync the app** — verify all photos uploaded, all
|
||
|
|
confirmations saved. Mobile data can be patchy; the sync
|
||
|
|
indicator in the top-right is the truth.
|
||
|
|
|
||
|
|
### Every Monday morning
|
||
|
|
|
||
|
|
- [ ] **Review your KPIs** (see §4). Look at last week's
|
||
|
|
collection rate, on-time rate, and error rate.
|
||
|
|
- [ ] **Walk the truck.** Inventory the packing materials,
|
||
|
|
reusable crates, etc. Report any missing.
|
||
|
|
|
||
|
|
### Every Friday afternoon
|
||
|
|
|
||
|
|
- [ ] **Triage any open collections** — items still
|
||
|
|
`collection_pool` over the weekend are at risk of supplier
|
||
|
|
closure or customer cancellation. Flag to the Order Operator.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Step-by-Step Procedures
|
||
|
|
|
||
|
|
### 2.1 View your assigned run
|
||
|
|
|
||
|
|
**When:** you arrive for your shift.
|
||
|
|
|
||
|
|
1. Open WFDASHDRIVER-APP.
|
||
|
|
2. Tap **Today's Run**. You see a list grouped by supplier, in
|
||
|
|
the order the Order Operator suggested (usually optimised by
|
||
|
|
proximity — see `/collection-map`).
|
||
|
|
3. For each supplier, you see:
|
||
|
|
- Supplier name, address, contact.
|
||
|
|
- Items to collect, with qty + description.
|
||
|
|
- The PO number (so the supplier can match).
|
||
|
|
- Any special instructions.
|
||
|
|
|
||
|
|
**If you need to re-order the run:** tap the supplier row,
|
||
|
|
**Re-order**. The Order Operator gets a notification.
|
||
|
|
|
||
|
|
### 2.2 Navigate to a supplier
|
||
|
|
|
||
|
|
**When:** you're at the first pickup.
|
||
|
|
|
||
|
|
1. Tap the supplier row in the app.
|
||
|
|
2. Tap **Navigate**. The app opens your default maps app with
|
||
|
|
the supplier's address.
|
||
|
|
3. **If the address is wrong:** tap **Report Wrong Address** on
|
||
|
|
the supplier row. Don't try to find the supplier yourself —
|
||
|
|
the Order Operator needs to fix the master data.
|
||
|
|
|
||
|
|
### 2.3 Confirm collection (the happy path)
|
||
|
|
|
||
|
|
**When:** you arrive at the supplier and the order is ready.
|
||
|
|
|
||
|
|
1. Tap **Confirm Collection** on the supplier row.
|
||
|
|
2. The app shows each line item. For each:
|
||
|
|
- **Scan the barcode** if the supplier labels have them
|
||
|
|
(faster, more accurate). The app matches against the
|
||
|
|
expected SKU.
|
||
|
|
- **Or tap to mark received** if no barcode.
|
||
|
|
3. If the supplier gave you a delivery note / invoice (paper
|
||
|
|
or PDF), tap **Attach**. Photograph it. The app stores it
|
||
|
|
with the standard `supplier_invoice_` filename prefix.
|
||
|
|
4. **Review the totals** at the bottom. The qty received should
|
||
|
|
match the qty ordered.
|
||
|
|
5. Tap **Submit**. The order items flip to `collected` and
|
||
|
|
the supplier invoice is attached to the PO.
|
||
|
|
|
||
|
|
**Don't:**
|
||
|
|
- Don't submit without attaching the supplier's invoice. The
|
||
|
|
Order Operator needs it to do the diff/receive.
|
||
|
|
- Don't submit with the wrong qty. If the supplier shorted
|
||
|
|
you, see §3.1.
|
||
|
|
|
||
|
|
### 2.4 Confirm a partial collection
|
||
|
|
|
||
|
|
**When:** the supplier delivered less than ordered.
|
||
|
|
|
||
|
|
1. Follow §2.3 up to step 3.
|
||
|
|
2. For each line, enter the **actual qty received** (not the
|
||
|
|
full qty). The app shows the difference.
|
||
|
|
3. In the **Note** field, write the reason ("supplier short by
|
||
|
|
2, ETA TBD" or "supplier out of stock on this SKU").
|
||
|
|
4. Continue. Tap **Submit**.
|
||
|
|
5. The items flip to `collected` with `qty_collected` set to
|
||
|
|
the partial amount. The Order Operator creates a
|
||
|
|
continuation order for the missing qty (see Order Operator
|
||
|
|
§2.6).
|
||
|
|
|
||
|
|
### 2.5 Report a wrong / damaged item
|
||
|
|
|
||
|
|
**When:** the supplier gave you the wrong item, or it's damaged.
|
||
|
|
|
||
|
|
1. **Don't accept the goods** (refuse at the supplier).
|
||
|
|
2. In the app, on the line, tap **Report Problem**.
|
||
|
|
3. Choose: `wrong_item`, `damaged`, `expired`, or `other`.
|
||
|
|
4. **Take photos** — at least 2 (whole item + close-up of the
|
||
|
|
problem). The app attaches them with a `damage_` or
|
||
|
|
`wrong_item_` filename prefix.
|
||
|
|
5. Add a note explaining the situation.
|
||
|
|
6. **Get the supplier's rep to sign** the delivery note with
|
||
|
|
the discrepancy. Photograph the signed note.
|
||
|
|
7. Tap **Submit**. The item stays in `collection_pool` (not
|
||
|
|
flipped to `collected`). The Order Operator handles the
|
||
|
|
dispute.
|
||
|
|
|
||
|
|
### 2.6 Deliver to a customer
|
||
|
|
|
||
|
|
**When:** you're at the customer's site with their order.
|
||
|
|
|
||
|
|
1. Tap the order row in the app.
|
||
|
|
2. Tap **Confirm Delivery**.
|
||
|
|
3. **For each line:**
|
||
|
|
- **Mark delivered** (qty matches).
|
||
|
|
- Or **partial delivery** (customer accepts less — see §3.4).
|
||
|
|
- Or **refused** (customer won't accept — see §3.5).
|
||
|
|
4. **Take a photo of the delivered goods** at the customer's
|
||
|
|
site (best practice for disputes).
|
||
|
|
5. **Get the customer's signature.** The app captures the
|
||
|
|
signature on screen. Alternatively, photograph the signed
|
||
|
|
waybill.
|
||
|
|
6. Tap **Submit**. Items flip to `delivered`.
|
||
|
|
|
||
|
|
**Don't:**
|
||
|
|
- Don't deliver without a signature / photo. A "delivered"
|
||
|
|
item without proof is a dispute magnet.
|
||
|
|
|
||
|
|
### 2.7 Report a surplus
|
||
|
|
|
||
|
|
**When:** the supplier gave you MORE than ordered (e.g. 12
|
||
|
|
instead of 10).
|
||
|
|
|
||
|
|
1. Follow §2.3, but for the over-delivered qty, tap **Surplus**.
|
||
|
|
2. Enter the surplus qty (e.g. 2).
|
||
|
|
3. The system splits the line: customer qty (10) stays on
|
||
|
|
the order, surplus qty (2) is booked to stock. A
|
||
|
|
`stock_ledger` entry is written with
|
||
|
|
`reason: "purchase_surplus"`.
|
||
|
|
4. Continue with §2.3 for the rest.
|
||
|
|
|
||
|
|
### 2.8 Hand off a damaged delivery to stock
|
||
|
|
|
||
|
|
**When:** a customer refuses damaged goods on arrival.
|
||
|
|
|
||
|
|
1. Take photos at the customer's site (see §2.5).
|
||
|
|
2. Get the customer's signature on the refusal note.
|
||
|
|
3. Bring the goods back to the office. **Don't** book them to
|
||
|
|
stock yourself — hand to the Stock Controller. They'll
|
||
|
|
inspect, decide return-to-vendor vs write-off, and book the
|
||
|
|
ledger entry.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Decision Tree
|
||
|
|
|
||
|
|
### 3.1 Supplier short / partial
|
||
|
|
|
||
|
|
```
|
||
|
|
Did the supplier know they were short (pre-called you)?
|
||
|
|
├── Yes → log partial qty, attach their note, submit. Order
|
||
|
|
│ Operator creates the continuation.
|
||
|
|
└── No
|
||
|
|
├── Did they offer a back-order ETA?
|
||
|
|
│ ├── Yes (within 1 week) → take the partial, log the
|
||
|
|
│ │ ETA, Order Operator schedules the back-order.
|
||
|
|
│ └── No / vague → take what they have. Order Operator
|
||
|
|
│ phones the supplier for an ETA, may
|
||
|
|
│ source from a backup.
|
||
|
|
└── Is the partial critical (customer waiting, no
|
||
|
|
substitute)?
|
||
|
|
├── Yes → phone the Order Operator NOW. They may
|
||
|
|
│ source from a backup supplier while you're
|
||
|
|
│ still at the supplier.
|
||
|
|
└── No → take the partial, log it, continue the run.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 Supplier closed / not ready
|
||
|
|
|
||
|
|
```
|
||
|
|
Can you reach the supplier by phone?
|
||
|
|
├── Yes
|
||
|
|
├── "Order not ready, will be in 2 hours" → wait if your
|
||
|
|
│ schedule allows. If not, re-order your run.
|
||
|
|
├── "Order not ready, will be tomorrow" → re-order your
|
||
|
|
│ run, do the other suppliers first. Phone the Order
|
||
|
|
│ Operator if it means the customer won't get it today.
|
||
|
|
└── "Closed for the day" → re-order, mark `assigned` not
|
||
|
|
`collected`, phone the Order
|
||
|
|
Operator.
|
||
|
|
└── No → re-order your run. Phone the Order Operator. Don't
|
||
|
|
wait — every minute parked is a minute not delivering.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.3 Wrong address (supplier or customer)
|
||
|
|
|
||
|
|
```
|
||
|
|
Is the address in the app matching what you see?
|
||
|
|
├── No (typo in the app, building really exists)
|
||
|
|
│ └── Tap **Report Wrong Address**. Don't try to find it
|
||
|
|
│ yourself — the master data needs fixing. Wait for
|
||
|
|
│ the Order Operator.
|
||
|
|
└── The address is right but you can't find the place
|
||
|
|
├── Phone the contact on the row.
|
||
|
|
├── If no answer, ask locals / security.
|
||
|
|
└── If still can't find → mark `assigned`, note "couldn't
|
||
|
|
locate", return to the office. Order Operator
|
||
|
|
resolves.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.4 Customer wants partial delivery (not what we brought)
|
||
|
|
|
||
|
|
```
|
||
|
|
Is the customer a strategic account?
|
||
|
|
├── Yes → call the Order Operator before doing anything. Don't
|
||
|
|
│ make a delivery decision on the customer's porch.
|
||
|
|
└── No
|
||
|
|
├── Will they accept what they need and leave the rest?
|
||
|
|
│ ├── Yes → deliver the partial, note the refused qty
|
||
|
|
│ │ and reason, return the rest to the office.
|
||
|
|
│ └── No (must be all or nothing) → mark `assigned`,
|
||
|
|
│ return the whole
|
||
|
|
│ delivery to the
|
||
|
|
│ office. Phone the
|
||
|
|
│ Order Operator.
|
||
|
|
└── Is the partial a "while you're here" ask (can they
|
||
|
|
take an extra qty)?
|
||
|
|
└── Phone the Order Operator. Don't unilaterally
|
||
|
|
add to the delivery.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.5 Customer refuses (damaged, wrong, "changed my mind")
|
||
|
|
|
||
|
|
```
|
||
|
|
Why are they refusing?
|
||
|
|
├── Damaged → §2.5 / §2.8. Take photos, get signature, return
|
||
|
|
│ to office.
|
||
|
|
├── Wrong item → §2.5. Same process.
|
||
|
|
├── Customer changed mind (no defect)
|
||
|
|
│ ├── Customer pays restocking fee per policy?
|
||
|
|
│ │ ├── Yes → take the refusal, return to office, note
|
||
|
|
│ │ │ the fee on the order.
|
||
|
|
│ │ └── No / unclear → phone the Order Operator. Don't
|
||
|
|
│ │ bring the goods back without
|
||
|
|
│ │ confirming the restocking fee.
|
||
|
|
│ └── Customer wants to keep it but at a discount?
|
||
|
|
│ └── Phone the Order Operator. Don't unilaterally
|
||
|
|
discount.
|
||
|
|
└── Other
|
||
|
|
└── Phone the Order Operator. Get instruction.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.6 Customer not on site when you arrive
|
||
|
|
|
||
|
|
```
|
||
|
|
Have you called ahead?
|
||
|
|
├── Yes (no answer) → wait 15 min. Try again. If still
|
||
|
|
│ nothing, leave a card / note, mark
|
||
|
|
│ `assigned` with "not on site", return
|
||
|
|
│ to office. Order Operator reschedules.
|
||
|
|
└── No → call now. If no answer, same as above.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.7 Truck breakdown / accident
|
||
|
|
|
||
|
|
```
|
||
|
|
Is anyone hurt?
|
||
|
|
├── Yes → emergency services first. Then phone the Order
|
||
|
|
│ Operator. The goods are secondary.
|
||
|
|
└── No
|
||
|
|
├── Is the truck driveable?
|
||
|
|
│ ├── Yes → drive to a safe spot. Phone the Order
|
||
|
|
│ │ Operator. They'll re-assign the rest of
|
||
|
|
│ │ your run to another driver.
|
||
|
|
│ └── No → road service. Phone the Order Operator.
|
||
|
|
│ They'll re-assign.
|
||
|
|
└── Can the goods be salvaged? → assess, take photos,
|
||
|
|
continue if possible.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.8 Bad weather
|
||
|
|
|
||
|
|
```
|
||
|
|
Is the road to the customer / supplier safe?
|
||
|
|
├── No → don't go. Phone the Order Operator. They'll
|
||
|
|
│ re-schedule. Customer/supplier gets a weather
|
||
|
|
│ delay note on the order.
|
||
|
|
└── Yes → continue. Take extra care.
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. KPIs
|
||
|
|
|
||
|
|
All KPIs measured per working day unless noted.
|
||
|
|
|
||
|
|
| KPI | Target | How it's measured |
|
||
|
|
|---|---|---|
|
||
|
|
| **On-time collection rate** | > 90% of `assigned` items `collected` same day | `count(items where item_status=collected AND collected_at date = assigned_at date) / count(assigned items)` |
|
||
|
|
| **On-time delivery rate** | > 95% of `ready_delivery` items `delivered` within the customer-promised window | per-order `delivery_date` vs `delivered_at` |
|
||
|
|
| **Error rate (wrong item / damaged)** | < 2% of line items | `count(items with damage/wrong_item photo attached) / total items handled` |
|
||
|
|
| **Photo proof rate** | 100% of collections + deliveries have at least one photo | `count(photos) / count(items handled)` — should be 1:1 minimum |
|
||
|
|
| **Signature capture rate** | 100% of deliveries have a signature | same as above, for the signature field |
|
||
|
|
| **Surplus booking rate** | 100% of surpluses booked same day | `stock_ledger` entries with `reason="purchase_surplus"` per day vs supplier delivery notes flagged with surplus |
|
||
|
|
| **Refusal rate** | < 3% of attempted deliveries | `count(customer refusals) / count(delivery attempts)` |
|
||
|
|
| **Re-run rate** | < 5% of items needing a second visit | `count(items with 2+ collection attempts)` |
|
||
|
|
| **App sync success** | 100% (all confirmations uploaded by EOD) | `count(items confirmed offline more than 4h) / total items confirmed` — should be zero |
|
||
|
|
| **Cost per collection** | tracked, target stable | total driver cost (incl truck, fuel) / number of collections per month |
|
||
|
|
|
||
|
|
### How KPIs feed into your review
|
||
|
|
|
||
|
|
- **Daily** (end of shift): the app's home screen shows your
|
||
|
|
day's KPI snapshot. If any are red, the supervisor gets an
|
||
|
|
alert.
|
||
|
|
- **Weekly** (Monday standup): one-pager with the week's KPIs.
|
||
|
|
On-time rate and error rate are the headline numbers.
|
||
|
|
- **Monthly** (1st of month): 1-page review with the
|
||
|
|
supervisor. **Photo proof rate and signature capture rate
|
||
|
|
must be 100%** — these are the dispute-defence evidence.
|
||
|
|
Anything below is a process failure.
|
||
|
|
- **Quarterly**: top performers on on-time + zero-error are
|
||
|
|
eligible for the senior-driver tier (they can take the
|
||
|
|
high-value / strategic-account runs).
|
||
|
|
|
||
|
|
### What the system does NOT measure (yet)
|
||
|
|
|
||
|
|
- Customer satisfaction (no NPS yet)
|
||
|
|
- Fuel efficiency per route
|
||
|
|
- Truck wear-and-tear
|
||
|
|
|
||
|
|
If a KPI is unfair, raise it. The supervisor can adjust
|
||
|
|
targets, but the metric stays.
|