feat(logistics): auto-generate packing slip on local delivery dispatch
fusion.plating.delivery already had packing_list_attachment_id + a viewer action, but nothing populated it — shipping a local delivery produced no packing slip. Add _fp_generate_packing_slip(): renders fusion_plating_reports.action_report_fp_packing_slip_portrait and stores it on packing_list_attachment_id. Hooked into action_start_route (the dispatch / loaded-on-vehicle moment, so it travels with the goods) and as a generate-if-missing catch-all on action_mark_delivered. Idempotent (skips deliveries that already have one unless force=True) and best-effort (a report glitch logs + continues, never blocks shipping). Report action resolved at runtime so logistics keeps no hard dep on fusion_plating_reports. Deployed + verified on entech (12.8KB PDF for DLV-30097, rolled back). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,16 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
# Part of the Fusion Plating product family.
|
||||
|
||||
import base64
|
||||
import logging
|
||||
|
||||
from markupsafe import Markup
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FpDelivery(models.Model):
|
||||
"""Scheduled delivery of finished parts back to a customer.
|
||||
@@ -480,6 +485,51 @@ class FpDelivery(models.Model):
|
||||
or rec.vehicle_id.display_name
|
||||
or 'Driver'),
|
||||
)
|
||||
# Packing slip travels with the shipment — render + attach it on
|
||||
# dispatch so the driver/customer get it and it's on the record.
|
||||
self._fp_generate_packing_slip()
|
||||
|
||||
def _fp_generate_packing_slip(self, force=False):
|
||||
"""Render each delivery's packing slip and store it on
|
||||
packing_list_attachment_id so it ships with the goods.
|
||||
|
||||
Fired on dispatch (action_start_route) and as a catch-all on
|
||||
action_mark_delivered. Idempotent + best-effort: skips deliveries
|
||||
that already carry a slip (unless force=True) and never raises —
|
||||
a report glitch must not block shipping. The report action is
|
||||
resolved at runtime so this module needs no hard dependency on
|
||||
fusion_plating_reports.
|
||||
"""
|
||||
report_xmlid = (
|
||||
'fusion_plating_reports.action_report_fp_packing_slip_portrait'
|
||||
)
|
||||
report = self.env.ref(report_xmlid, raise_if_not_found=False)
|
||||
if not report:
|
||||
return
|
||||
for rec in self:
|
||||
if 'packing_list_attachment_id' not in rec._fields:
|
||||
return
|
||||
if rec.packing_list_attachment_id and not force:
|
||||
continue
|
||||
try:
|
||||
report_model = self.env['ir.actions.report'].sudo()
|
||||
pdf_bytes, _fmt = report_model._render_qweb_pdf(
|
||||
report_xmlid, res_ids=rec.ids)
|
||||
att = self.env['ir.attachment'].sudo().create({
|
||||
'name': _('Packing Slip - %s.pdf') % rec.display_name,
|
||||
'type': 'binary',
|
||||
'datas': base64.b64encode(pdf_bytes),
|
||||
'mimetype': 'application/pdf',
|
||||
'res_model': rec._name,
|
||||
'res_id': rec.id,
|
||||
})
|
||||
rec.packing_list_attachment_id = att.id
|
||||
rec.message_post(
|
||||
body=_('Packing slip generated and attached.'))
|
||||
except Exception as exc:
|
||||
_logger.warning(
|
||||
'Packing slip render failed for delivery %s: %s',
|
||||
rec.display_name, exc)
|
||||
|
||||
def action_mark_delivered(self):
|
||||
"""Block "delivered" until a Proof of Delivery exists.
|
||||
@@ -511,6 +561,9 @@ class FpDelivery(models.Model):
|
||||
# Sub 8 — box-parity warning. Non-blocking; just posts to
|
||||
# chatter so the shipping supervisor sees it on the record.
|
||||
rec._fp_check_box_parity()
|
||||
# Catch-all: ensure a slip exists even if dispatch was skipped
|
||||
# (generate-if-missing — won't overwrite the dispatch-time one).
|
||||
self._fp_generate_packing_slip()
|
||||
|
||||
def _fp_check_box_parity(self):
|
||||
"""Compare this delivery's boxes-out count to the boxes-in count
|
||||
|
||||
Reference in New Issue
Block a user