feat(sub12a): extend process.node + process.node.input

process.node — additive only:
  is_template, source_template_id, tank_ids (M2M to fusion.plating.tank
  with new join table fp_node_tank_rel), material_callout, time/temp
  targets + units, voltage_target, viscosity_target,
  requires_rack_assignment, requires_transition_form, default_kind,
  preferred_editor.

process.node.input — additive only:
  kind (step_input/transition_input, default step_input so existing
  rows keep working), target_min/target_max/target_unit, compliance_tag,
  plus 9 new typed input_type values (time_hms, time_seconds,
  temperature, thickness, pass_fail, date, signature, location_picker,
  customer_wo).

No removed fields, no removed selection values. Tree editor + every
existing battle test (S14/S15/S17/S18/S19) untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-27 20:33:11 -04:00
parent 7a0e74c456
commit 91681d722e

View File

@@ -284,6 +284,88 @@ class FpProcessNode(models.Model):
string='Operator Inputs',
)
# ===== Sub 12a — Simple Editor + Step Library extensions =================
# All fields are additive; tree editor + runtime are unaffected. Drag-drop
# from the library snapshot-copies these into a new node (no live ref).
is_template = fields.Boolean(
string='Use as Starter Template',
help='When True (and node_type=recipe), this recipe appears in the '
'Simple Editor\'s "Import starter from template" dropdown.',
)
source_template_id = fields.Many2one(
'fp.step.template',
string='Source Library Template',
ondelete='set null',
index=True,
help='Snapshot trace — set when this node was created by dragging '
'a library step in. Editing the template later does not change '
'this node (snapshot semantics).',
)
tank_ids = fields.Many2many(
'fusion.plating.tank',
'fp_node_tank_rel', 'node_id', 'tank_id',
string='Allowed Stations',
help='Stations the operator may pick at runtime.',
)
material_callout = fields.Char(
string='Material Callout',
help='Short string for traveller "Material" column. Defaults to '
'process type name if blank.',
)
time_min_target = fields.Float(string='Time Min')
time_max_target = fields.Float(string='Time Max')
time_unit = fields.Selection(
[('sec', 'Seconds'), ('min', 'Minutes'), ('hr', 'Hours')],
string='Time Unit', default='min',
)
temp_min_target = fields.Float(string='Temp Min')
temp_max_target = fields.Float(string='Temp Max')
temp_unit = fields.Selection(
[('F', '°F'), ('C', '°C')],
string='Temp Unit', default='F',
)
voltage_target = fields.Float(string='Voltage Target')
viscosity_target = fields.Float(string='Viscosity Target')
requires_rack_assignment = fields.Boolean(
string='Requires Rack Assignment',
help='Sub 12b — triggers Rack Parts sub-dialog at runtime.',
)
requires_transition_form = fields.Boolean(
string='Requires Transition Form',
help='Sub 12b — opens the transition form before Mark Done.',
)
default_kind = fields.Selection(
[
('cleaning', 'Cleaning'),
('etch', 'Etch'),
('rinse', 'Rinse'),
('plate', 'Plating'),
('bake', 'Bake'),
('inspect', 'Inspection'),
('racking', 'Racking'),
('derack', 'De-Racking'),
('mask', 'Masking'),
('demask', 'De-Masking'),
('dry', 'Drying'),
('wbf_test', 'Water Break Free Test'),
('final_inspect', 'Final Inspection'),
('ship', 'Shipping'),
('gating', 'Gating'),
],
string='Step Kind',
)
preferred_editor = fields.Selection(
[
('tree', 'Tree Editor'),
('simple', 'Simple Editor'),
('auto', 'Use Company Default'),
],
string='Preferred Editor', default='auto',
help='Which editor opens when this recipe is selected from the '
'menu list. "Auto" follows the company-level default.',
)
# ---- SQL constraints -----------------------------------------------------
_sql_constraints = [
@@ -504,6 +586,16 @@ class FpProcessNodeInput(models.Model):
('boolean', 'Yes / No'),
('selection', 'Selection'),
('photo', 'Photo'),
# Sub 12a — typed inputs the simple editor + traveller need
('time_hms', 'Time (HH:MM:SS)'),
('time_seconds', 'Time (seconds)'),
('temperature', 'Temperature'),
('thickness', 'Thickness'),
('pass_fail', 'Pass / Fail'),
('date', 'Date / Time'),
('signature', 'Signature'),
('location_picker', 'Location Picker'),
('customer_wo', 'Customer WO #'),
],
string='Input Type',
required=True,
@@ -529,3 +621,28 @@ class FpProcessNodeInput(models.Model):
string='Unit',
help='Unit label (e.g. °C, min, psi).',
)
# ===== Sub 12a — kind + target ranges + compliance tag ==================
kind = fields.Selection(
[
('step_input', 'Step Measurement'),
('transition_input', 'Transition Form Field'),
],
string='Kind', default='step_input', index=True,
help='step_input = recorded during the step. transition_input = '
'recorded when leaving the step (Sub 12b uses these in the '
'Move Parts dialog).',
)
target_min = fields.Float(string='Target Min')
target_max = fields.Float(string='Target Max')
target_unit = fields.Char(string='Target Unit')
compliance_tag = fields.Selection(
[
('none', 'None'),
('as9100', 'AS9100'),
('nadcap', 'Nadcap'),
('cgp', 'Controlled Goods'),
('nuclear', 'Nuclear'),
],
string='Compliance Tag', default='none',
)