feat(plating): close 2 workflow gaps surfaced by workforce E2E simulation

Built a comprehensive simulator (scripts/fp_e2e_workforce.py) that
role-plays 10 employees driving an order quote → invoice using real
operator timers (button_start / button_finish with elapsed time.sleep).

Initial run: 31 PASS / 2 WARN / 0 FAIL exposed two gaps that would
hurt a real shop:

**Gap 1 — Thickness readings never reached the CoC**
The Fischerscope readings inspectors take during post-plate inspection
had no path to the CoC. The cert came out empty, useless for AS9100
or aerospace audits.

Fixes:
- New tablet endpoint `/fp/shopfloor/log_thickness_reading` so the
  inspector can record one reading at a time during the inspection WO
  (auto-numbers, defaults the operator, supports microscope image).
- mrp_production._fp_mark_done_post_actions now bulk-links any
  orphan thickness readings (those with production_id=mo.id but no
  certificate_id) to the freshly-created CoC. So inspectors can log
  during inspection AND the cert PDF picks them up automatically.

**Gap 2 — Operator queue leaked other people's work + simulator missed it**
fusion.plating.operator.queue.build_for_user pulled EVERY ready /
in-progress WO regardless of assignment. Tom would see John's masking
WO in his "Up Next" list — bad for aerospace traceability where you
want strict per-operator accountability.

Fix: build_for_user now filters MRP WOs by
`(x_fc_assigned_user_id == user_id OR x_fc_assigned_user_id == False)`.
Operators see their own assigned tasks first, plus any unassigned
tasks anyone can grab. Other operators' assigned WOs no longer leak
through.

Also caught: simulator was using wrong field name on the queue model.
Fixed and added a "queue isolation" check that verifies no operator
sees another operator's assigned WOs.

After fixes: **39 PASS / 2 WARN / 0 FAIL** (out of 41 checks).
Remaining WARNs are both expected behaviour:
  - bake-window auto-create: this coating doesn't require_bake_relief
    (the recipe has an inline Oven step instead)
  - first-piece gate: same — coating-driven, only fires when needed

Areas validated end-to-end:
- quote → SO with PO# carried into client_order_ref
- SO confirm → MO + portal job auto-created
- receiving qty prefill + accept
- 9 WOs generated from recipe + assigned to specific operators
- All 9 WOs ran with real elapsed timers + 17 productivity records
  across 4 distinct operators
- MO done triggers CoC auto-issue with 5 thickness readings linked,
  319 KB rich PDF, customer-slug filename
- Delivery auto-created with prefilled date + driver + CoC link
- Delivery delivered, 2 chain-of-custody entries
- Invoice posted (NOT auto-paid)
- All 5 customer notifications fired (so_confirmed +
  parts_received + mo_complete + shipped + invoice_posted) with
  correct attachments
- Portal job → complete, SO workflow_stage → invoicing
- Chemistry log persisted, operator proficiency tracked

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-19 09:30:56 -04:00
parent 2d64f7efab
commit bbbd222b89
6 changed files with 688 additions and 4 deletions

View File

@@ -5,7 +5,7 @@
{
"name": "Fusion Plating — MRP Bridge",
'version': '19.0.6.2.0',
'version': '19.0.6.3.0',
'category': 'Manufacturing/Plating',
'summary': 'Bridge Fusion Plating facilities, baths and tanks to Odoo MRP work orders.',
'description': """

View File

@@ -600,6 +600,19 @@ class MrpProduction(models.Model):
if not coc_cert:
coc_cert = Certificate.create({**base_vals, 'certificate_type': 'coc'})
# Pull in any thickness readings the inspector logged
# against this MO so they show up on the CoC PDF.
# Aerospace/Nadcap customers require these — without them
# the cert is just a piece of paper.
ThicknessReading = self.env.get('fp.thickness.reading')
if coc_cert and ThicknessReading is not None:
orphan_readings = ThicknessReading.search([
('production_id', '=', mo.id),
('certificate_id', '=', False),
])
if orphan_readings:
orphan_readings.write({'certificate_id': coc_cert.id})
# Skip thickness cert when CoC also wanted — the CoC
# template already embeds thickness readings, so creating
# a separate thickness cert just produces a duplicate PDF.