From 555dd5421fa6d8e00cf8aca10032219ea5b04267 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Wed, 29 Apr 2026 23:35:08 -0400 Subject: [PATCH] feat(jobs): step details quick-look modal for backend managers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Click a step's name in the embedded job-form list → opens a read-only modal with everything a manager wants in one scroll: equipment, schedule, master collect-measurements banner, operator instructions (rich-text from recipe_node.description), measurement prompts list, and values recorded so far. Implementation: separate read-only form view bound to the embedded field via context={'form_view_ref': '...'}. The standalone editable form view stays registered for the Job Steps menu, so direct navigation still loads the editable variant. Three new computed/related fields on fp.job.step: - quick_look_instructions (Html, related from recipe_node_id.description) - quick_look_prompt_ids (filtered+sorted recipe_node.input_ids, step_input only) - quick_look_recorded_value_ids (search across moves: input_value rows whose move.from_step_id == self.id) Plus a small action_open_full_form method that escapes from the modal to the editable form when the manager actually needs to edit. Edge cases: - No recipe_node_id → instructions panel shows empty-state hint - collect_measurements=False → amber banner: "Master switch off — no values will be collected at runtime" - Multiple moves on same step → values list shows all, newest first Spec: docs/superpowers/specs/2026-04-30-step-details-modal-design.md. Verified on entech: step "11. Hard Anodize Type III" populates with 516 chars instructions + 7 prompts. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-04-30-step-details-modal-design.md | 61 ++++++++++ .../fusion_plating_jobs/__manifest__.py | 3 +- .../fusion_plating_jobs/models/fp_job_step.py | 61 ++++++++++ .../views/fp_job_form_inherit.xml | 3 +- .../views/fp_job_step_quick_look_views.xml | 115 ++++++++++++++++++ 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 fusion_plating/docs/superpowers/specs/2026-04-30-step-details-modal-design.md create mode 100644 fusion_plating/fusion_plating_jobs/views/fp_job_step_quick_look_views.xml diff --git a/fusion_plating/docs/superpowers/specs/2026-04-30-step-details-modal-design.md b/fusion_plating/docs/superpowers/specs/2026-04-30-step-details-modal-design.md new file mode 100644 index 00000000..73ce837f --- /dev/null +++ b/fusion_plating/docs/superpowers/specs/2026-04-30-step-details-modal-design.md @@ -0,0 +1,61 @@ +# Step Details Quick-Look Modal — Design + +**Date:** 2026-04-30 +**Module:** `fusion_plating_jobs` +**Status:** Approved, implementing inline. + +## Problem + +The job's embedded step list shows minimal columns (Name · Work Centre · State · Times · Qty · action buttons). Backend managers and supervisors viewing a job have no fast way to see what each step entails — instructions written by the office, prompts the operator will be asked, and values already recorded so far. The existing editable form view (registered for the Job Steps menu) is editable + has 4 tabs — too dense for a "what's this step about?" glance, and presents a regression risk if a manager accidentally edits state. + +## Goals + +1. Click a step's name in the embedded job-form list → open a read-only quick-look modal with all the manager-relevant context for that step in one scroll. +2. Preserve the existing editable form for the standalone Job Steps menu / direct navigation. +3. Zero risk of accidental edits — the modal is read-only by construction (`edit="false" create="false" delete="false"`). + +## Non-Goals + +- Editable fields, time-logs, NCRs, predecessor status, action buttons (Start/Skip/Move). Available via "Open Full Form" link in the modal footer. +- New TransientModel mirroring step fields (rejected during brainstorm — duplication). +- Inline-row expansion / accordion (rejected — heavier OWL work). + +## Architecture + +| Component | What it does | +|---|---| +| **Three new related/computed fields on `fp.job.step`** | `quick_look_instructions` (Html, related from `recipe_node_id.description`), `quick_look_prompt_ids` (computed Many2many → `recipe_node_id.input_ids` filtered to step_input), `quick_look_recorded_value_ids` (computed Many2many → `fp.job.step.move.input.value` rows whose `move_id.from_step_id == self.id`) | +| **One new form view** `view_fp_job_step_quick_look_form` | Read-only single-sheet form. Header shows status + tank/bath/rack. Three panels: Instructions, Prompts, Recorded Values | +| **One new action method** `action_open_full_form` on `fp.job.step` | Returns `ir.actions.act_window` opening the existing editable form view, replacing the modal | +| **Single context attribute** on the parent job form's `` | `context="{'form_view_ref': 'fusion_plating_jobs.view_fp_job_step_quick_look_form'}"` — makes Odoo open the quick-look variant on row click | + +## Form Layout + +Single sheet, no notebook. From top to bottom: + +1. **Title row** — `name` as h1 + `state` widget="badge" +2. **Sub-header** — sequence · kind · tank · bath · rack (one line, separated by ·) +3. **Instructions panel** — Html field, `max-height: 40vh; overflow: auto`. Empty-state placeholder when blank: *"No instructions authored for this step."* +4. **Prompts panel** — read-only embedded list with columns: collect ✓/✗ (boolean_toggle, readonly), prompt name, type, target range (computed concat of `target_min–target_max`), unit, required ★ +5. **Values Recorded panel** — read-only embedded list with columns: prompt name (from `node_input_id.name`), value (computed display of typed value), recorded by, when. Sorted `create_date desc`. Empty-state: *"No values recorded yet."* +6. **Footer buttons** — `[Open Full Form]` (primary, calls action_open_full_form) · `[Close]` (special="cancel") + +## Edge Cases + +- **No `recipe_node_id`** — instructions panel shows empty-state; prompts list empty; recorded values still resolve via move search. +- **`collect_measurements=False`** — banner: *"Master switch off — no values will be collected at runtime."* Prompts list still rendered for reference. +- **Multiple moves on same step (re-records)** — Values Recorded list shows all, newest first. +- **Long instructions** — instruction panel scrolls so prompts/values stay visible. + +## Files Touched + +| File | Status | Change | +|---|---|---| +| `fusion_plating_jobs/models/fp_job_step.py` | MOD | Add 3 fields + `action_open_full_form` method | +| `fusion_plating_jobs/views/fp_job_step_quick_look_views.xml` | NEW | Read-only form view | +| `fusion_plating_jobs/views/fp_job_views.xml` (or wherever step_ids is rendered) | MOD | Add `context` attr to `` | +| `fusion_plating_jobs/__manifest__.py` | MOD | Register new view file, bump version | + +## Effort + +~150 lines, ~1 hour build + verify on entech. diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index 7cce258d..63807ef7 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.8.13.0', + 'version': '19.0.8.14.0', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'author': 'Nexa Systems Inc.', @@ -54,6 +54,7 @@ full design rationale and §6.2 of the implementation plan for task list. 'security/ir.model.access.csv', 'data/fp_cron_data.xml', 'views/res_config_settings_views.xml', + 'views/fp_job_step_quick_look_views.xml', 'views/fp_job_form_inherit.xml', 'views/fp_job_quality_buttons.xml', 'views/sale_order_views.xml', diff --git a/fusion_plating/fusion_plating_jobs/models/fp_job_step.py b/fusion_plating/fusion_plating_jobs/models/fp_job_step.py index 700fa041..3039a14e 100644 --- a/fusion_plating/fusion_plating_jobs/models/fp_job_step.py +++ b/fusion_plating/fusion_plating_jobs/models/fp_job_step.py @@ -872,3 +872,64 @@ class FpJobStep(models.Model): step.duration_running_minutes = closed + running else: step.duration_running_minutes = step.duration_actual or 0.0 + + # ------------------------------------------------------------------ + # Sub 12d — Step Details Quick-Look modal + # ------------------------------------------------------------------ + # Three computed/related fields that power the read-only manager + # quick-look modal. The modal is bound via context= on the parent + # job form's — no TransientModel needed. + + quick_look_instructions = fields.Html( + string='Operator Instructions', + related='recipe_node_id.description', + readonly=True, + ) + quick_look_collect_master = fields.Boolean( + string='Collect Measurements', + related='recipe_node_id.collect_measurements', + readonly=True, + ) + quick_look_prompt_ids = fields.Many2many( + 'fusion.plating.process.node.input', + string='Prompts', + compute='_compute_quick_look_prompt_ids', + ) + quick_look_recorded_value_ids = fields.Many2many( + 'fp.job.step.move.input.value', + string='Recorded Values', + compute='_compute_quick_look_recorded_value_ids', + ) + + @api.depends('recipe_node_id', 'recipe_node_id.input_ids') + def _compute_quick_look_prompt_ids(self): + for step in self: + node = step.recipe_node_id + if node: + step.quick_look_prompt_ids = node.input_ids.filtered( + lambda i: (i.kind or 'step_input') == 'step_input' + ).sorted('sequence') + else: + step.quick_look_prompt_ids = False + + def _compute_quick_look_recorded_value_ids(self): + Value = self.env['fp.job.step.move.input.value'] + for step in self: + if not step.id: + step.quick_look_recorded_value_ids = False + continue + step.quick_look_recorded_value_ids = Value.search([ + ('move_id.from_step_id', '=', step.id), + ], order='create_date desc') + + def action_open_full_form(self): + """From the quick-look modal, escape to the full editable form.""" + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'res_model': 'fp.job.step', + 'res_id': self.id, + 'view_mode': 'form', + 'target': 'current', + 'name': self.name, + } diff --git a/fusion_plating/fusion_plating_jobs/views/fp_job_form_inherit.xml b/fusion_plating/fusion_plating_jobs/views/fp_job_form_inherit.xml index 0ec1cc71..f0537fe3 100644 --- a/fusion_plating/fusion_plating_jobs/views/fp_job_form_inherit.xml +++ b/fusion_plating/fusion_plating_jobs/views/fp_job_form_inherit.xml @@ -75,7 +75,8 @@ sees on the tablet; Running Min ticks on every refresh for the active step. --> - + + + + + + fp.job.step.quick.look.form + fp.job.step + 50 + +
+ +
+

+ +

+
+ · + · + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ +
+

+ No instructions authored for this step. +

+ + + + + + + + + + + + + + +

+ No measurement prompts authored for this step. +

+ + + + + + + + + + + + + + +

+ No values recorded yet. +

+
+
+
+ +
+
+ +