fix(api): only require notes when the product actually requires them on POST /order/items (#360)
## Bug PR #345 (order_item_reason_policy wiring) accidentally broadened the legacy \`Notes is required for this product\` check to fire for every product whose POST body carried an empty/whitespace \`notes\` field. Mobile POS step 2 always posts the primary product (e.g. Sættevognstræk, product id 3) with \`notes: ''\` as part of \`syncCurrentTransactionToOrder\`. After #345, the API started returning 400 for that primary item. The frontend silently swallowed the 400 in the next-step click handler, and the operator saw **"Fuldfør doesn't continue"** with no feedback. ## Repro 1. Log in to the mobile POS (e.g. dept 12 / Taulov) 2. Scan / type a customer's plates (e.g. EP68666 + GG1876) 3. Long-press Sættevognstræk to add the service 4. Tap **Fuldfør** Before this fix: \`POST /order/items\` → 400 \`Notes is required for this product\`. Frontend catches and logs \`Next-step action was interrupted: AxiosError: Request failed with status code 400\`. Operator sees no error in the UI. After this fix: \`POST /order/items\` → 200 for the primary product; the order completes normally. ## Fix Scope the empty-notes rejection to products whose \`requires_note\` flag (or extraordinary-chemistry special case) is set, matching the existing PUT handler behaviour. Products that don't require notes can post \`notes=''\` without rejection. ## Lock-in tests Two Pest tests under \`Tests\\Api\\OrderItemsApiTest\`: - \`allows empty notes for primary products that do not require a note\` — \`requires_note=0\` product with \`notes=''\` returns 200 - \`still rejects empty notes for products whose requires_note flag is enabled\` — \`requires_note=1\` product with \`notes=' '\` returns 400 with the legacy message ## Verification PHP API suite: **292/292 passing** (11892 assertions). Local \`scripts/php-ci-test.sh api\`. ## Companion PR \`copenhagentruckwash/pleno-vue\` → \`fix/fuldfor-surface-order-item-error\` will surface order-item API errors in the UI so silent failures become visible. That PR is a follow-up; this one is the actual root cause fix. Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
This commit is contained in:
co-authored by
Truck Wash Agent
parent
7174e3be6c
commit
43df3e4dca
@@ -104,18 +104,26 @@ class orderItemsRoute
|
||||
}
|
||||
// Validation order for audited products:
|
||||
// 1. If reason_code is present, run reason validation first (most specific messages).
|
||||
// 2. If notes is provided but empty/whitespace, return "Notes is required" (skip reason).
|
||||
// 3. Otherwise run reason validation (covers missing reason_code and invalid combos).
|
||||
// 2. If the product requires an order-item note and notes are provided but
|
||||
// empty/whitespace, return "Notes is required" (the legacy message). Other products
|
||||
// may carry an empty notes field without rejecting the request.
|
||||
// 3. Otherwise run reason validation (covers missing reason_code on affected products).
|
||||
$reasonFields = ['reason_code' => null, 'reason_label_snapshot' => null, 'reason_comment' => null];
|
||||
$reasonCodeProvided = array_key_exists('reason_code', (array)$data) || array_key_exists('order_item_reason_code', (array)$data);
|
||||
|
||||
$productRequiresOrderItemNote = $product->requiresOrderItemNote();
|
||||
|
||||
if ($reasonCodeProvided) {
|
||||
try {
|
||||
$reasonFields = \classes\order_item_reason_policy::validateForProduct((int)$data['product_id'], $data);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$response->error($e->getMessage(), 400);
|
||||
}
|
||||
} elseif (array_key_exists('notes', (array)$data) && trim((string)($data['notes'] ?? '')) === '') {
|
||||
} elseif (
|
||||
$productRequiresOrderItemNote
|
||||
&& array_key_exists('notes', (array)$data)
|
||||
&& trim((string)($data['notes'] ?? '')) === ''
|
||||
) {
|
||||
$response->error('Notes is required for this product', 400);
|
||||
} else {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user