changes
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating — Notifications',
|
||||
'version': '19.0.6.4.0',
|
||||
'version': '19.0.6.6.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Auto-email notifications at workflow milestones with configurable templates, PDF attachments, and audit log.',
|
||||
'author': 'Nexa Systems Inc.',
|
||||
@@ -22,6 +22,7 @@
|
||||
'fusion_plating_invoicing',
|
||||
'fusion_plating_logistics',
|
||||
'fusion_plating_reports',
|
||||
'fusion_shipping',
|
||||
'sale_management',
|
||||
'account',
|
||||
'mail',
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="fp_notif_shipment_labeled" model="fp.notification.template">
|
||||
<field name="name">Shipping Label Generated</field>
|
||||
<field name="trigger_event">shipment_labeled</field>
|
||||
<field name="mail_template_id" ref="fp_mail_template_shipment_labeled"/>
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="fp_notif_shipped" model="fp.notification.template">
|
||||
<field name="name">Shipped / Delivered</field>
|
||||
<field name="trigger_event">shipped</field>
|
||||
|
||||
@@ -184,6 +184,70 @@
|
||||
fp.notification.template's `job_complete` trigger, defined
|
||||
in fp_notification_template_data.xml. -->
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- 4b. Shipping Label Generated (Info, #2B6CB0) -->
|
||||
<!-- Fires when fusion.shipment.tracking_number first lands. -->
|
||||
<!-- Customer gets the tracking link BEFORE the package goes -->
|
||||
<!-- out the door, so they can monitor from pickup. -->
|
||||
<!-- ============================================================= -->
|
||||
<record id="fp_mail_template_shipment_labeled" model="mail.template">
|
||||
<field name="name">FP: Shipping Label Generated</field>
|
||||
<field name="model_id" ref="fusion_shipping.model_fusion_shipment"/>
|
||||
<field name="subject">Tracking #{{ object.tracking_number }} — your order is being prepared for shipment</field>
|
||||
<field name="email_from">{{ (object.company_id.email or user.email) }}</field>
|
||||
<field name="email_to">{{ (object.sale_order_id and object.sale_order_id.partner_id.email) or '' }}</field>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html" type="html">
|
||||
<div style="font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif; max-width: 600px; margin: 0 auto; padding: 32px 24px;">
|
||||
<div style="height: 4px; background-color: #2B6CB0; margin-bottom: 28px;"></div>
|
||||
<div style="font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #2B6CB0; font-weight: 600; margin-bottom: 8px;">
|
||||
EN Technologies
|
||||
</div>
|
||||
<h2 style="margin: 0 0 8px 0; font-size: 22px; font-weight: bold;">Your Order Is Being Prepared for Shipment</h2>
|
||||
<p style="margin: 0 0 20px 0; font-size: 15px; opacity: 0.65;">
|
||||
Hi <t t-out="object.sale_order_id.partner_id.name or ''"/>, the shipping label has been generated for your order. Tracking starts as soon as our shipping crew hands the package to the carrier.
|
||||
</p>
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
|
||||
<tr style="border-bottom: 2px solid rgba(128,128,128,0.35);">
|
||||
<th style="text-align: left; padding: 8px 4px; font-size: 12px; text-transform: uppercase; opacity: 0.55; font-weight: 600;">Shipment</th>
|
||||
<th style="text-align: right; padding: 8px 4px; font-size: 12px; text-transform: uppercase; opacity: 0.55; font-weight: 600;">Detail</th>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid rgba(128,128,128,0.25);">
|
||||
<td style="padding: 8px 4px;">Sale Order</td>
|
||||
<td style="padding: 8px 4px; text-align: right; font-family: monospace;"><t t-out="object.sale_order_id.name or '—'"/></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid rgba(128,128,128,0.25); background: rgba(128,128,128,0.06);">
|
||||
<td style="padding: 8px 4px;">Carrier</td>
|
||||
<td style="padding: 8px 4px; text-align: right;"><t t-out="object.carrier_id.name or '—'"/></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid rgba(128,128,128,0.25);">
|
||||
<td style="padding: 8px 4px;">Tracking Number</td>
|
||||
<td style="padding: 8px 4px; text-align: right; font-family: monospace; font-weight: bold;"><t t-out="object.tracking_number or '—'"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div t-if="object.x_fc_tracking_url" style="margin: 24px 0; text-align: center;">
|
||||
<a t-att-href="object.x_fc_tracking_url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style="display: inline-block; padding: 12px 28px; background-color: #2B6CB0; color: #ffffff; text-decoration: none; font-weight: 600; border-radius: 4px;">
|
||||
Track Shipment
|
||||
</a>
|
||||
</div>
|
||||
<div style="border-left: 3px solid #2B6CB0; padding: 12px 16px; margin: 20px 0; font-size: 14px;">
|
||||
<strong>What's next:</strong> Once the carrier collects the package, you'll receive a Shipped confirmation with the Certificate of Conformance attached.
|
||||
</div>
|
||||
<div style="margin-top: 32px; font-size: 14px;">
|
||||
Best regards,<br/>
|
||||
<strong><t t-out="user.name or ''"/></strong><br/>
|
||||
EN Technologies Inc.
|
||||
</div>
|
||||
<div style="margin-top: 40px; padding-top: 16px; border-top: 1px solid rgba(128,128,128,0.25); font-size: 11px; opacity: 0.5; text-align: center;">
|
||||
This is an automated notification from EN Technologies production system.
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- 5. Shipped / Delivered (Success, #38a169) -->
|
||||
<!-- ============================================================= -->
|
||||
|
||||
@@ -15,3 +15,4 @@ from . import account_payment
|
||||
# fires from fp.job.button_mark_done -> _fp_fire_notification('job_complete').
|
||||
# from . import mrp_production
|
||||
from . import fp_delivery
|
||||
from . import fusion_shipment
|
||||
|
||||
@@ -16,6 +16,7 @@ TRIGGER_EVENTS = [
|
||||
('mo_complete', 'Manufacturing Complete'), # legacy, fired by mrp; kept for back-compat
|
||||
('job_confirmed', 'Plating Job Confirmed'), # Sub 11 — fp.job lifecycle
|
||||
('job_complete', 'Plating Job Complete'), # Sub 11 — fp.job.button_mark_done
|
||||
('shipment_labeled', 'Shipping Label Generated'), # Phase C — fired when tracking_number lands on fusion.shipment
|
||||
('shipped', 'Shipped / Delivered'),
|
||||
('invoice_posted', 'Invoice Posted'),
|
||||
('payment_received', 'Payment Received'),
|
||||
@@ -36,6 +37,7 @@ FP_TRIGGER_STREAM = {
|
||||
'mo_complete': 'qc',
|
||||
'job_confirmed': 'qc',
|
||||
'job_complete': 'qc',
|
||||
'shipment_labeled': 'certs',
|
||||
'shipped': 'certs',
|
||||
'invoice_posted': 'invoices',
|
||||
'payment_received': 'invoices',
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""Phase C — fire 'shipment_labeled' notification when tracking_number
|
||||
lands on a fusion.shipment for the first time.
|
||||
|
||||
Triggers regardless of how tracking got set: live API call or manual
|
||||
fallback wizard. Customer gets the tracking link as soon as the label
|
||||
is generated, not after the package physically ships (that's the
|
||||
existing 'shipped' event on fp.delivery)."""
|
||||
import logging
|
||||
|
||||
from odoo import models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FusionShipment(models.Model):
|
||||
_inherit = 'fusion.shipment'
|
||||
|
||||
def write(self, vals):
|
||||
# Identify shipments that gain a tracking number for the first
|
||||
# time. Done BEFORE super().write so we can compare before/after.
|
||||
will_fire = self.browse()
|
||||
if 'tracking_number' in vals and vals.get('tracking_number'):
|
||||
will_fire = self.filtered(lambda s: not s.tracking_number)
|
||||
res = super().write(vals)
|
||||
if not will_fire:
|
||||
return res
|
||||
Dispatch = self.env.get('fp.notification.template')
|
||||
if Dispatch is None:
|
||||
return res
|
||||
for ship in will_fire:
|
||||
partner = (
|
||||
ship.sale_order_id.partner_id
|
||||
if ship.sale_order_id else False
|
||||
)
|
||||
if not partner:
|
||||
continue
|
||||
try:
|
||||
Dispatch._dispatch(
|
||||
'shipment_labeled',
|
||||
ship,
|
||||
partner,
|
||||
sale_order=ship.sale_order_id or False,
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.warning(
|
||||
'Shipment %s: shipment_labeled dispatch failed: %s',
|
||||
ship.name, e,
|
||||
)
|
||||
return res
|
||||
Reference in New Issue
Block a user