refactor(jobs): gate fp.job lifecycle hooks on fp_jobs_migration context
Migration script now sets context fp_jobs_migration=True before creating fp.job records. action_confirm and button_mark_done check this flag and skip side-effects (portal job creation, QC check, racking inspection, delivery, certificate, notification dispatch) when migrating. Without this, the migration would double-create portal jobs / QC checks / racking inspections — once via bridge_mrp's original create on the source MO, once via jobs module's lifecycle hook on the new fp.job mirror. With the gate, the migration script explicitly rebinds the existing dependents via x_fc_job_id. Manifest 19.0.2.0.0 → 19.0.2.1.0. Part of: native job model migration (spec 2026-04-25) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Native Jobs',
|
'name': 'Fusion Plating — Native Jobs',
|
||||||
'version': '19.0.2.0.0',
|
'version': '19.0.2.1.0',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -267,6 +267,11 @@ class FpJob(models.Model):
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
def action_confirm(self):
|
def action_confirm(self):
|
||||||
result = super().action_confirm()
|
result = super().action_confirm()
|
||||||
|
# During migration, lifecycle side-effects are skipped — the
|
||||||
|
# migration script directly rebinds existing portal/QC/inspection
|
||||||
|
# records via x_fc_job_id. See scripts/migrate_to_fp_jobs.py.
|
||||||
|
if self.env.context.get('fp_jobs_migration'):
|
||||||
|
return result
|
||||||
for job in self:
|
for job in self:
|
||||||
job._fp_create_portal_job()
|
job._fp_create_portal_job()
|
||||||
job._fp_create_qc_check_if_needed()
|
job._fp_create_qc_check_if_needed()
|
||||||
@@ -383,6 +388,8 @@ class FpJob(models.Model):
|
|||||||
- Auto-creates a draft fusion.plating.delivery
|
- Auto-creates a draft fusion.plating.delivery
|
||||||
- Triggers certificate auto-generation (best-effort)
|
- Triggers certificate auto-generation (best-effort)
|
||||||
"""
|
"""
|
||||||
|
# During migration, side-effects are skipped — see action_confirm.
|
||||||
|
skip_side_effects = self.env.context.get('fp_jobs_migration')
|
||||||
for job in self:
|
for job in self:
|
||||||
if job.state == 'done':
|
if job.state == 'done':
|
||||||
continue
|
continue
|
||||||
@@ -392,9 +399,10 @@ class FpJob(models.Model):
|
|||||||
)
|
)
|
||||||
job.state = 'done'
|
job.state = 'done'
|
||||||
job.date_finished = fields.Datetime.now()
|
job.date_finished = fields.Datetime.now()
|
||||||
job._fp_create_delivery()
|
if not skip_side_effects:
|
||||||
job._fp_create_certificates()
|
job._fp_create_delivery()
|
||||||
job._fp_fire_notification('job_complete')
|
job._fp_create_certificates()
|
||||||
|
job._fp_fire_notification('job_complete')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -391,6 +391,12 @@ def run(env):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
print('=== Migration starting ===')
|
print('=== Migration starting ===')
|
||||||
|
# The fp_jobs_migration context flag tells fp.job.action_confirm and
|
||||||
|
# fp.job.button_mark_done to skip lifecycle side-effects (creating
|
||||||
|
# portal jobs, QC checks, racking inspections, deliveries, certs,
|
||||||
|
# notifications). The migration script rebinds existing records via
|
||||||
|
# x_fc_job_id directly — so the side-effects would create duplicates.
|
||||||
|
env = env(context=dict(env.context, fp_jobs_migration=True))
|
||||||
MO = env['mrp.production']
|
MO = env['mrp.production']
|
||||||
all_mos = MO.search([])
|
all_mos = MO.search([])
|
||||||
print('Migrating %d MOs and their WOs...' % len(all_mos))
|
print('Migrating %d MOs and their WOs...' % len(all_mos))
|
||||||
|
|||||||
Reference in New Issue
Block a user