docs: clarify customer non-nullable, full-order scope, collision link, partial-fail UX
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
20533bcddf
commit
03ca2c8d29
1 changed files with 7 additions and 5 deletions
|
|
@ -113,10 +113,10 @@ Same size + ghost-icon styling as `ExternalLink`. Tinted warn-amber. Tooltip: "R
|
|||
|
||||
### Behavior details
|
||||
|
||||
- **Editability** — every numeric cell in the order items table is an `Input`. The `selling_price` ↔ `cost_price` pair uses the lock-pattern from `SprintItemPricingModal` (type into one, the other recomputes via `markup`). Quantity is a plain integer input. `description` and `po_description` are read-only here (edits live on the order detail page).
|
||||
- **Editability** — every numeric cell in the order items table is an `Input`. The `selling_price` ↔ `cost_price` pair uses the lock-pattern from `SprintItemPricingModal` (type into one, the other recomputes via `markup`). Quantity is a plain integer input. `description` and `po_description` are read-only here (edits live on the order detail page). The modal shows **all line items** for the order regardless of which tab the operator came from — the review is always whole-order, never tab-filtered.
|
||||
- **Dirty state** — the modal tracks a `dirty: Set<"number" | "customer" | "items">` so Save is disabled until at least one field changes. Cancel and Esc discard changes without confirmation if nothing's dirty; if dirty, show a confirm-discard dialog.
|
||||
- **Save flow** — POST to `/api/v1/orders/[id]/review-save` with `{ order_number?, customer?, items?: [{ id, quantity?, selling_price?, cost_price? }] }`. The route returns 200 on success, 409 on number collision (with the colliding order id), or 4xx with a message on validation failure.
|
||||
- **Number collision error** — rendered inline beneath the order-number input: "ORD-2026-07-014 is already used by another order." Modal stays open, no fields lost.
|
||||
- **Number collision error** — rendered inline beneath the order-number input: `"ORD-2026-07-014 is already used by another order."` The colliding order id is rendered as a link to `/orders/<id>` so the operator can jump straight to the existing row and decide what to do (merge, re-rename the new one, etc.). Modal stays open, no fields lost.
|
||||
- **Realtime collision** — if PB fires an `orders` or `order_items` write while the modal is open, the modal keeps its own dirty state and refetches on close. The card behind the modal updates via the existing subscription; reopening the modal re-fetches fresh data.
|
||||
- **No source email** (order not from a quote) — right pane shows "No source email — this order wasn't created from a quote." Edits still work; nothing to preview.
|
||||
|
||||
|
|
@ -139,10 +139,12 @@ Two new functions in `src/lib/server/orders-service.ts` (the existing data-layer
|
|||
```ts
|
||||
export async function updateOrderReviewFields(
|
||||
orderId: string,
|
||||
patch: { order_number?: string; customer?: string | null },
|
||||
patch: { order_number?: string; customer?: string },
|
||||
): Promise<Order>
|
||||
```
|
||||
|
||||
`customer` is non-nullable here on purpose: the `orders.customer` field is a required relation, and the operator is choosing among real PB customer rows in the `CustomerSearch` combobox. Sending `null` would be a 400 from PB; the route handler enforces this so the modal can never accidentally clear the relation.
|
||||
|
||||
- If `order_number` is set and differs from the current value, query `pb.collection("orders").getList(1, 1, { filter: \`order_number = "${newNumber}" && id != "${orderId}"\` })`. If any row matches, throw `OrderNumberCollisionError` carrying the colliding order id.
|
||||
- Else PATCH the order with the supplied fields via `pb.collection("orders").update(orderId, patch)`.
|
||||
- Return the updated `Order`.
|
||||
|
|
@ -178,7 +180,7 @@ Request body:
|
|||
```ts
|
||||
{
|
||||
order_number?: string;
|
||||
customer?: string | null;
|
||||
customer?: string;
|
||||
items?: Array<{
|
||||
id: string;
|
||||
quantity?: number | null;
|
||||
|
|
@ -213,7 +215,7 @@ Use `getAdminPocketBase()` for writes (mirrors the existing `orders-service.ts`
|
|||
|-------------------------------|----------------------|----------------------------------------------------------------------|
|
||||
| Number already used | Route handler | Inline error under order_number input; modal stays open |
|
||||
| PB validation error on PATCH | Service layer | Toast with the PB error message; modal stays open |
|
||||
| Partial item PATCH failure | Service layer | Toast: "Saved N items, M failed"; modal closes; failed items list |
|
||||
| Partial item PATCH failure | Service layer | Toast: "Saved N items, M failed"; modal stays open; failed item ids shown beneath the items table so the operator can retry |
|
||||
| Network failure on Save click | Client (try/catch) | Toast: "Save failed"; modal stays open; no fields lost |
|
||||
| Realtime update during modal | Client (refetch) | Modal keeps dirty state; underlying card updates; reopen re-fetches |
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue