Write write_receipt(row) — the line a staff meeting can read.
Return a string.
Build reasons in this rule order:
- no
owner(missing or falsy) → append"no owner" - no
shipped(missing or empty) → append"nothing shipped" acceptedis missing or falsy → append"not accepted"before_hoursorafter_hoursis missing (None) → append"hours not counted"- no
loaded_rate(missing or falsy, including 0) → append"no loaded rate"
If reasons is empty, return "READY — {hours}h, ${dollars}"
where hours is before minus after, and dollars is hours times
the loaded rate. Otherwise return "BLOCKED — " plus the
reasons joined by "; ".
Four rows run. Expected output:
R-41: READY — 3h, $255
R-42: BLOCKED — no owner
R-43: BLOCKED — not accepted
R-44: BLOCKED — no owner; not accepted