From a90eace4d08d8b52b55e399f2b71871ba4d1595f Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 23 May 2026 20:51:36 -0400 Subject: [PATCH] =?UTF-8?q?feat(shopfloor):=20Phase=203=20=E2=80=94=20plan?= =?UTF-8?q?t=5Fkanban=20endpoint=20+=20dispatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PV-Phase3 of the plant-view redesign. - /fp/landing/plant_kanban JSONRPC endpoint returns {kpis, columns, cards} in one payload. One card per fp.job; cards denormalized so the OWL component doesn't fan out RPCs. Server-side filter handling for All / Mine / Running / Blocked / Overdue / FAIR. Within-column sort by (overdue, _SORT_PRIORITY[card_state], due_date). - fusion_plating_shopfloor.action_fp_plant_kanban client action registered alongside the existing fp_shopfloor_landing action. - fp_landing_data.xml resolver extended to read the layout flag and dispatch to v2 when x_fc_shopfloor_layout='v2' (default still legacy). Card payload (23 fields): WO, customer, PN+rev, qty, PO, recipe, spec, tags, current step + work centre, state chip, mini_timeline, operator, icons (signoff / bake / tracking / etc.), progress. State-chip mapping per spec §6.1 — one map keyed by card_state with running-time elapsed, idle-hours, and operator-name interpolation. Verified live — card payload sample on WO-30036 (contract_review state) produces all expected keys + 9-element mini_timeline. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../fusion_plating/data/fp_landing_data.xml | 26 +- .../controllers/__init__.py | 1 + .../controllers/plant_kanban.py | 378 ++++++++++++++++++ .../views/fp_plant_overview_views.xml | 14 + 4 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 fusion_plating/fusion_plating_shopfloor/controllers/plant_kanban.py diff --git a/fusion_plating/fusion_plating/data/fp_landing_data.xml b/fusion_plating/fusion_plating/data/fp_landing_data.xml index e26af20b..f823df61 100644 --- a/fusion_plating/fusion_plating/data/fp_landing_data.xml +++ b/fusion_plating/fusion_plating/data/fp_landing_data.xml @@ -24,15 +24,37 @@ code 1: + return _('Due %s · %dd') % (base, days) + return _('Due %s · %dd late') % (base, -days) + + +def _icons(job, step): + """Compact icon row at the card footer.""" + icons = [] + if step: + if step.requires_signoff and not step.signoff_user_id: + icons.append('🔏') + if step.recipe_node_id \ + and step.recipe_node_id.default_kind == 'bake': + icons.append('🔥') + if job.card_state == 'bake_due': + icons.append('⏰') + if job.card_state == 'no_parts': + icons.append('🚚') + if job.card_state == 'on_hold': + icons.append('💬') + if job.card_state == 'predecessor_locked': + icons.append('🔒') + if job.card_state == 'done': + icons.append('📜') + return icons + + +def _initials_for(user): + if not user or not user.name: + return '' + parts = user.name.strip().split() + if len(parts) == 1: + return parts[0][:2].upper() + return (parts[0][0] + parts[-1][0]).upper() + + +def _sort_key(card): + """Sort within a column: overdue first, then by state priority, + then by due date (earlier = higher priority).""" + return ( + 0 if card['is_overdue'] else 1, + _SORT_PRIORITY.get(card['card_state'], 99), + card['due_date'] or '9999-12-31', + ) diff --git a/fusion_plating/fusion_plating_shopfloor/views/fp_plant_overview_views.xml b/fusion_plating/fusion_plating_shopfloor/views/fp_plant_overview_views.xml index 6a7b0b7a..0d838433 100644 --- a/fusion_plating/fusion_plating_shopfloor/views/fp_plant_overview_views.xml +++ b/fusion_plating/fusion_plating_shopfloor/views/fp_plant_overview_views.xml @@ -28,4 +28,18 @@ fp_process_tree + + + + + + + + + + Shop Floor + fp_plant_kanban + main + +