feat(jobs): Phase 4 light refactors — notifications, KPI source tag

- Adds 'job_confirmed' and 'job_complete' trigger events to
  fp.notification.template (legacy 'mo_confirmed' / 'mo_complete'
  stay for bridge_mrp).
- fp.job.action_confirm and button_mark_done now fire those
  notifications best-effort via fp.notification.template._dispatch
  (silent skip if templates absent or notifications module missing).
- Adds x_fc_source ['mrp', 'jobs'] tag to fusion.plating.kpi.value
  so Phase 9 dashboards can filter or display both sources.
- Verified aerospace/nuclear/cgp/safety modules don't directly
  reference mrp.production or mrp.workorder.

Configurator integration was already covered by Task 2.5's SO
confirm hook (reads x_fc_part_catalog_id and x_fc_coating_config_id
from sale.order.line).

Manifest 19.0.1.6.0 -> 19.0.1.7.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:
gsinghpal
2026-04-24 23:38:38 -04:00
parent b359be3745
commit 51a5cbbe5d
6 changed files with 136 additions and 1 deletions

View File

@@ -19,3 +19,7 @@ from . import fp_certificate
from . import fp_thickness_reading
from . import fp_delivery
from . import fp_racking_inspection
# Phase 4 — light refactors batch B (notifications, KPI source tag).
from . import fp_notification_trigger
from . import fusion_plating_kpi_value

View File

@@ -260,6 +260,7 @@ class FpJob(models.Model):
job._fp_create_portal_job()
job._fp_create_qc_check_if_needed()
job._fp_create_racking_inspection()
job._fp_fire_notification('job_confirmed')
return result
def _fp_create_racking_inspection(self):
@@ -382,8 +383,43 @@ class FpJob(models.Model):
job.date_finished = fields.Datetime.now()
job._fp_create_delivery()
job._fp_create_certificates()
job._fp_fire_notification('job_complete')
return True
# ------------------------------------------------------------------
# Notifications dispatch (Phase 4)
#
# Fires fp.notification.template records whose trigger_event matches
# the given event name. Best-effort: silently skips if the
# fusion_plating_notifications module is not installed (model not
# registered) and logs (without raising) on any send failure so the
# job lifecycle is never blocked by an email problem.
# ------------------------------------------------------------------
def _fp_fire_notification(self, event):
"""Best-effort notification dispatch for fp.job lifecycle events.
Looks up fp.notification.template records with the matching
trigger_event and dispatches via the central _dispatch helper
provided by fusion_plating_notifications. Silently no-ops when
that module isn't installed.
"""
self.ensure_one()
if 'fp.notification.template' not in self.env:
return
Template = self.env['fp.notification.template'].sudo()
try:
# The notifications module exposes a model-level _dispatch
# helper that handles template lookup, recipient resolution
# (Sub 6 contact routing), attachment rendering, and audit
# logging in one go. Pass partner explicitly since fp.job's
# partner_id is the customer.
Template._dispatch(event, self, partner=self.partner_id)
except Exception as e:
_logger.warning(
"Job %s: notification %s dispatch failed: %s",
self.name, event, e,
)
def _fp_create_delivery(self):
"""Create a draft fusion.plating.delivery linked to this job."""
self.ensure_one()

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
#
# Adds 'job_confirmed' and 'job_complete' trigger events to the
# fp.notification.template selection. Fired from fp.job lifecycle
# hooks (action_confirm, button_mark_done).
#
# bridge_mrp's existing 'mo_confirmed' / 'mo_complete' triggers
# stay alive for the legacy MO flow.
from odoo import fields, models
class FpNotificationTemplate(models.Model):
_inherit = 'fp.notification.template'
trigger_event = fields.Selection(
selection_add=[
('job_confirmed', 'Plating Job Confirmed'),
('job_complete', 'Plating Job Complete'),
],
ondelete={
'job_confirmed': 'cascade',
'job_complete': 'cascade',
},
)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
#
# Tags KPI values by source: 'mrp' (legacy bridge_mrp rollups) vs
# 'jobs' (native fp.job rollups). Lets Phase 9 / Phase 10 dashboards
# show both side-by-side or filter to one.
from odoo import fields, models
class FusionPlatingKpiValue(models.Model):
_inherit = 'fusion.plating.kpi.value'
x_fc_source = fields.Selection(
[
('mrp', 'MRP (legacy)'),
('jobs', 'Native Jobs'),
],
string='Data Source',
default='mrp',
index=True,
help='Which data path produced this KPI value. Phase 9+ '
'rollups from fp.job/fp.job.step set this to jobs.',
)