This commit is contained in:
gsinghpal
2026-05-04 02:14:34 -04:00
parent 3cc393454d
commit 586f05d567
43 changed files with 3656 additions and 112 deletions

View File

@@ -0,0 +1,96 @@
# FP Step Kind — User-Extensible Model
Date: 2026-05-04
Status: design + implementation
## Problem
`default_kind` on `fp.step.template` is a hardcoded `Selection` of 24 entries. Users can't add new kinds (e.g. "Shot Peen", "Passivation"). The same Selection list is duplicated on `fusion.plating.process.node`. Default-input seeding (`DEFAULT_INPUTS_BY_KIND`) is also locked in Python — adding a new kind would require a code change + module update.
## Solution
Convert `default_kind` from `Selection``Many2one('fp.step.kind')`. Move the default-input templates from a Python dict into seeded data records on a new `fp.step.kind.default.input` child model. Users add new kinds through the standard Odoo CRUD form.
## Models
### `fp.step.kind`
| Field | Type | Notes |
|---|---|---|
| `code` | Char, required, unique per company | Technical key (lowercase). Stable XML IDs use this. |
| `name` | Char, required, translated | UI label (e.g. "Cleaning") |
| `sequence` | Integer | Order in dropdown |
| `active` | Boolean default True | Archive instead of delete |
| `icon` | Selection (reuses 24-icon list from `fp.process.node`) | Optional |
| `description` | Html | Optional ops note |
| `company_id` | Many2one res.company | Multi-co support |
| `default_input_ids` | One2many → `fp.step.kind.default.input` | The seed list |
### `fp.step.kind.default.input`
Same shape as `fp.step.template.input`: `name`, `input_type`, `target_unit`, `sequence`, `required`, `hint`, `selection_options`. Plus `kind_id` parent FK.
## Field changes
### `fp.step.template`
- **add** `kind_id = Many2one('fp.step.kind', ondelete='restrict', string='Step Kind')` — user-facing input
- **change** existing `default_kind` from `Selection(...)` to `default_kind = fields.Char(related='kind_id.code', store=True, readonly=True)` — back-compat shim. Lets every legacy `node.default_kind == 'cleaning'` comparison keep working without touching 30+ sites. Stored=True so existing search domains (`('default_kind', '=', 'foo')`) still work.
### `fusion.plating.process.node`
- Same: add `kind_id`, convert `default_kind` to `related='kind_id.code'` stored Char.
### `fp.job.workflow.state.trigger_default_kinds`
- **No change in Phase 1.** Stays a Char of comma-separated codes. The codes still match `kind_id.code` after migration. Phase 2 deferred convert to m2m.
## DEFAULT_INPUTS_BY_KIND
Removed from `fp_step_template.py`. Lives in seed data XML. `action_seed_default_inputs` reads `tpl.kind_id.default_input_ids` instead of the dict.
## Migration `19.0.18.13.0/post-migrate.py`
1. SQL-read existing `default_kind` text values from `fp_step_template` and `fusion_plating_process_node` BEFORE Odoo recomputes the related field.
2. Build map `code → fp.step.kind.id` from seeded records.
3. SQL UPDATE `kind_id` per row.
4. Trigger recompute of stored related `default_kind` (or leave — values are already there from step 1).
5. Log counts.
## Why not drop `default_kind` entirely?
- Comma-CSV `trigger_default_kinds` on workflow state still searches it.
- 30+ comparison sites and existing search domains in views.
- Stored related Char keeps it a single source of truth (m2o-derived) without a churn-PR through every dependent.
## View changes
- `fp_step_template_views.xml` — replace `<field name="default_kind"/>` with `<field name="kind_id" options="{'no_create_edit': false, 'no_quick_create': false}"/>`. Same for search filter and `group_by="default_kind"``group_by="kind_id"`.
- `fp_process_node_views.xml` — same swap on the one occurrence.
- New `fp_step_kind_views.xml` — list/form/menu so admins can manage kinds. Form embeds `default_input_ids` as inline list.
## Controller / JS changes
- `simple_recipe_controller.py`:
- Add `kind_id` (id) and `kind_name` (label) to all step-payload responses.
- Accept `kind_id` int on `_save_recipe`/template-create endpoints.
- Keep returning `default_kind` (the code Char) for back-compat with deployed editor sessions until cache flushes.
- `simple_recipe_editor.js`:
- Replace the `<select>` over selection options with a Many2one-style typeahead. Fetch list from new endpoint `/fusion_plating/recipe/kinds` returning `[{id, code, name, icon}]`.
- Submit `kind_id` (int) instead of `default_kind` (string).
- `simple_recipe_editor.xml`:
- Replace `<select t-model=".default_kind">` block with a `<select t-model=".kind_id">` populated from fetched list, plus a "+ New kind…" link that opens a small inline form via `/fusion_plating/recipe/kinds/create`.
## ACLs (`ir.model.access.csv`)
```
access_fp_step_kind_operator,fp.step.kind.operator,model_fp_step_kind,group_fusion_plating_operator,1,0,0,0
access_fp_step_kind_supervisor,fp.step.kind.supervisor,model_fp_step_kind,group_fusion_plating_supervisor,1,1,1,0
access_fp_step_kind_manager,fp.step.kind.manager,model_fp_step_kind,group_fusion_plating_manager,1,1,1,1
access_fp_step_kind_default_input_* … same triplet
```
## Manifest
- Bump `version` to `19.0.18.13.0`
- Add to `data`:
- `data/fp_step_kind_data.xml` (BEFORE `fp_step_template_data.xml` since templates reference kinds)
- `views/fp_step_kind_views.xml`
## Out of scope (Phase 2)
- Convert `trigger_default_kinds` Char-CSV to m2m on `fp.job.workflow.state`
- Remove DEFAULT_INPUTS_BY_KIND dict from migration scripts (one-shot dev scripts — no harm leaving)
- Migrate stored `default_kind` Char to a non-stored related once all callers refactored
## Test plan
1. `odoo -d admin -u fusion_plating --stop-after-init` (entech) — install + migration runs cleanly
2. UI smoke: open a step template, kind dropdown shows 24 seeded kinds, dropdown allows quick-create
3. Create new kind "Passivation" with 3 default inputs → save → return to step template → "Seed defaults" button populates the 3 inputs
4. Open recipe editor (simple): kind dropdown matches; existing recipes show correct kind label
5. Run a step that's wired through workflow-state trigger (e.g. completion of a `receiving` step → state changes to "On Floor") to confirm CSV-trigger backwards compat still works