From 27af984f28c0404e87713b91bc98f745799360bc Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 26 May 2026 21:22:43 -0400 Subject: [PATCH] docs(configurator): E1 - Express Orders smoke test runbook --- .../docs/express_orders_smoke_test.md | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 fusion_plating/fusion_plating_configurator/docs/express_orders_smoke_test.md diff --git a/fusion_plating/fusion_plating_configurator/docs/express_orders_smoke_test.md b/fusion_plating/fusion_plating_configurator/docs/express_orders_smoke_test.md new file mode 100644 index 00000000..f3f6fa9c --- /dev/null +++ b/fusion_plating/fusion_plating_configurator/docs/express_orders_smoke_test.md @@ -0,0 +1,235 @@ +# Express Orders — Smoke Test Runbook + +End-to-end manual checks for the Express Orders feature. Run after every deploy that touches `fusion_plating_configurator`, `fusion_plating_jobs`, or `fusion_plating`. Expect ~10 minutes if everything works; longer if a test fails and you have to dig into logs. + +Spec: [docs/superpowers/specs/2026-05-26-express-orders-design.md](../../docs/superpowers/specs/2026-05-26-express-orders-design.md) +Plan: [docs/superpowers/plans/2026-05-26-express-orders-plan.md](../../docs/superpowers/plans/2026-05-26-express-orders-plan.md) + +--- + +## Setup + +1. Open Odoo (entech: https://erp.enplating.com, local: http://localhost:8069) +2. Log in as a user with the Estimator role +3. Navigate to: **Plating → Sales → + New Express Order** +4. Confirm the Express form opens (NOT the legacy form). The header should say "Express Order Entry" and there should be a "Switch to Legacy View" button. + +If the menu is missing or the wrong form opens, the deploy didn't land correctly. Check the manifest's `data` list includes `views/fp_express_order_views.xml`. + +--- + +## Test 1 — Happy path with mask ON + bake non-empty + +Goal: confirm the SO → job → step pipeline works for the simplest case (everything on). + +1. Pick customer **WESTIN HEALTHCARE INC.** (or any partner with at least one part in the catalog) +2. Confirm `partner_shipping_id` auto-fills to the customer's first child address +3. Confirm `pricelist_id` defaults to the customer's pricelist (currency pill should match) +4. Type PO# **`PO-SMOKE-01`** and upload any PDF +5. Add a line: pick a part with a recipe. Auto-fill should populate description / thickness / process / masking checkbox (on) / bake text (from the part's defaults) +6. Set quantity **5**, price **42.00** +7. Click **Confirm Order** + +Expected: +- A `sale.order` is created in `quotation` state +- The wizard transitions to `confirmed` +- The "Open Sale Order" button appears +- Clicking it opens the SO with the lines you entered + +Verify via SQL (entech LXC 111): +```bash +ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT id, name, partner_id, state FROM sale_order WHERE x_fc_po_number = '\''PO-SMOKE-01'\'';\""' +``` + +--- + +## Test 2 — Masking opt-out + +Goal: unchecking masking on a line should spawn override rows for masking + de_masking nodes. + +1. Repeat Test 1 setup with a fresh PO# `PO-SMOKE-02` +2. **Uncheck the Mask toggle on the line** +3. Set bake to a non-empty text (e.g. `350F x 4hr`) so bake doesn't also opt out +4. Confirm Order +5. The SO confirms; an `fp.job` should be auto-created. Find it via: + ```bash + ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT j.id, j.name FROM fp_job j JOIN sale_order so ON j.sale_order_id=so.id WHERE so.x_fc_po_number='\''PO-SMOKE-02'\'';\""' + ``` + +Expected: +- `fp.job.node.override` rows exist with `included=False` for the recipe's masking + de_masking nodes: + ```bash + ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT ov.id, n.name, n.default_kind, ov.included FROM fp_job_node_override ov JOIN fusion_plating_process_node n ON ov.node_id=n.id WHERE ov.job_id=;\""' + ``` +- Open the job in the UI. The audit chatter should contain: **"Masking + de-masking steps opted out (per SO line)"** + +--- + +## Test 3 — Bake opt-out + +Goal: emptying the bake cell should spawn an override for the recipe's baking node. + +1. Fresh order with PO# `PO-SMOKE-03` +2. Keep Mask checked +3. **Clear the Bake cell** (the value should be empty / "no bake") +4. Confirm Order +5. Verify the resulting `fp.job` has `fp.job.node.override` row(s) for nodes with `default_kind='baking'`, `included=False` +6. Audit chatter on the job: **"Baking steps opted out (per SO line)"** + +--- + +## Test 4 — Bake instructions write through to step + +Goal: typed bake instructions should appear on the operator tablet's bake step. + +1. Fresh order with PO# `PO-SMOKE-04` +2. Set bake to **`375F x 2hr`** on the line +3. Confirm Order +4. **Assign To Me** on the resulting SO (this calls `fp.job.action_confirm` which generates steps) +5. Open the job's step list; find the step with `recipe_node_id.default_kind='baking'` + +Expected: +- The bake step's `instructions` field reads **`375F x 2hr`** +- Audit chatter: **"Bake step instructions set to: 375F x 2hr"** + +Verify via SQL: +```bash +ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT s.id, s.name, s.instructions FROM fp_job_step s JOIN fusion_plating_process_node n ON s.recipe_node_id=n.id WHERE n.default_kind='\''baking'\'' AND s.job_id=;\""' +``` + +--- + +## Test 5 — Part-default write-back + +Goal: values typed on the line should persist to the part's defaults for next time. + +1. Pick a part that has NO `default_bake_instructions` set yet +2. Type bake `400F x 1hr` and Specification `Per drawing rev C, mirror finish` +3. Confirm Order +4. Reload the part record: + ```bash + ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT part_number, default_bake_instructions, default_specification_text, default_masking_enabled FROM fp_part_catalog WHERE id=;\""' + ``` + +Expected: +- `default_bake_instructions = '400F x 1hr'` +- `default_specification_text = 'Per drawing rev C, mirror finish'` +- `default_masking_enabled` matches what was on the line + +Next, fresh order with the SAME part: +- Auto-fill should pre-populate the bake + specification cells from the part defaults + +--- + +## Test 6 — Customer line ref (ABC/DEF/GHJ) + +Goal: per-line customer reference persists to the SO line and prints on docs. + +1. Fresh order with 2 lines +2. Type `ABC` in Line Job # on line 1, `DEF` on line 2 +3. Confirm Order +4. Open the resulting SO; the two lines should have the same Line Job # values +5. Print the Sale Order PDF — the Customer Line Job # should appear in the line table column + +Verify via SQL: +```bash +ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \"SELECT id, x_fc_customer_line_ref FROM sale_order_line WHERE order_id=;\""' +``` + +--- + +## Test 7 — Bulk-add serials (existing wizard, new trigger) + +Goal: confirm the `+ bulk` button on the part cell's serial row opens the bulk-add wizard. + +1. Open a draft Express Order. Pick a part on a line. +2. (v1 deferment: the inline `+ bulk` button isn't on the form yet — this test currently has to use the standard Serials field directly. Skip until C polish lands.) + +--- + +## Test 8 — DWG / OPEN buttons per line + +Goal: drawings upload to the part record, OPEN navigates to the part form. + +(v1 deferment: not on the form yet — comes in C polish.) + +--- + +## Test 9 — Currency switch + +Goal: changing the pricelist updates the currency pill and triggers a price recompute prompt. + +1. Open a draft. Pricelist defaults to CAD. +2. Add a line at $42.00 CAD. +3. Switch the Pricelist to a USD pricelist. +4. Odoo prompts: **"Update Prices?"** Click Yes. + +Expected: +- The line's `unit_price` recomputes via the USD pricelist's rules +- The Grand Total currency pill flips to USD +- The line subtotal shows in USD + +If you don't have a USD pricelist, this test can't run — confirm with admin that at least one alternative-currency pricelist exists. + +--- + +## Test 10 — Round-trip with legacy view + +Goal: Express drafts open in Express, Legacy drafts open in Legacy, but each can be flipped via the header button. + +1. Create a draft in Express (PO `PO-SMOKE-10A`, don't confirm — just save) +2. Go to **Plating → Sales → Direct Order Drafts** +3. The list shows a `view_source` badge column. Your draft has `EXPRESS` (blue). +4. Click the **Open** button on the row → confirm it opens in Express +5. From the Express form, click **Switch to Legacy View** → confirms legacy form loads with same data +6. Back to drafts list. Click Open again — should re-route to Legacy (because the draft's `view_source` is now... wait, the switch button doesn't change `view_source`, just temporarily renders in a different view. So Open should still go to Express.) + +Verify behaviour above. Then: +7. From **Plating → Sales → + New Direct Order (Legacy)**, create a draft. Save without confirming. +8. Open the drafts list: this draft has `view_source = LEGACY` (muted badge). +9. Click Open → legacy form opens. + +--- + +## Quick PG verification — every Express field + +After deploy, confirm all 17 new schema fields are present: + +```bash +ssh pve-worker5 'pct exec 111 -- bash -c "cd /tmp && sudo -u postgres psql -d admin -t -c \" +SELECT table_name, column_name FROM information_schema.columns WHERE + (table_name=\\\"fp_part_catalog\\\" AND column_name IN (\\\"default_specification_text\\\",\\\"default_bake_instructions\\\",\\\"default_masking_enabled\\\")) OR + (table_name=\\\"sale_order_line\\\" AND column_name IN (\\\"x_fc_customer_line_ref\\\",\\\"x_fc_masking_enabled\\\",\\\"x_fc_bake_instructions\\\")) OR + (table_name=\\\"sale_order\\\" AND column_name IN (\\\"x_fc_material_process\\\",\\\"x_fc_internal_notes\\\",\\\"x_fc_print_terms\\\")) OR + (table_name=\\\"fp_direct_order_wizard\\\" AND column_name IN (\\\"terms_and_conditions\\\",\\\"internal_notes\\\",\\\"material_process\\\",\\\"pricelist_id\\\",\\\"validity_date\\\",\\\"view_source\\\")) OR + (table_name=\\\"fp_direct_order_line\\\" AND column_name IN (\\\"customer_line_ref\\\",\\\"masking_enabled\\\",\\\"bake_instructions\\\")) +ORDER BY table_name, column_name; +\""' +``` + +Expected: 17 rows. If fewer, the upgrade didn't fully land — re-run the canonical CLAUDE.md upgrade command. + +--- + +## Common failure modes + +| Symptom | Likely cause | Fix | +|---|---|---| +| Menu "+ New Express Order" doesn't appear | manifest doesn't include `views/fp_express_order_views.xml`, OR module wasn't upgraded | Check manifest data list; re-run `-u fusion_plating_configurator` | +| Form opens but bake/masking columns are empty | onchange `_onchange_part_default_thickness` didn't fire | Check `fp.direct.order.line.bake_instructions` field exists; check the onchange extension landed | +| Confirm Order errors with `KeyError: 'x_fc_masking_enabled'` | `sale.order.line` field missing | Re-run module upgrade | +| Job created but no override rows | `_fp_auto_create_job` hook missing | Check `fusion_plating_jobs/models/sale_order.py` for the Express overrides block after `Job.create(vals)` | +| Override rows present but bake step.instructions empty | The second hook (in `fp.job.action_confirm`) didn't fire, OR steps weren't generated yet | Check `fusion_plating_jobs/models/fp_job.py` for the Express block after `_generate_steps_from_recipe()` | +| Customer line ref blank on SO line | `_prepare_order_line_vals` carry-through missing | Check `fp_direct_order_wizard.py` for `x_fc_customer_line_ref` in the `so_vals['order_line'].append` block | + +--- + +## Deploy command (canonical CLAUDE.md pattern) + +```bash +ssh pve-worker5 "pct exec 111 -- bash -c 'systemctl stop odoo && su - odoo -s /bin/bash -c \"/usr/bin/odoo -c /etc/odoo/odoo.conf -d admin -u fusion_plating_configurator,fusion_plating_jobs,fusion_plating --stop-after-init\" > /tmp/odoo-up.log 2>&1; systemctl start odoo; tail -25 /tmp/odoo-up.log'" +``` + +Expected: 20-30 seconds, exit 0, log ends with **"Modules loaded."** + +Do NOT add `--test-enable` — it caused a 20-minute hang during the original deploy by getting tangled with production HTTP traffic. Run tests separately if needed (`--no-http --test-enable --test-tags fp_express`).