Battle-tested complete workflow on entech: ABC Manufacturing + Anodize recipe (id=136) cloned to part-variant (id=1775) → SO S00276 confirmed → fp.job 1234 with 17 steps → recorded 56 measurement values exercising all 13 input types (incl. all 4 new types) → CoC chronological report renders 69KB with all values incl. photo thumbnails. Bugs found and fixed: 1. fp.process.node.input_ids missing copy=True — when a master recipe was cloned per-part (the standard variant pattern), the operator prompts on each step did NOT get copied to the variant. Result: jobs built from variants ran with zero prompts even though the master had them. Fixed: input_ids now copy=True so cloning auto-duplicates. 2. CoC chronological template read dest.input_ids where dest is fp.job.step. Steps don't carry input_ids — that field lives on the recipe node. Result: AttributeError aborted the entire CoC render. Fixed: walk via dest.recipe_node_id.input_ids; preserves the existing collect=True filter. 3. CoC chronological template used hasattr() in a t-value expression. QWeb's expression engine doesn't expose Python builtins, raised KeyError: 'hasattr'. Fixed: use 'collect' in i._fields instead. Also enhanced photo rendering in CoC: was just "[Attachment]" placeholder; now renders an actual <img> thumbnail (max 80px tall) plus the filename. Battle-test script saved to fusion_plating/scripts/bt_e2e_anodize_v2.py for re-runs / regression testing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Phase 3 recon — SO→job→step trigger pipeline."""
|
|
|
|
# Find recent confirmed SO with x_fc_process_variant_id set
|
|
sol = env['sale.order.line'].search([
|
|
('x_fc_process_variant_id', '!=', False),
|
|
], limit=5, order='id desc')
|
|
print('=== Recent SO lines with process variant ===')
|
|
for l in sol:
|
|
print(' SO=%s line=%d part=%s recipe=%s' % (
|
|
l.order_id.name, l.id, l.x_fc_part_catalog_id.part_number,
|
|
l.x_fc_process_variant_id.name,
|
|
))
|
|
|
|
# Pick one and trace its job
|
|
if sol:
|
|
target = sol[0]
|
|
so = target.order_id
|
|
print('\nFor SO %s state=%s' % (so.name, so.state))
|
|
job = env['fp.job'].search([('origin', '=', so.name)], limit=1)
|
|
print('Linked fp.job:', job.id if job else 'NONE')
|
|
if job:
|
|
steps = env['fp.job.step'].search([('job_id', '=', job.id)], order='sequence')
|
|
print(' steps: %d' % len(steps))
|
|
for s in steps[:8]:
|
|
recipe_node = s.recipe_node_id
|
|
input_count = len(recipe_node.input_ids) if recipe_node else 0
|
|
print(' [%s] %s -- recipe_node=%d inputs=%d state=%s' % (
|
|
s.sequence, s.name, recipe_node.id if recipe_node else 0,
|
|
input_count, s.state,
|
|
))
|
|
|
|
# Check whether default_kind exists on every step in the Anodize recipe
|
|
Node = env['fusion.plating.process.node']
|
|
anodize = Node.browse(136)
|
|
def collect_steps(n, out):
|
|
if n.node_type in ('step', 'operation'):
|
|
out.append(n)
|
|
for c in n.child_ids:
|
|
collect_steps(c, out)
|
|
|
|
steps = []
|
|
collect_steps(anodize, steps)
|
|
print('\n=== Anodize step audit ===')
|
|
print('Total step/operation nodes:', len(steps))
|
|
no_kind = [s for s in steps if not s.default_kind]
|
|
print('Without default_kind:', len(no_kind))
|
|
for s in no_kind[:8]:
|
|
print(' - %s (type=%s)' % (s.name, s.node_type))
|