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>
64 lines
2.5 KiB
Python
64 lines
2.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Plating product family.
|
|
#
|
|
# /fp/wo/<id> — scan-redirect endpoint.
|
|
#
|
|
# The WO box sticker embeds a QR code that encodes this URL. When
|
|
# warehouse staff scan the sticker with their phone / tablet /
|
|
# handheld scanner, the device opens the URL; this controller then
|
|
# redirects them to the work-order form inside Odoo's backend.
|
|
# Logged-out users land on the standard Odoo login page and bounce
|
|
# back after authenticating (Odoo's redirect handles the round-trip).
|
|
|
|
from odoo import http
|
|
from odoo.http import request
|
|
|
|
|
|
class FpWoScanController(http.Controller):
|
|
|
|
@http.route('/fp/wo/<int:wo_id>', type='http', auth='user', website=False)
|
|
def wo_scan_redirect(self, wo_id, **kwargs):
|
|
"""Redirect a scanned sticker to the right backend form.
|
|
|
|
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.
|
|
"""
|
|
env = request.env
|
|
|
|
# 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
|
|
)
|
|
|
|
# 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
|
|
)
|
|
|
|
# 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')
|