fix(shopfloor,reports): make QR scan actually navigate after decode

Two bugs were colluding to make iPhone scans look like "nothing
happens":

1. The in-app scanner was calling action.doAction({res_model: 'fp.job',
   res_id: <decoded-id>}). Old physical stickers (still on every box)
   encode /fp/wo/<mrp.production.id> — that id space doesn't match
   fp.job, so the form opened on a non-existent record and silently
   showed nothing. New /fp/job/<id> stickers happened to work because
   the IDs lined up by coincidence.

2. The /fp/wo/<id> controller redirected to mrp.production / mrp.workorder
   forms, both of which still exist as legacy records but aren't the
   canonical source of truth post-migration.

Fix:
- qr_scanner._handleCode now navigates via window.location.href instead
  of action.doAction. It hands /fp/job/<n> and /fp/wo/<n> URLs straight
  to the existing server-side controllers, which know how to resolve
  the right record. Bare numeric ids pasted manually -> /fp/job/<n>.
  Anything else surfaces the decoded text as an error so the operator
  can see decode worked but the value isn't a sticker.

- Modal now shows "Detected: <value>" the moment a code is decoded
  (before navigation), so even on slow phones the operator sees
  immediate feedback that the camera read the QR.

- wo_scan.py now resolves in this order:
    1. fp.job by legacy_mrp_production_id (migration-aware — old
       stickers route to the new model)
    2. mrp.production direct browse
    3. mrp.workorder direct browse
    4. fall back to /odoo/plating-jobs (or work-orders list)

Versions: shopfloor 19.0.17.0.0 -> 19.0.18.0.0,
          reports   19.0.7.15.0 -> 19.0.7.16.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-25 13:14:06 -04:00
parent ecac43eef4
commit b93633d728
6 changed files with 99 additions and 31 deletions

View File

@@ -22,25 +22,42 @@ class FpWoScanController(http.Controller):
def wo_scan_redirect(self, wo_id, **kwargs):
"""Redirect a scanned sticker to the right backend form.
Stickers are printed from two sources — mrp.workorder (WO) and
mrp.production (MO) — and both embed their own numeric id in
the QR. Try the MO table first (operators live on the MO
form — customer, SO, all WOs visible) and fall back to WO.
Resolution order:
1. fp.job mapped from this MO id via legacy_mrp_production_id
(post-migration: physical stickers still encode the old MO
id, but the canonical record is now an fp.job)
2. mrp.production with this id (pre-migration callers, or if
the legacy mapping wasn't run)
3. mrp.workorder with this id (older stickers that encoded
the WO id rather than the MO id)
4. fall back to the jobs list so staff can search manually.
"""
MO = request.env['mrp.production'].sudo()
WO = request.env['mrp.workorder'].sudo()
env = request.env
mo = MO.browse(wo_id).exists()
# 1) New native model — preferred when migration has run.
if 'fp.job' in env and 'legacy_mrp_production_id' in env['fp.job']._fields:
job = env['fp.job'].sudo().search(
[('legacy_mrp_production_id', '=', wo_id)], limit=1)
if job:
return request.redirect(
'/odoo/action-fusion_plating.action_fp_job/%d' % job.id
)
# 2) Legacy MO form (pre-migration or non-migrated records).
mo = env['mrp.production'].sudo().browse(wo_id).exists()
if mo:
return request.redirect(
'/odoo/action-mrp.mrp_production_action/%d' % mo.id
)
wo = WO.browse(wo_id).exists()
# 3) Legacy WO form.
wo = env['mrp.workorder'].sudo().browse(wo_id).exists()
if wo:
return request.redirect(
'/odoo/action-mrp.action_mrp_workorder/%d' % wo.id
)
# Neither resolved — land on the WO list so staff can search manually.
# 4) Fall back: native jobs list if it exists, otherwise WO list.
if 'fp.job' in env:
return request.redirect('/odoo/plating-jobs')
return request.redirect('/odoo/manufacturing/work-orders')