cleanup(shopfloor): strip tablet_tech_id from 17 endpoints

Session swap makes attribution automatic via request.env.user — the
tablet_tech_id plumbing is dead code after the kiosk + per-tech-session
architecture lands. Removed kwarg from 3 endpoints in
manager_controller, 11 in shopfloor_controller, 3 in
workspace_controller. _tablet_audit.env_for_tablet_tech import gone
from all 3 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-24 14:29:51 -04:00
parent 2a93ece4ba
commit 3120612e35
3 changed files with 34 additions and 47 deletions

View File

@@ -25,8 +25,6 @@ from odoo import fields, http
from odoo.addons.fusion_plating.models.fp_tz import fp_format from odoo.addons.fusion_plating.models.fp_tz import fp_format
from odoo.http import request from odoo.http import request
from ._tablet_audit import env_for_tablet_tech
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -390,7 +388,7 @@ class FpManagerDashboardController(http.Controller):
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@http.route('/fp/manager/assign_worker', type='jsonrpc', auth='user') @http.route('/fp/manager/assign_worker', type='jsonrpc', auth='user')
def assign_worker(self, step_id=None, user_id=None, workorder_id=None, def assign_worker(self, step_id=None, user_id=None, workorder_id=None,
tablet_tech_id=None, **kwargs): **kwargs):
"""Assign an operator to a step. ``step_id`` is the canonical """Assign an operator to a step. ``step_id`` is the canonical
kwarg; ``workorder_id`` is accepted as a deprecated alias for kwarg; ``workorder_id`` is accepted as a deprecated alias for
one release so any caller we missed doesn't break. one release so any caller we missed doesn't break.
@@ -403,7 +401,7 @@ class FpManagerDashboardController(http.Controller):
step_id = workorder_id step_id = workorder_id
if not step_id: if not step_id:
return {'ok': False, 'error': 'step_id required'} return {'ok': False, 'error': 'step_id required'}
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
step = env['fp.job.step'].browse(int(step_id)) step = env['fp.job.step'].browse(int(step_id))
if not step.exists(): if not step.exists():
return {'ok': False, 'error': 'Step not found.'} return {'ok': False, 'error': 'Step not found.'}
@@ -420,7 +418,7 @@ class FpManagerDashboardController(http.Controller):
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@http.route('/fp/manager/assign_tank', type='jsonrpc', auth='user') @http.route('/fp/manager/assign_tank', type='jsonrpc', auth='user')
def assign_tank(self, step_id=None, tank_id=None, workorder_id=None, def assign_tank(self, step_id=None, tank_id=None, workorder_id=None,
tablet_tech_id=None, **kwargs): **kwargs):
"""Swap the tank on a step. ``step_id`` is the canonical kwarg; """Swap the tank on a step. ``step_id`` is the canonical kwarg;
``workorder_id`` is accepted as a deprecated alias. ``workorder_id`` is accepted as a deprecated alias.
""" """
@@ -432,7 +430,7 @@ class FpManagerDashboardController(http.Controller):
step_id = workorder_id step_id = workorder_id
if not step_id: if not step_id:
return {'ok': False, 'error': 'step_id required'} return {'ok': False, 'error': 'step_id required'}
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
step = env['fp.job.step'].browse(int(step_id)) step = env['fp.job.step'].browse(int(step_id))
if not step.exists(): if not step.exists():
return {'ok': False, 'error': 'Step not found.'} return {'ok': False, 'error': 'Step not found.'}
@@ -448,8 +446,7 @@ class FpManagerDashboardController(http.Controller):
# Manager takes over a step (no-show coverage) # Manager takes over a step (no-show coverage)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@http.route('/fp/manager/take_over', type='jsonrpc', auth='user') @http.route('/fp/manager/take_over', type='jsonrpc', auth='user')
def take_over(self, step_id=None, workorder_id=None, def take_over(self, step_id=None, workorder_id=None, **kwargs):
tablet_tech_id=None, **kwargs):
"""Manager takes over a step. ``step_id`` is the canonical kwarg; """Manager takes over a step. ``step_id`` is the canonical kwarg;
``workorder_id`` is accepted as a deprecated alias. ``workorder_id`` is accepted as a deprecated alias.
""" """
@@ -461,7 +458,7 @@ class FpManagerDashboardController(http.Controller):
step_id = workorder_id step_id = workorder_id
if not step_id: if not step_id:
return {'ok': False, 'error': 'step_id required'} return {'ok': False, 'error': 'step_id required'}
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
step = env['fp.job.step'].browse(int(step_id)) step = env['fp.job.step'].browse(int(step_id))
if not step.exists(): if not step.exists():
return {'ok': False, 'error': 'Step not found.'} return {'ok': False, 'error': 'Step not found.'}

