WFDASHDRIVER-APP/lib/types.ts
Dave 5ef212cdfa docs(pocketbase): clarify driver/drv_id schema — operator app fix needed
Live PB schema probe (2026-08-11) confirmed `driver` and
`item_status="driver_pool"` are not in the schema; referencing
either in a filter hard-400s the whole query. The driver app's
getMyAssignedItems already used the canonical `drv_id` +
`item_status="assigned"` pair, so a defensive OR-fallback against
the missing fields would have BROKEN the query (not rescued it);
that attempt was reverted.

Items 'assigned' by the operator (WFDash) app never reach the
driver's Assigned tab because the operator-side filter still
references those non-existent identifiers. Operator app needs to
filter/write `drv_id` and `item_status="assigned"` instead.

Also restored the dropped OrderItem.expand definition (each
component was accessing item.expand.* unchecked) and widened the
item_status union to include 'invoiced' and 'problem' seen in the
live schema.

Co-authored-by: Orca <help@stably.ai>
2026-08-12 08:04:19 +02:00

217 lines
7.4 KiB
TypeScript

export interface Supplier {
id: string;
suppliername: string;
email: string;
suppliernumber: string;
supplieraddress: string;
supply_tags: string;
coordinates: string; // Raw coordinates text (e.g. "-33.9249, 18.4241")
closingtime: string;
}
export interface Order {
id: string;
order_number: string;
status: string;
notes: string;
}
export interface PurchaseOrder {
id: string;
po_number: string;
status: string;
// Attached PO PDF documents (file field on the purchase_orders PB collection)
documents?: string[];
// Pre-composed email payload (subject, body, to) — driver can resend
// this to the supplier via the "Email PO" button when the supplier
// hasn't received it.
email_payload?: {
to: string;
subject: string;
body: string;
bodyText: string;
cc?: string;
bcc?: string;
};
// Linked supplier (expanded)
expand?: {
supplier?: Supplier;
};
supplier?: string;
total_amount?: number;
order?: string;
order_item?: string;
updated?: string;
}
export interface OrderItem {
id: string;
order: string;
// Customer-facing line. Use this for label / list / customer view.
description: string;
// Supplier-facing line. Use this on the PO pickup screen — supplier
// paperwork references this exact wording. Falls back to description.
po_description?: string;
// Customer-side quantity. Nullable on legacy rows.
quantity: number;
// Supplier-side quantity. Per the brief, falls back to quantity when
// blank (zero is treated as blank in getItemDisplayQty).
order_qty?: number;
// Pricing — operator-side (cost), customer-side (selling), and audit
// source ('quote' | 'catalogue' | 'manual').
cost_price?: number;
selling_price?: number | null;
pricing_source?: 'quote' | 'catalogue' | 'manual' | string;
matched_quote_item?: string;
// Supplier part number. Use this on PO paperwork over description.
sku?: string;
// Workflow states. item_status is the operator-side state, drv_status
// is the driver-side state. They're independent enums — an item can
// be item_status='collected' (operator marked it received) while
// drv_status is still 'en_route' (driver hasn't checked in), etc.
item_status:
| 'pending'
| 'processed'
| 'po_generated'
| 'collection_pool'
| 'assigned'
| 'collected'
| 'stock_verified'
| 'picking'
| 'ready_delivery'
| 'delivered'
| 'cancelled'
| 'invoiced'
| 'problem'
| string;
drv_status?: 'unassigned' | 'assigned' | 'en_route' | 'collected' | 'failed' | string;
driver_status?: string;
delivery_status?: 'pending' | 'ready' | 'in_transit' | 'delivered' | 'failed';
invoice_status?: 'pending' | 'invoiced' | 'paid' | 'cancelled';
// Driver assignment. The canonical driver field per the brief is
// `drv_id` (relation -> users); the older `driver` field is a legacy
// shadow that only a handful of rows set. Use drv_id in every filter.
drv_id?: string;
driver?: string;
// Server-side ISO timestamp of when drv_id was set. Surface in detail.
assigned_at?: string;
// Audit trail of failed-collection attempts. The driver writes here.
// Distinct from notes (operator-side).
notes?: string;
problem_notes?: string;
problem_flag?: boolean;
problem_type?: 'stock' | 'supplier' | 'driver' | 'delivery' | 'pricing' | 'other' | string;
// Expanded relations populated by the PB `expand` query parameter
// (supplier, order, purchase_order). PocketBase attaches this object
// at fetch time; the driver app reads it as `item.expand?.supplier`
// etc. Not a stored column — synthesized client-side.
expand?: {
supplier?: Supplier;
order?: Order;
purchase_order?: PurchaseOrder;
};
// Pickup proof files. Two storage paths exist in PB; the runtime
// currently writes to the legacy file field on the order_items row
// (see `uploadOrderItemAttachment` in pocketbase.ts, which appends
// to `order_item_attachements+` with the `+` so each upload is
// preserved alongside previous ones rather than overwriting). The
// separate `order_item_attachments` collection (one row per file,
// schema documented near the bottom of this file) exists in PB and
// is exercised by the e2e probes, but the driver app does not write
// to it yet — migration is in flight, not complete. The misspelling
// `order_item_attachements` is the literal PB field name; do not
// "fix" it without a coordinated PB migration.
// (The legacy single-photo `collection_photo` slot is also still
// declared on the row but no longer written by the runtime — see
// handleCollect passing `photo: null` for that reason.)
order_item_attachements?: string[];
// Per-row quantities used for proving/dashboard math.
qty_processed?: number;
qty_assigned?: number;
qty_collected?: number;
qty_delivered?: number;
drv_assigned_at?: string;
drv_collected_at?: string;
delivered_at?: string;
markup?: number;
markup_percent?: number;
legacy_order_item_id?: string;
// Backwards-compat shim the app uses in some spots
is_stock_item?: boolean;
collected_date?: string;
collection_date?: string;
}
export interface DriverLocation {
id: string;
// PB schema note (verified live 2026-07-08): the relation field on
// `driver_locations` is named `relation`, NOT `driver`. Earlier docs
// and the type had this as `driver` — every save silently 400'd inside
// a try{}catch{} and the map polyline was always empty.
relation: string;
latitude: number;
longitude: number;
accuracy?: number;
altitude?: number;
speed?: number;
heading?: number;
timestamp: string;
}
// Attached files for a single order_item — photos taken at pickup,
// delivery note scans, supplier-side signed slips, etc. Created
// alongside the order_item row when a driver collects the item and
// optionally attaches a photo. Mirrors the `quote_item_attachments`
// schema (one row per file, parent via relation).
//
// PB collection verified 2026-07-07: order_item_attachments
// - order_item : relation -> order_items (cascadeDelete, required)
// - filename : text (required, max 500)
// - file : file (image/* + application/pdf, 20MB max)
// - content_type : text (optional, e.g. "image/jpeg")
// - size_bytes : number (optional)
// - source : select (driver_proof | operator_proof | manual)
// - notes : text (optional)
// - uploaded_at : autodate (server-side)
export type AttachmentSource = 'driver_proof' | 'operator_proof' | 'manual';
export interface OrderItemAttachment {
id: string;
order_item: string;
filename: string;
file: string;
content_type?: string;
size_bytes?: number;
source: AttachmentSource;
notes?: string;
uploaded_at: string;
expand?: {
order_item?: OrderItem;
};
}
export interface AppSettings {
locationInterval: number;
minimumAccuracy: number;
enableHighAccuracy: boolean;
darkMode: boolean;
fontSize: 'small' | 'normal' | 'large';
offlineMode: boolean;
}
export const DEFAULT_SETTINGS: AppSettings = {
locationInterval: 60,
minimumAccuracy: 50,
enableHighAccuracy: true,
darkMode: false,
fontSize: 'normal',
offlineMode: false,
};
export const PROBLEM_TYPES = [
{ value: 'out_of_stock', label: 'Out of Stock' },
{ value: 'partial_stock', label: 'Partial Stock' },
{ value: 'quality_issue', label: 'Quality Issue' },
{ value: 'wrong_item', label: 'Wrong Item' },
{ value: 'other', label: 'Other' },
] as const;