fix(shopfloor): Manager Desk speaks fp.job/fp.job.step end-to-end
The previous shopfloor consolidation kept the data layer correct (controller queries fp.job.step) but left the UI labels, JS variables, and RPC kwargs in legacy WO/MO vocabulary. Result: every label said 'Unassigned WOs' / 'X WO' even though the underlying records are fp.job.step rows. Renames throughout: wo → step (variable / loop / payload key) WO → Step (label) unassigned_wos → unassigned_steps (KPI key) active_wos → active_steps ready_to_ship_mos → ready_to_ship_jobs mo_id / mo_name / expandedMoId → job_id / job_name / expandedJobId wo_kind → kind, wo_kind_label → kind_label o_fp_mgr_wo_* CSS classes → o_fp_mgr_step_* RPC routes /fp/manager/assign_worker, /fp/manager/assign_tank, /fp/manager/take_over: primary kwarg is step_id; workorder_id accepted as a deprecated alias for one release with a logged warning, so any uncaught caller doesn't break. No layout / visual changes — same UI shape, native vocabulary. SCSS class renames are mechanical (only `_wo_` → `_step_` in selectors); XML updated in lockstep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
# Part of the Fusion Plating product family.
|
||||
"""JSON-RPC endpoints for the Manager Dashboard (client action).
|
||||
"""JSON-RPC endpoints for the Manager Desk (client action).
|
||||
|
||||
Native fp.job / fp.job.step edition (consolidated 2026-04-24). All
|
||||
endpoint URLs are preserved (`/fp/manager/*`); the underlying data
|
||||
layer is now fp.job + fp.job.step.
|
||||
Native fp.job / fp.job.step edition. Speaks fp.job/fp.job.step
|
||||
end-to-end — payload keys, variables, and RPC kwargs all use the
|
||||
job/step vocabulary.
|
||||
|
||||
Manager Desk ergonomics:
|
||||
- Column 1 ("Needs a Worker") = jobs that have at least one step
|
||||
@@ -34,8 +34,7 @@ _NEG_JOB_STATES = ('done', 'cancelled')
|
||||
_ACTIVE_JOB_STATES = ('confirmed', 'in_progress', 'on_hold')
|
||||
|
||||
# A step needs an operator and (for wet/bake/mask) the right equipment
|
||||
# before the operator can tap Start. Mirrors the legacy
|
||||
# x_fc_is_release_ready compute on mrp.workorder.
|
||||
# before the operator can tap Start.
|
||||
def _step_release_readiness(step):
|
||||
"""Return (is_release_ready, missing_str) for a fp.job.step."""
|
||||
missing = []
|
||||
@@ -55,7 +54,7 @@ def _step_release_readiness(step):
|
||||
|
||||
|
||||
def _priority_int(priority):
|
||||
"""fp.job.priority → int 0/1/2 (parallel of legacy x_fc_priority)."""
|
||||
"""fp.job.priority → int 0/1/2."""
|
||||
return {'rush': 2, 'high': 1, 'normal': 0, 'low': 0}.get(priority, 0)
|
||||
|
||||
|
||||
@@ -120,10 +119,10 @@ class FpManagerDashboardController(http.Controller):
|
||||
)
|
||||
steps_iter = steps_iter.sorted('sequence')
|
||||
|
||||
wo_rows = []
|
||||
step_rows = []
|
||||
for s in steps_iter:
|
||||
ready, missing = readiness_by_step.get(s.id, (False, ''))
|
||||
wo_rows.append({
|
||||
step_rows.append({
|
||||
'id': s.id,
|
||||
'name': s.name or '',
|
||||
'workcenter': s.work_centre_id.name or '',
|
||||
@@ -138,8 +137,8 @@ class FpManagerDashboardController(http.Controller):
|
||||
'assigned_user_name': s.assigned_user_id.name or '',
|
||||
'role_id': False,
|
||||
'role_name': '',
|
||||
'wo_kind': s.kind or 'other',
|
||||
'wo_kind_label': dict(s._fields['kind'].selection).get(
|
||||
'kind': s.kind or 'other',
|
||||
'kind_label': dict(s._fields['kind'].selection).get(
|
||||
s.kind, '',
|
||||
) if s.kind else '',
|
||||
'is_release_ready': ready,
|
||||
@@ -150,8 +149,8 @@ class FpManagerDashboardController(http.Controller):
|
||||
})
|
||||
|
||||
return {
|
||||
'mo_id': job.id,
|
||||
'mo_name': job.name or '',
|
||||
'job_id': job.id,
|
||||
'job_name': job.name or '',
|
||||
'so_name': job.origin or '',
|
||||
'customer': partner.name if partner else '',
|
||||
'product': job.product_id.display_name if job.product_id else '',
|
||||
@@ -163,7 +162,7 @@ class FpManagerDashboardController(http.Controller):
|
||||
'recipe': job.recipe_id.name if job.recipe_id else '',
|
||||
'priority_any': _priority_int(job.priority),
|
||||
'current_location': job.current_location or '',
|
||||
'wos': wo_rows,
|
||||
'steps': step_rows,
|
||||
}
|
||||
|
||||
unassigned_cards = [_job_card(j) for j in unassigned_jobs]
|
||||
@@ -256,14 +255,14 @@ class FpManagerDashboardController(http.Controller):
|
||||
ready_to_ship_jobs = Job.search_count([('state', '=', 'done')])
|
||||
|
||||
kpis = {
|
||||
'unassigned_wos': len(all_steps.filtered(
|
||||
'unassigned_steps': len(all_steps.filtered(
|
||||
lambda s: not readiness_by_step.get(s.id, (False, ''))[0],
|
||||
)),
|
||||
'active_wos': len(all_steps.filtered(
|
||||
'active_steps': len(all_steps.filtered(
|
||||
lambda s: readiness_by_step.get(s.id, (False, ''))[0]
|
||||
and s.state in ('ready', 'in_progress'),
|
||||
)),
|
||||
'ready_to_ship_mos': ready_to_ship_jobs,
|
||||
'ready_to_ship_jobs': ready_to_ship_jobs,
|
||||
'pending_accept_sos': pending_accept_sos,
|
||||
}
|
||||
|
||||
@@ -295,10 +294,20 @@ class FpManagerDashboardController(http.Controller):
|
||||
# Assign a worker to a step
|
||||
# ------------------------------------------------------------------
|
||||
@http.route('/fp/manager/assign_worker', type='jsonrpc', auth='user')
|
||||
def assign_worker(self, workorder_id, user_id):
|
||||
"""`workorder_id` is the canonical kwarg name from the legacy
|
||||
XML; it now resolves to a fp.job.step id."""
|
||||
step = request.env['fp.job.step'].browse(int(workorder_id))
|
||||
def assign_worker(self, step_id=None, user_id=None, workorder_id=None, **kwargs):
|
||||
"""Assign an operator to a step. ``step_id`` is the canonical
|
||||
kwarg; ``workorder_id`` is accepted as a deprecated alias for
|
||||
one release so any caller we missed doesn't break.
|
||||
"""
|
||||
if step_id is None and workorder_id is not None:
|
||||
_logger.warning(
|
||||
"workorder_id kwarg is deprecated; use step_id "
|
||||
"(/fp/manager/assign_worker)",
|
||||
)
|
||||
step_id = workorder_id
|
||||
if not step_id:
|
||||
return {'ok': False, 'error': 'step_id required'}
|
||||
step = request.env['fp.job.step'].browse(int(step_id))
|
||||
if not step.exists():
|
||||
return {'ok': False, 'error': 'Step not found.'}
|
||||
step.assigned_user_id = int(user_id) if user_id else False
|
||||
@@ -313,8 +322,19 @@ class FpManagerDashboardController(http.Controller):
|
||||
# Reassign or swap tank on a step
|
||||
# ------------------------------------------------------------------
|
||||
@http.route('/fp/manager/assign_tank', type='jsonrpc', auth='user')
|
||||
def assign_tank(self, workorder_id, tank_id):
|
||||
step = request.env['fp.job.step'].browse(int(workorder_id))
|
||||
def assign_tank(self, step_id=None, tank_id=None, workorder_id=None, **kwargs):
|
||||
"""Swap the tank on a step. ``step_id`` is the canonical kwarg;
|
||||
``workorder_id`` is accepted as a deprecated alias.
|
||||
"""
|
||||
if step_id is None and workorder_id is not None:
|
||||
_logger.warning(
|
||||
"workorder_id kwarg is deprecated; use step_id "
|
||||
"(/fp/manager/assign_tank)",
|
||||
)
|
||||
step_id = workorder_id
|
||||
if not step_id:
|
||||
return {'ok': False, 'error': 'step_id required'}
|
||||
step = request.env['fp.job.step'].browse(int(step_id))
|
||||
if not step.exists():
|
||||
return {'ok': False, 'error': 'Step not found.'}
|
||||
step.tank_id = int(tank_id) if tank_id else False
|
||||
@@ -329,8 +349,19 @@ class FpManagerDashboardController(http.Controller):
|
||||
# Manager takes over a step (no-show coverage)
|
||||
# ------------------------------------------------------------------
|
||||
@http.route('/fp/manager/take_over', type='jsonrpc', auth='user')
|
||||
def take_over(self, workorder_id):
|
||||
step = request.env['fp.job.step'].browse(int(workorder_id))
|
||||
def take_over(self, step_id=None, workorder_id=None, **kwargs):
|
||||
"""Manager takes over a step. ``step_id`` is the canonical kwarg;
|
||||
``workorder_id`` is accepted as a deprecated alias.
|
||||
"""
|
||||
if step_id is None and workorder_id is not None:
|
||||
_logger.warning(
|
||||
"workorder_id kwarg is deprecated; use step_id "
|
||||
"(/fp/manager/take_over)",
|
||||
)
|
||||
step_id = workorder_id
|
||||
if not step_id:
|
||||
return {'ok': False, 'error': 'step_id required'}
|
||||
step = request.env['fp.job.step'].browse(int(step_id))
|
||||
if not step.exists():
|
||||
return {'ok': False, 'error': 'Step not found.'}
|
||||
user = request.env.user
|
||||
|
||||
Reference in New Issue
Block a user