From 7c3b8f642afcbe8ab3587cb973f08f4c8bf32b37 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 16:14:29 +0200 Subject: [PATCH] docs(stock): bulk cap 100 + clarify selling-derive precedence --- .../specs/2026-08-31-stock-pricing-inline-edit-design.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/superpowers/specs/2026-08-31-stock-pricing-inline-edit-design.md b/docs/superpowers/specs/2026-08-31-stock-pricing-inline-edit-design.md index 27ccc99..b33e65c 100644 --- a/docs/superpowers/specs/2026-08-31-stock-pricing-inline-edit-design.md +++ b/docs/superpowers/specs/2026-08-31-stock-pricing-inline-edit-design.md @@ -25,7 +25,7 @@ Editing cost must keep the audit trail honest: when `cost_price` is patched by h 2. **Click "Missing pricing only"** (filter toggle). The list collapses to rows with `selling_price = 0 AND cost_price = 0`. The header subtitle updates to *"N items need pricing"*. 3. **Click "Show pricing columns"** (header toggle). The table grows three right-aligned columns: **Cost (R)**, **Markup %**, **Selling (R)**. Each cell reads either the current numeric value or "—" if zero. 4. **Click "Edit pricing"** (header toggle). The toggle label flips to *"Done editing"*. Every pricing cell across the filtered list becomes a number input. Rows the operator hasn't touched look exactly like read-only values (numbers visible, no input chrome). Every row the operator changes gets a yellow background tint. -5. **Operator edits values.** Cost and markup inputs trigger a derived recompute of selling when both are present: `selling = round(cost × (1 + markup / 100), 2)`. The operator can also type selling directly to override the derived value. +5. **Operator edits values.** When the operator types into Cost or Markup, Selling auto-derives to `round(cost × (1 + markup / 100), 2)` — but only if the operator has NOT manually edited Selling for that row in the current edit-pass. The "Selling manually edited" flag is per-row, reset on row-blur or Apply. If the operator clicks into Selling and types, Selling locks to their value and stops deriving until the row is re-focused or Apply is run. 6. **Local draft persists.** Each keystroke serialises the staged changes into `localStorage` under the key `wfdash.stock.pricingDraft`. A page refresh after a long edit session preserves the work. 7. **Operator clicks "Apply changes"** in the sticky footer. One POST to `/api/v1/stock/items/set-pricing` ships the delta. On success the table re-renders with the new values, the draft clears, the footer disappears. 8. **Per-row outcome.** If a single row fails (PB validation, etc.), that row stays tinted with a red corner badge; the others persist. A toast summarises *"Saved N rows — M failed, click row to retry"*. @@ -148,6 +148,7 @@ Behaviours: Reject 400 when: - `updates` is empty, missing, or not an array. +- `updates.length > 100` (matches `bulk_update_quote_items` cap; the page slices if more). - Any `update` has keys outside `{ id, costPrice, sellingPrice, markup }`. - Any `update` has `id` empty or not 15-char PB id. - Numeric fields not finite / negative.