View File

@@ -20,8 +20,6 @@ from odoo.addons.fusion_plating.models.fp_tz import (
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.http import request from odoo.http import request
from ._tablet_audit import env_for_tablet_tech
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -257,10 +255,9 @@ class FpShopfloorController(http.Controller):
# Quick chemistry log from the tablet # Quick chemistry log from the tablet
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@http.route('/fp/shopfloor/log_chemistry', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/log_chemistry', type='jsonrpc', auth='user')
def log_chemistry(self, bath_id, readings, shift=None, notes=None, def log_chemistry(self, bath_id, readings, shift=None, notes=None):
tablet_tech_id=None):
"""Create a fusion.plating.bath.log with one line per reading.""" """Create a fusion.plating.bath.log with one line per reading."""
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
if not bath_id: if not bath_id:
raise UserError("bath_id required") raise UserError("bath_id required")
bath = env['fusion.plating.bath'].browse(int(bath_id)) bath = env['fusion.plating.bath'].browse(int(bath_id))
@@ -295,10 +292,10 @@ class FpShopfloorController(http.Controller):
# Bake window controls # Bake window controls
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@http.route('/fp/shopfloor/start_bake', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/start_bake', type='jsonrpc', auth='user')
def start_bake(self, bake_window_id, oven_id=None, tablet_tech_id=None): def start_bake(self, bake_window_id, oven_id=None):
# action_start_bake raises UserError for S6 missed_window. Wrap # action_start_bake raises UserError for S6 missed_window. Wrap
# the same way as start_wo so operator gets a clean flash. # the same way as start_wo so operator gets a clean flash.
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
bw = env['fusion.plating.bake.window'].browse(int(bake_window_id)) bw = env['fusion.plating.bake.window'].browse(int(bake_window_id))
if not bw.exists(): if not bw.exists():
return {'ok': False, 'error': f'Bake window {bake_window_id} not found'} return {'ok': False, 'error': f'Bake window {bake_window_id} not found'}
@@ -315,8 +312,8 @@ class FpShopfloorController(http.Controller):
} }
@http.route('/fp/shopfloor/end_bake', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/end_bake', type='jsonrpc', auth='user')
def end_bake(self, bake_window_id, tablet_tech_id=None): def end_bake(self, bake_window_id):
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
bw = env['fusion.plating.bake.window'].browse(int(bake_window_id)) bw = env['fusion.plating.bake.window'].browse(int(bake_window_id))
if not bw.exists(): if not bw.exists():
return {'ok': False, 'error': f'Bake window {bake_window_id} not found'} return {'ok': False, 'error': f'Bake window {bake_window_id} not found'}
@@ -354,7 +351,7 @@ class FpShopfloorController(http.Controller):
return step if step.exists() else False return step if step.exists() else False
@http.route('/fp/shopfloor/start_wo', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/start_wo', type='jsonrpc', auth='user')
def start_wo(self, workorder_id=None, step_id=None, tablet_tech_id=None): def start_wo(self, workorder_id=None, step_id=None):
"""Start the timer on a fp.job.step (called from the tablet). """Start the timer on a fp.job.step (called from the tablet).
button_start() can raise UserError for any guarded condition button_start() can raise UserError for any guarded condition
@@ -363,7 +360,7 @@ class FpShopfloorController(http.Controller):
the explicit state check, so the tablet flashes a clean toast the explicit state check, so the tablet flashes a clean toast
instead of popping a stack-trace dialog at the operator. instead of popping a stack-trace dialog at the operator.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
step = self._resolve_step_in_env(env, step_id, workorder_id) step = self._resolve_step_in_env(env, step_id, workorder_id)
if not step: if not step:
return {'ok': False, 'error': 'Step not found'} return {'ok': False, 'error': 'Step not found'}
@@ -383,8 +380,7 @@ class FpShopfloorController(http.Controller):
} }
@http.route('/fp/shopfloor/stop_wo', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/stop_wo', type='jsonrpc', auth='user')
def stop_wo(self, workorder_id=None, step_id=None, finish=False, def stop_wo(self, workorder_id=None, step_id=None, finish=False):
tablet_tech_id=None):
"""Finish the timer on a fp.job.step. """Finish the timer on a fp.job.step.
finish=True calls button_finish(); other values are no-ops for finish=True calls button_finish(); other values are no-ops for
@@ -395,7 +391,7 @@ class FpShopfloorController(http.Controller):
not provided). Wrapped same as start_wo so the operator gets a not provided). Wrapped same as start_wo so the operator gets a
clean flash, not a stack-trace dialog. clean flash, not a stack-trace dialog.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
step = self._resolve_step_in_env(env, step_id, workorder_id) step = self._resolve_step_in_env(env, step_id, workorder_id)
if not step: if not step:
return {'ok': False, 'error': 'Step not found'} return {'ok': False, 'error': 'Step not found'}
@@ -425,11 +421,11 @@ class FpShopfloorController(http.Controller):
# both with a single tap. Scrap auto-spawns a hold via fp.job.write # both with a single tap. Scrap auto-spawns a hold via fp.job.write
# (S17 hook, no extra wiring needed here). # (S17 hook, no extra wiring needed here).
@http.route('/fp/shopfloor/bump_qty_done', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/bump_qty_done', type='jsonrpc', auth='user')
def bump_qty_done(self, job_id, delta=1, tablet_tech_id=None): def bump_qty_done(self, job_id, delta=1):
"""Increment job.qty_done by `delta` (defaults to +1). """Increment job.qty_done by `delta` (defaults to +1).
Returns the new totals so the tablet can update without a full refresh. Returns the new totals so the tablet can update without a full refresh.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
job = env['fp.job'].browse(int(job_id)) job = env['fp.job'].browse(int(job_id))
if not job.exists(): if not job.exists():
return {'ok': False, 'error': 'Job not found'} return {'ok': False, 'error': 'Job not found'}
@@ -450,14 +446,13 @@ class FpShopfloorController(http.Controller):
} }
@http.route('/fp/shopfloor/bump_qty_scrapped', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/bump_qty_scrapped', type='jsonrpc', auth='user')
def bump_qty_scrapped(self, job_id, delta=1, reason=None, def bump_qty_scrapped(self, job_id, delta=1, reason=None):
tablet_tech_id=None):
"""Increment job.qty_scrapped by `delta`. The S17 write-hook on """Increment job.qty_scrapped by `delta`. The S17 write-hook on
fp.job auto-spawns a fusion.plating.quality.hold for the delta; fp.job auto-spawns a fusion.plating.quality.hold for the delta;
the operator can edit the description on that hold later. the operator can edit the description on that hold later.
`reason` is optional — passed through to the hold's description. `reason` is optional — passed through to the hold's description.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
job = env['fp.job'].browse(int(job_id)) job = env['fp.job'].browse(int(job_id))
if not job.exists(): if not job.exists():
return {'ok': False, 'error': 'Job not found'} return {'ok': False, 'error': 'Job not found'}
@@ -489,15 +484,14 @@ class FpShopfloorController(http.Controller):
position_label=None, reading_number=None, position_label=None, reading_number=None,
equipment_model=None, calibration_std_ref=None, equipment_model=None, calibration_std_ref=None,
microscope_image=None, microscope_image=None,
microscope_image_filename=None, microscope_image_filename=None):
tablet_tech_id=None):
"""Record a single Fischerscope reading against a job. """Record a single Fischerscope reading against a job.
`job_id` is the canonical kwarg; `production_id` is accepted as an `job_id` is the canonical kwarg; `production_id` is accepted as an
alias for older clients. The reading auto-links to an existing alias for older clients. The reading auto-links to an existing
CoC certificate for the job when one exists. CoC certificate for the job when one exists.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
Reading = env.get('fp.thickness.reading') Reading = env.get('fp.thickness.reading')
if Reading is None: if Reading is None:
return {'ok': False, 'error': 'Certificates module not installed'} return {'ok': False, 'error': 'Certificates module not installed'}
@@ -578,8 +572,7 @@ class FpShopfloorController(http.Controller):
part_ref=None, qty_on_hold=0, qty_original=0, part_ref=None, qty_on_hold=0, qty_original=0,
hold_reason='other', description=None, hold_reason='other', description=None,
mark_for_scrap=False, facility_id=None, mark_for_scrap=False, facility_id=None,
work_center_id=None, current_process_node=None, work_center_id=None, current_process_node=None):
tablet_tech_id=None):
"""Create a quality hold record, splitting qty from the original lot. """Create a quality hold record, splitting qty from the original lot.
The hold is linked to the fp.job and (when provided) the The hold is linked to the fp.job and (when provided) the
@@ -588,7 +581,7 @@ class FpShopfloorController(http.Controller):
if not qty_on_hold or int(qty_on_hold) <= 0: if not qty_on_hold or int(qty_on_hold) <= 0:
raise UserError("qty_on_hold must be a positive integer.") raise UserError("qty_on_hold must be a positive integer.")
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
Hold = env['fusion.plating.quality.hold'] Hold = env['fusion.plating.quality.hold']
vals = { vals = {
@@ -1018,8 +1011,8 @@ class FpShopfloorController(http.Controller):
# Mark a first-piece gate result from the tablet # Mark a first-piece gate result from the tablet
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@http.route('/fp/shopfloor/mark_gate', type='jsonrpc', auth='user') @http.route('/fp/shopfloor/mark_gate', type='jsonrpc', auth='user')
def mark_gate(self, gate_id, result, tablet_tech_id=None): def mark_gate(self, gate_id, result):
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
gate = env['fusion.plating.first.piece.gate'].browse(int(gate_id)) gate = env['fusion.plating.first.piece.gate'].browse(int(gate_id))
if not gate.exists(): if not gate.exists():
return {'ok': False, 'error': 'Gate not found.'} return {'ok': False, 'error': 'Gate not found.'}
@@ -1108,15 +1101,14 @@ class FpShopfloorController(http.Controller):
@http.route('/fp/shopfloor/plant_overview/move_card', @http.route('/fp/shopfloor/plant_overview/move_card',
type='jsonrpc', auth='user') type='jsonrpc', auth='user')
def plant_overview_move_card(self, card_id, source_model=None, def plant_overview_move_card(self, card_id, source_model=None,
target_workcenter_id=None, target_workcenter_id=None):
tablet_tech_id=None):
"""Move a step card to a different work centre (drag & drop). """Move a step card to a different work centre (drag & drop).
`source_model` is accepted for backward compatibility but ignored — `source_model` is accepted for backward compatibility but ignored —
Plant Overview now only ever serves fp.job.step cards. A target Plant Overview now only ever serves fp.job.step cards. A target
of 0 / falsy clears the work centre. of 0 / falsy clears the work centre.
""" """
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
Step = env['fp.job.step'] Step = env['fp.job.step']
step = Step.browse(int(card_id)) step = Step.browse(int(card_id))
if not step.exists(): if not step.exists():

View File

@@ -23,8 +23,6 @@ from odoo import fields, http
from odoo.addons.fusion_plating.models.fp_tz import fp_format from odoo.addons.fusion_plating.models.fp_tz import fp_format
from odoo.http import request from odoo.http import request
from ._tablet_audit import env_for_tablet_tech
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -196,8 +194,8 @@ class FpWorkspaceController(http.Controller):
@http.route('/fp/workspace/hold', type='jsonrpc', auth='user') @http.route('/fp/workspace/hold', type='jsonrpc', auth='user')
def hold(self, job_id, reason='other', qty_on_hold=1, description='', def hold(self, job_id, reason='other', qty_on_hold=1, description='',
part_ref='', step_id=None, mark_for_scrap=False, part_ref='', step_id=None, mark_for_scrap=False,
photo_data=None, photo_filename=None, tablet_tech_id=None): photo_data=None, photo_filename=None):
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
job = env['fp.job'].browse(int(job_id)) job = env['fp.job'].browse(int(job_id))
if not job.exists(): if not job.exists():
return {'ok': False, 'error': f'Job {job_id} not found'} return {'ok': False, 'error': f'Job {job_id} not found'}
@@ -259,8 +257,8 @@ class FpWorkspaceController(http.Controller):
# /fp/workspace/sign_off — capture signature + finish step atomically # /fp/workspace/sign_off — capture signature + finish step atomically
# ====================================================================== # ======================================================================
@http.route('/fp/workspace/sign_off', type='jsonrpc', auth='user') @http.route('/fp/workspace/sign_off', type='jsonrpc', auth='user')
def sign_off(self, step_id, signature_data_uri, tablet_tech_id=None): def sign_off(self, step_id, signature_data_uri):
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
sig = (signature_data_uri or '').strip() sig = (signature_data_uri or '').strip()
if not sig: if not sig:
_logger.warning("workspace/sign_off: empty signature for step %s", step_id) _logger.warning("workspace/sign_off: empty signature for step %s", step_id)
@@ -308,8 +306,8 @@ class FpWorkspaceController(http.Controller):
# /fp/workspace/advance_milestone — fire next_milestone_action # /fp/workspace/advance_milestone — fire next_milestone_action
# ====================================================================== # ======================================================================
@http.route('/fp/workspace/advance_milestone', type='jsonrpc', auth='user') @http.route('/fp/workspace/advance_milestone', type='jsonrpc', auth='user')
def advance_milestone(self, job_id, tablet_tech_id=None): def advance_milestone(self, job_id):
env = env_for_tablet_tech(request.env, tablet_tech_id) env = request.env
job = env['fp.job'].browse(int(job_id)) job = env['fp.job'].browse(int(job_id))
if not job.exists(): if not job.exists():
return {'ok': False, 'error': f'Job {job_id} not found'} return {'ok': False, 'error': f'Job {job_id} not found'}