feat(jobs): Phase 7 — migration script + legacy id fields
Adds legacy_mrp_production_id (Integer index) on fp.job and
legacy_mrp_workorder_id on fp.job.step. Used as the idempotency
key during cutover migration.
Three scripts under fusion_plating_jobs/scripts/:
- audit_pre_migration.py — counts and data-quality concerns BEFORE
- migrate_to_fp_jobs.py — copies MO->fp.job, WO->fp.job.step, time
logs, rebinds cross-refs (batches,
holds, certs, readings, portals,
inspections, deliveries). Idempotent.
- audit_post_migration.py — counts and verifies AFTER
Migration is run manually from \`odoo shell\` at cutover (not as
auto post-migration hook, for safety). README explains usage.
Tests verify the legacy id fields exist and the migration script
files are well-formed Python.
Manifest 19.0.1.9.0 -> 19.0.2.0.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:
@@ -574,3 +574,63 @@ class TestPhase6Controllers(TransactionCase):
|
||||
step_by_node = {s.recipe_node_id.id: s for s in self.job.step_ids if s.recipe_node_id}
|
||||
self.assertIn(op.id, step_by_node)
|
||||
self.assertEqual(step_by_node[op.id].name, 'Op1')
|
||||
|
||||
|
||||
class TestPhase7Migration(TransactionCase):
|
||||
"""Phase 7 — verify the migration script idempotency-key fields are
|
||||
in place and the script files are present + parse as valid Python.
|
||||
|
||||
We cannot run the migration end-to-end in a unit test (it would need
|
||||
a populated MO/WO snapshot). Instead we assert the scaffolding is
|
||||
solid: fields exist, files are well-formed.
|
||||
"""
|
||||
|
||||
def test_legacy_id_field_on_fp_job(self):
|
||||
self.assertIn(
|
||||
'legacy_mrp_production_id',
|
||||
self.env['fp.job']._fields,
|
||||
)
|
||||
# Should be Integer (we store the raw db id, not a Many2one — the
|
||||
# source MO may be archived later without breaking the link).
|
||||
self.assertEqual(
|
||||
self.env['fp.job']._fields['legacy_mrp_production_id'].type,
|
||||
'integer',
|
||||
)
|
||||
|
||||
def test_legacy_id_field_on_fp_job_step(self):
|
||||
self.assertIn(
|
||||
'legacy_mrp_workorder_id',
|
||||
self.env['fp.job.step']._fields,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.env['fp.job.step']._fields['legacy_mrp_workorder_id'].type,
|
||||
'integer',
|
||||
)
|
||||
|
||||
def test_migration_script_files_exist_and_parse(self):
|
||||
# Sanity check that the script files we ship are valid Python.
|
||||
# Catches syntax errors that would otherwise only surface on the
|
||||
# cutover engineer's screen at the worst possible moment.
|
||||
import ast
|
||||
from pathlib import Path
|
||||
scripts_dir = (
|
||||
Path(__file__).parent.parent / 'scripts'
|
||||
)
|
||||
for script in (
|
||||
'audit_pre_migration.py',
|
||||
'migrate_to_fp_jobs.py',
|
||||
'audit_post_migration.py',
|
||||
):
|
||||
path = scripts_dir / script
|
||||
self.assertTrue(path.exists(), '%s missing' % script)
|
||||
with open(path) as f:
|
||||
ast.parse(f.read()) # Will raise SyntaxError if invalid
|
||||
|
||||
def test_scripts_dir_is_a_python_package(self):
|
||||
# __init__.py exists so Odoo's autodiscovery doesn't trip and the
|
||||
# dir is importable for hypothetical future post-migration hooks.
|
||||
from pathlib import Path
|
||||
init = (
|
||||
Path(__file__).parent.parent / 'scripts' / '__init__.py'
|
||||
)
|
||||
self.assertTrue(init.exists())
|
||||
|
||||
Reference in New Issue
Block a user