feat(jobs): Phase 6 — Plant Overview kanban + Manager Dashboard
Two operator-facing client actions for the native job model. Plant Overview: kanban with columns = fp.work.centre, cards = active fp.job.step rows (ready/in_progress/paused). Drag a card to a different column to reassign the step's work_centre_id; click to open the step form. Backend: /fp/jobs/plant_overview returns columns with cards; /fp/jobs/plant_overview/move_card reassigns work_centre. Manager Dashboard: list of in-flight fp.job rows with progress bars, deadline (overdue highlight), current_step / current_location, and a priority side-bar (rush=red, high=orange, normal=blue, low=grey). Click a row to open the job form. State-count pills filter by state. Backend: /fp/jobs/manager_dashboard returns rows + state counts. Both menu entries land inside the existing 'Plating Jobs (Native)' submenu under the Plating app (manager-only). The menu items are defined in this module rather than in fusion_plating core, because the action xmlids they reference aren't loaded yet at the time the core menu file is parsed (fusion_plating_jobs depends on core, not the other way round). Manifest 19.0.2.2.0 → 19.0.2.3.0. Three new SCSS, three new JS, three new XML files registered in web.assets_backend. Verified on entech: module loaded clean, all 41 fusion_plating_jobs tests pass, asset bundle regenerates without errors, both menus and both client actions registered in ir_ui_menu / ir_act_client. Part of: native job model migration (spec 2026-04-25) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
#
|
||||
# /fp/jobs/manager_dashboard — JSON endpoint powering the native-job
|
||||
# Manager Dashboard. Returns a flat list of in-flight fp.job rows
|
||||
# with progress / current-step / deadline info, plus state-count
|
||||
# pills for the filter bar at the top of the dashboard.
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class FpJobsManagerDashboardController(http.Controller):
|
||||
|
||||
@http.route('/fp/jobs/manager_dashboard', type='jsonrpc', auth='user', website=False)
|
||||
def fp_jobs_manager_dashboard(self, state=None, **kwargs):
|
||||
env = request.env
|
||||
Job = env['fp.job']
|
||||
|
||||
# Default view: jobs that need triage. Specifying state=<value>
|
||||
# narrows to that one bucket; state='all' opens the floodgates.
|
||||
if state and state != 'all':
|
||||
domain = [('state', '=', state)]
|
||||
elif state == 'all':
|
||||
domain = []
|
||||
else:
|
||||
domain = [('state', 'in', ('confirmed', 'in_progress', 'on_hold'))]
|
||||
|
||||
jobs = Job.search(
|
||||
domain,
|
||||
order='priority desc, date_deadline asc, id desc',
|
||||
limit=200,
|
||||
)
|
||||
|
||||
rows = []
|
||||
for job in jobs:
|
||||
rows.append({
|
||||
'id': job.id,
|
||||
'name': job.name,
|
||||
'partner': job.partner_id.name or '',
|
||||
'qty': job.qty,
|
||||
'state': job.state,
|
||||
'priority': job.priority,
|
||||
'date_deadline': (
|
||||
job.date_deadline.isoformat()
|
||||
if job.date_deadline else None
|
||||
),
|
||||
'current_step': (
|
||||
job.current_step_id.name
|
||||
if job.current_step_id else None
|
||||
),
|
||||
'current_location': job.current_location,
|
||||
'progress_pct': job.step_progress_pct,
|
||||
'step_done': job.step_done_count,
|
||||
'step_total': job.step_count,
|
||||
'recipe': job.recipe_id.name if job.recipe_id else None,
|
||||
})
|
||||
|
||||
# State-count pills for the filter bar — let the dashboard show
|
||||
# the manager how big each bucket is at a glance.
|
||||
counts = {}
|
||||
for s in ('confirmed', 'in_progress', 'on_hold', 'done'):
|
||||
counts[s] = Job.search_count([('state', '=', s)])
|
||||
|
||||
return {'rows': rows, 'counts': counts}
|
||||
Reference in New Issue
Block a user