feat(plating): recipe-level cert suppression Booleans
Adds five requires_* Booleans on fusion.plating.process.node (requires_coc, requires_thickness_report, requires_nadcap_cert, requires_mill_test, requires_customer_specific), default True. Recipe is SUPPRESS-ONLY: when False, the recipe never produces that cert type even if the customer/part requested it. Default True = existing recipes keep producing the same cert set they produce today. Surfaced on recipe-level form (node_type == 'recipe'); resolver reads from job.recipe_id which is always a top-level recipe node. Post-migrate backfills NULL -> TRUE on existing nodes. Sub: docs/superpowers/specs/2026-05-27-recipe-cert-toggles-design.md Task: T2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating',
|
'name': 'Fusion Plating',
|
||||||
'version': '19.0.21.4.0',
|
'version': '19.0.22.0.0',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1
|
||||||
|
"""Post-migrate for 19.0.22.0.0 — Recipe-level cert suppression Booleans.
|
||||||
|
|
||||||
|
Backfills NULL -> TRUE on the five new requires_* columns on
|
||||||
|
fusion.plating.process.node (requires_coc, requires_thickness_report,
|
||||||
|
requires_nadcap_cert, requires_mill_test, requires_customer_specific).
|
||||||
|
|
||||||
|
Default TRUE = inherit current behaviour for every existing recipe
|
||||||
|
(zero migration surprises — every existing recipe keeps producing
|
||||||
|
the same cert set it produces today).
|
||||||
|
|
||||||
|
Idempotent: safe to re-run.
|
||||||
|
|
||||||
|
Spec: docs/superpowers/specs/2026-05-27-recipe-cert-toggles-design.md
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate(cr, version):
|
||||||
|
if not version:
|
||||||
|
return
|
||||||
|
_logger.info(
|
||||||
|
'19.0.22.0.0 post-migrate: backfilling recipe cert-suppression '
|
||||||
|
'requires_* Booleans to TRUE on fusion.plating.process.node rows'
|
||||||
|
)
|
||||||
|
for col in (
|
||||||
|
'requires_coc',
|
||||||
|
'requires_thickness_report',
|
||||||
|
'requires_nadcap_cert',
|
||||||
|
'requires_mill_test',
|
||||||
|
'requires_customer_specific',
|
||||||
|
):
|
||||||
|
cr.execute(
|
||||||
|
"UPDATE fusion_plating_process_node SET %s = TRUE "
|
||||||
|
"WHERE %s IS NULL" % (col, col)
|
||||||
|
)
|
||||||
|
_logger.info(' %s: %d rows updated', col, cr.rowcount)
|
||||||
@@ -502,6 +502,56 @@ class FpProcessNode(models.Model):
|
|||||||
string='Requires Transition Form',
|
string='Requires Transition Form',
|
||||||
help='Sub 12b — opens the transition form before Mark Done.',
|
help='Sub 12b — opens the transition form before Mark Done.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Certificate Output — recipe-level cert suppression (2026-05-27 sub
|
||||||
|
# docs/superpowers/specs/2026-05-27-recipe-cert-toggles-design.md).
|
||||||
|
# Default True for all five so existing recipes keep producing the
|
||||||
|
# same cert set they produce today. A recipe author flips OFF only
|
||||||
|
# the types the recipe physically never produces (passivation = no
|
||||||
|
# thickness; commodity ENP = no nadcap).
|
||||||
|
#
|
||||||
|
# Precedence (Q1 locked decision): recipe SUPPRESSES ONLY. Customer
|
||||||
|
# / part flags decide what is requested; recipe can remove from that
|
||||||
|
# set but never add. See fp.job._resolve_required_cert_types.
|
||||||
|
#
|
||||||
|
# Surfaced on the recipe form only when node_type == 'recipe'; the
|
||||||
|
# fields exist on every node row but the UX hides them deeper in
|
||||||
|
# the tree to avoid confusing authors. Resolver reads from
|
||||||
|
# job.recipe_id which is always a top-level recipe node.
|
||||||
|
requires_coc = fields.Boolean(
|
||||||
|
string='Requires CoC',
|
||||||
|
default=True,
|
||||||
|
help='When False, this recipe never produces a Certificate of '
|
||||||
|
'Conformance even if the customer/part requested one.',
|
||||||
|
)
|
||||||
|
requires_thickness_report = fields.Boolean(
|
||||||
|
string='Requires Thickness Report',
|
||||||
|
default=True,
|
||||||
|
help='When False, this recipe never produces a thickness report. '
|
||||||
|
'Use for passivation, chemical conversion, anodize seal-only, '
|
||||||
|
'etc. — processes that physically have no plating thickness '
|
||||||
|
'to measure.',
|
||||||
|
)
|
||||||
|
requires_nadcap_cert = fields.Boolean(
|
||||||
|
string='Requires Nadcap Certificate',
|
||||||
|
default=True,
|
||||||
|
help='When False, this recipe never auto-spawns a Nadcap cert. '
|
||||||
|
'Use for commodity recipes that the shop does not run under '
|
||||||
|
'Nadcap accreditation.',
|
||||||
|
)
|
||||||
|
requires_mill_test = fields.Boolean(
|
||||||
|
string='Requires Mill Test Report',
|
||||||
|
default=True,
|
||||||
|
help='When False, this recipe never auto-spawns a Mill Test Report '
|
||||||
|
'cert.',
|
||||||
|
)
|
||||||
|
requires_customer_specific = fields.Boolean(
|
||||||
|
string='Requires Customer-Specific Cert',
|
||||||
|
default=True,
|
||||||
|
help='When False, this recipe never auto-spawns a Customer-Specific '
|
||||||
|
'cert.',
|
||||||
|
)
|
||||||
|
|
||||||
# Sub 14b — User-extensible Step Kinds (was Selection of 24).
|
# Sub 14b — User-extensible Step Kinds (was Selection of 24).
|
||||||
# 2026-05-20: required + ondelete='restrict' — kind drives gates,
|
# 2026-05-20: required + ondelete='restrict' — kind drives gates,
|
||||||
# workflow milestones, and operator routing. Optional was a foot-gun
|
# workflow milestones, and operator routing. Optional was a foot-gun
|
||||||
|
|||||||
Reference in New Issue
Block a user