feat(step-library): full plating workflow coverage + per-recipe configurability + audit
Implements 2026-04-29-step-library-audit-design.md. Bumps fusion_plating to 19.0.18.7.0, fusion_plating_jobs to 19.0.8.12.0, fusion_plating_reports to 19.0.10.2.0. LIBRARY EXPANSION - 8 new Step Kinds: Receiving, Electroclean, Strike, Salt Spray, Adhesion Test, Hardness Test, Packaging, Tank Replenishment - 4 new input types: photo, multi_point_thickness, bath_chemistry_panel, ph - DEFAULT_INPUTS_BY_KIND rewritten to seed audit-grade prompts on every kind (bath IDs, photos, multi-point thickness, signatures, etc.) - + Common Audit Fields one-click button on the library template form - Default Operator Instructions relabel + alert callout PER-RECIPE CONFIGURABILITY - collect (Boolean) per recipe-step input prompt — opt out without delete - collect_measurements (Boolean) master switch on recipe step — when off, wizard skips entirely - template_input_id (Many2one) traceability link from recipe to library - Recipe-step backend form view exposes the new fields with handle drag, toggle, target range, and library-source column RUNTIME WIRING - Step input wizard filters node.input_ids to step_input AND collect=True; short-circuits on collect_measurements=False - New input types: photo (image widget + ir.attachment), multi-point thickness (5 readings + auto avg, skips empty cells), bath chemistry panel (pH/conc/temp/bath bundle), pH (0-14 numeric) - Composite values JSON-serialized into value_text; photo via attachment CoC REPORT - Filters captured prompts to collect=True only - Renders new input types with appropriate format MIGRATION (post-migrate.py for 19.0.18.7.0) - Backfills collect=True on recipe-step inputs - Backfills collect_measurements=True on recipe steps - Re-runs action_seed_default_inputs on every existing template (idempotent, preserves user edits) - Backfills template_input_id by name-matching against source library template (handles JSONB vs varchar name columns) SEED DATA - 8 example templates (one per new kind) in fp_step_template_data.xml with noupdate=1 BATTLE TEST - bt_step_library_audit.py: 29 assertions all PASS on entech OWL EDITOR EXTENSION DEFERRED - The simple recipe editor's per-step Instructions/Measurements expansions were not implemented in this pass; users configure via the backend recipe-step form. Track follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""Post-migration for 19.0.18.7.0 — Step Library audit expansion.
|
||||
|
||||
1. Default `collect=True` on all existing recipe-step inputs.
|
||||
2. Default `collect_measurements=True` on all existing recipe steps.
|
||||
3. Re-run action_seed_default_inputs on every existing template to
|
||||
pull in the newly-added prompts (idempotent — skips rows whose
|
||||
name is already present, so user edits survive).
|
||||
4. Backfill template_input_id by name-matching against the linked
|
||||
library template (best-effort).
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
if not version:
|
||||
return
|
||||
from odoo.api import Environment, SUPERUSER_ID
|
||||
env = Environment(cr, SUPERUSER_ID, {})
|
||||
|
||||
# 1. Default collect=True on all recipe-step inputs that have NULL
|
||||
cr.execute("""
|
||||
UPDATE fusion_plating_process_node_input
|
||||
SET collect = TRUE
|
||||
WHERE collect IS NULL
|
||||
""")
|
||||
_logger.info(
|
||||
"Backfilled collect=True on %s recipe-step inputs", cr.rowcount
|
||||
)
|
||||
|
||||
# 2. Default collect_measurements=True on recipe steps with NULL
|
||||
cr.execute("""
|
||||
UPDATE fusion_plating_process_node
|
||||
SET collect_measurements = TRUE
|
||||
WHERE collect_measurements IS NULL
|
||||
""")
|
||||
_logger.info(
|
||||
"Backfilled collect_measurements=True on %s recipe steps", cr.rowcount
|
||||
)
|
||||
|
||||
# 3. Re-seed defaults on every existing template (idempotent)
|
||||
Template = env['fp.step.template']
|
||||
templates = Template.search([('default_kind', '!=', False)])
|
||||
for tpl in templates:
|
||||
try:
|
||||
tpl.action_seed_default_inputs()
|
||||
except Exception as e:
|
||||
_logger.warning(
|
||||
"Failed to re-seed defaults on template %s: %s", tpl.id, e
|
||||
)
|
||||
_logger.info("Re-seeded defaults on %s templates", len(templates))
|
||||
|
||||
# 4. Backfill template_input_id — name-match recipe-node inputs against
|
||||
# their parent recipe's source library template.
|
||||
# Note: fusion_plating_process_node_input.name is plain varchar;
|
||||
# fp_step_template_input.name is translatable JSONB (use ->>'en_US').
|
||||
cr.execute("""
|
||||
SELECT ni.id, ni.name, n.source_template_id
|
||||
FROM fusion_plating_process_node_input ni
|
||||
JOIN fusion_plating_process_node n ON n.id = ni.node_id
|
||||
WHERE ni.template_input_id IS NULL
|
||||
AND n.source_template_id IS NOT NULL
|
||||
""")
|
||||
rows = cr.fetchall()
|
||||
matched = 0
|
||||
for ni_id, name, tpl_id in rows:
|
||||
if not name:
|
||||
continue
|
||||
cr.execute("""
|
||||
SELECT id FROM fp_step_template_input
|
||||
WHERE template_id = %s
|
||||
AND name->>'en_US' = %s
|
||||
LIMIT 1
|
||||
""", (tpl_id, name))
|
||||
match = cr.fetchone()
|
||||
if match:
|
||||
cr.execute("""
|
||||
UPDATE fusion_plating_process_node_input
|
||||
SET template_input_id = %s WHERE id = %s
|
||||
""", (match[0], ni_id))
|
||||
matched += 1
|
||||
_logger.info(
|
||||
"Backfilled template_input_id on %s recipe-step inputs", matched
|
||||
)
|
||||
Reference in New Issue
Block a user