fix(configurator/bridge_mrp): address all bugs from code review
Two critical, one important, four polish fixes found by the
pr-review-toolkit code-reviewer.
C1 (CRITICAL) Start-at-node filter dropped later siblings
fusion_plating_bridge_mrp/models/mrp_production.py:448
The allowed_ids set was {descendants} ∪ {ancestors}, which wrongly
excluded nodes that should run AFTER the start node — including
later siblings of the start node and all operations in subsequent
sub-processes. Rewrote the upward walk to ALSO include each
ancestor's later-sequence siblings and their descendants. Smoke on
ENP-ALUM-BASIC: full=9 WOs, partial from mid-tree 'De-Masking'=5
WOs (previously was 1).
C2 (CRITICAL) Duplicate MO on re-confirm of pre-PR SOs
fusion_plating_bridge_mrp/models/sale_order.py:96
Legacy untagged MOs (created before this PR had line-linkage m2m)
were not recognized by the untagged idempotency check, so
re-confirming an already-processed SO would create one additional
MO per untagged plating line. Fix: pre-scan for a single legacy
untagged MO and adopt it by linking ALL untagged plating lines
onto it. Those lines are then treated as covered and no per-line
MOs are created on top. Smoke: S00066 before=1 MO, after
re-run=1 MO.
I5 (IMPORTANT) push_to_defaults wrote to pre-bump revision
fusion_plating_configurator/wizard/fp_direct_order_wizard.py:236
When create_new_revision=True, _get_or_bump_revision() returned a
new part record that got written to the SO line, but the
post-confirm push_to_defaults loop re-read line.part_catalog_id
(still the OLD rev) and wrote defaults there, defeating the whole
point of "save as default". Fix: cache resolved parts in a dict
keyed by wizard-line ID during the build loop, and use that cache
in the push_to_defaults pass.
I3/I4/I6 (PERF) Computes lacked @api.depends and did per-record
search_count / search queries
fusion_plating_configurator/models/sale_order.py
_compute_nav_counts, _compute_workorder_count, _compute_wo_completion
now:
- declare @api.depends
- batch via read_group across the whole self recordset
- rebuild {origin: counts} dicts and assign per record
M7 (MEDIUM) No savepoint around per-group MO creation
fusion_plating_bridge_mrp/models/sale_order.py:_fp_auto_create_mo
A mid-loop exception left group 1's MO persisted and aborted
groups 2..N. Wrapped each group's create in SAVEPOINT/RELEASE/
ROLLBACK TO SAVEPOINT so one bad group no longer corrupts state.
M8 (MEDIUM) Email 'opened' status false-positived on internal CC
fusion_plating_configurator/models/sale_order.py:_compute_email_status
Switched from 'any notification is_read' to 'customer partner has
a read email notification on this SO'.
M9 (LOW) start_at_node_id domain silently empty when coating unset
fusion_plating_configurator/wizard/fp_direct_order_line.py:94
Changed `('parent_id', 'child_of', ...)` to
`('id', 'child_of', ..., or 0)` and clarified the help text.
Regression smoke passed all checks on odoo-entech.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -94,9 +94,11 @@ class FpDirectOrderLine(models.TransientModel):
|
||||
start_at_node_id = fields.Many2one(
|
||||
'fusion.plating.process.node',
|
||||
string='Start at Node',
|
||||
domain="[('parent_id', 'child_of', coating_config_id and coating_config_id.recipe_id.id)]",
|
||||
domain="[('id', 'child_of', coating_config_id and coating_config_id.recipe_id.id or 0)]",
|
||||
help='For re-work jobs: pick the recipe step where this job should '
|
||||
'begin. Skips ancestor steps in the generated work order.',
|
||||
'begin. Pick a coating first — nodes are scoped to its '
|
||||
'recipe tree. Skips earlier steps in the generated WO but '
|
||||
'keeps later siblings and sub-processes.',
|
||||
)
|
||||
is_one_off = fields.Boolean(
|
||||
string='One-off Part',
|
||||
|
||||
@@ -235,9 +235,13 @@ class FpDirectOrderWizard(models.TransientModel):
|
||||
'order_line': [],
|
||||
}
|
||||
|
||||
# 4. One SO line per wizard line
|
||||
# 4. One SO line per wizard line. Cache resolved parts (post
|
||||
# rev-bump) so the push-to-defaults pass writes to the right
|
||||
# catalog entry.
|
||||
resolved_parts = {} # {wizard_line_id: resolved part record}
|
||||
for line in self.line_ids:
|
||||
part = line._get_or_bump_revision()
|
||||
resolved_parts[line.id] = part
|
||||
header = '%s - %s Rev %s (x%d)' % (
|
||||
line.coating_config_id.name,
|
||||
part.name,
|
||||
@@ -270,14 +274,14 @@ class FpDirectOrderWizard(models.TransientModel):
|
||||
so = self.env['sale.order'].create(so_vals)
|
||||
so.action_confirm()
|
||||
|
||||
# 6. Push-to-defaults (C4) — after the part has been resolved /
|
||||
# revision-bumped, write coating + treatments back onto the part
|
||||
# catalog entry so the next order inherits the same defaults.
|
||||
# 6. Push-to-defaults (C4) — uses the resolved part cached
|
||||
# during the build loop so rev-bumped lines write defaults to
|
||||
# the NEW revision, not the pre-bump one.
|
||||
for line in self.line_ids:
|
||||
if not line.push_to_defaults:
|
||||
if not line.push_to_defaults or line.is_one_off:
|
||||
continue
|
||||
part = line.part_catalog_id
|
||||
if not part or line.is_one_off:
|
||||
part = resolved_parts.get(line.id) or line.part_catalog_id
|
||||
if not part:
|
||||
continue
|
||||
part.write({
|
||||
'x_fc_default_coating_config_id': line.coating_config_id.id or False,
|
||||
|
||||
Reference in New Issue
Block a user