feat(jobs): add x_fc_use_native_jobs flag + SO confirm hook (Task 2.5)
Settings flag controls which SO confirm path runs. Default False keeps the legacy bridge_mrp / mrp.production flow on entech. Setting True diverts confirm into fp.job creation. Both hooks coexist — bridge_mrp's _fp_auto_create_mo and the new _fp_auto_create_job — but only one creates records per SO confirm (controlled by the flag). The new _fp_auto_create_job mirrors bridge_mrp's grouping logic (x_fc_wo_group_tag), recipe resolution (coating → part), and traceability fields (origin, sale_order_line_ids). Settings UI shows the flag in a 'Fusion Plating Jobs' app section of the standard Configuration menu. 3 new tests cover: flag off no-op, flag on creates job, idempotency. Manifest 19.0.1.3.0 → 19.0.1.4.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:
@@ -260,3 +260,75 @@ class TestFpJobStepsGenerator(TransactionCase):
|
||||
self.assertEqual(first_step.duration_expected, 30.0)
|
||||
# Work centre resolved by code from legacy model
|
||||
self.assertEqual(first_step.work_centre_id, self.wc)
|
||||
|
||||
|
||||
class TestSoConfirmHook(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.partner = self.env['res.partner'].create({'name': 'C'})
|
||||
self.product = self.env['product.product'].create({'name': 'P'})
|
||||
self.ICP = self.env['ir.config_parameter'].sudo()
|
||||
|
||||
def _make_so_with_plating_line(self, **line_vals):
|
||||
# client_order_ref satisfies the fusion_plating_invoicing PO# gate.
|
||||
so_vals = {
|
||||
'partner_id': self.partner.id,
|
||||
'client_order_ref': 'TEST-PO-001',
|
||||
}
|
||||
so = self.env['sale.order'].create(so_vals)
|
||||
line_defaults = {
|
||||
'order_id': so.id,
|
||||
'product_id': self.product.id,
|
||||
'product_uom_qty': 5.0,
|
||||
'price_unit': 10.0,
|
||||
}
|
||||
line_defaults.update(line_vals)
|
||||
self.env['sale.order.line'].create(line_defaults)
|
||||
return so
|
||||
|
||||
def test_flag_off_no_job_created(self):
|
||||
# Default flag is False
|
||||
self.ICP.set_param('fusion_plating_jobs.use_native_jobs', 'False')
|
||||
so = self._make_so_with_plating_line()
|
||||
so.action_confirm()
|
||||
jobs = self.env['fp.job'].search([('sale_order_id', '=', so.id)])
|
||||
self.assertFalse(jobs)
|
||||
|
||||
def test_flag_on_creates_job(self):
|
||||
self.ICP.set_param('fusion_plating_jobs.use_native_jobs', 'True')
|
||||
# Need a plating line — add x_fc_part_catalog_id if available
|
||||
if 'x_fc_part_catalog_id' in self.env['sale.order.line']._fields:
|
||||
partner_for_part = self.env['res.partner'].create({'name': 'PartOwner'})
|
||||
part = self.env['fp.part.catalog'].create({
|
||||
'name': 'TPart', 'part_number': 'TP-1',
|
||||
'partner_id': partner_for_part.id,
|
||||
})
|
||||
so = self._make_so_with_plating_line(x_fc_part_catalog_id=part.id)
|
||||
so.action_confirm()
|
||||
jobs = self.env['fp.job'].search([('sale_order_id', '=', so.id)])
|
||||
self.assertEqual(len(jobs), 1)
|
||||
self.assertEqual(jobs.qty, 5.0)
|
||||
self.assertEqual(jobs.part_catalog_id, part)
|
||||
self.assertEqual(jobs.origin, so.name)
|
||||
else:
|
||||
self.skipTest('x_fc_part_catalog_id field not present on sale.order.line')
|
||||
|
||||
def test_flag_on_idempotent(self):
|
||||
self.ICP.set_param('fusion_plating_jobs.use_native_jobs', 'True')
|
||||
if 'x_fc_part_catalog_id' in self.env['sale.order.line']._fields:
|
||||
partner_for_part = self.env['res.partner'].create({'name': 'PO'})
|
||||
part = self.env['fp.part.catalog'].create({
|
||||
'name': 'IdemPart', 'part_number': 'IP-1',
|
||||
'partner_id': partner_for_part.id,
|
||||
})
|
||||
so = self._make_so_with_plating_line(x_fc_part_catalog_id=part.id)
|
||||
so.action_confirm()
|
||||
count_after_first = self.env['fp.job'].search_count(
|
||||
[('sale_order_id', '=', so.id)])
|
||||
# Calling action_confirm again should NOT create a duplicate
|
||||
so._fp_auto_create_job()
|
||||
count_after_second = self.env['fp.job'].search_count(
|
||||
[('sale_order_id', '=', so.id)])
|
||||
self.assertEqual(count_after_first, count_after_second)
|
||||
else:
|
||||
self.skipTest('x_fc_part_catalog_id field not present')
|
||||
|
||||
Reference in New Issue
Block a user