docs(configurator): E1 - Express Orders smoke test runbook
This commit is contained in:
@@ -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=<job-id-from-above>;\""'
|
||||
```
|
||||
- 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=<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=<part-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=<so-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`).
|
||||
Reference in New Issue
Block a user