feat(reports): packing slip for local deliveries (fusion.plating.delivery)
The packing slip report only existed for stock.picking (Delivery Orders), but this shop ships via fusion.plating.delivery and has no pickings — so packing slips never rendered for their flow, and the prior auto-generate + email-notification paths pointed the stock.picking report at a delivery (wrong model -> blank PDF). Add a delivery-native variant: report_fp_packing_slip_delivery_portrait + action_report_fp_packing_slip_delivery_portrait (bound to fusion.plating.delivery -> shows in the delivery Print menu), resolving the SO + lines from the delivery job_ref (same pattern as the BoL report) and reusing the shared styles / address / signoff bits + a sale.order.line items table. Repoint _fp_generate_packing_slip (dispatch auto-gen) and the notification attachment to the new report. Verified on entech: real content (customer, PO, items, PS#) for DLV-30102 — 142KB PDF vs prior blank 12.8KB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -501,7 +501,7 @@ class FpDelivery(models.Model):
|
|||||||
fusion_plating_reports.
|
fusion_plating_reports.
|
||||||
"""
|
"""
|
||||||
report_xmlid = (
|
report_xmlid = (
|
||||||
'fusion_plating_reports.action_report_fp_packing_slip_portrait'
|
'fusion_plating_reports.action_report_fp_packing_slip_delivery_portrait'
|
||||||
)
|
)
|
||||||
report = self.env.ref(report_xmlid, raise_if_not_found=False)
|
report = self.env.ref(report_xmlid, raise_if_not_found=False)
|
||||||
if not report:
|
if not report:
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ class FpNotificationTemplate(models.Model):
|
|||||||
# Packing slip — gated by customer preference (default True)
|
# Packing slip — gated by customer preference (default True)
|
||||||
if self.attach_packing_list and delivery and _customer_wants('x_fc_send_packing_slip'):
|
if self.attach_packing_list and delivery and _customer_wants('x_fc_send_packing_slip'):
|
||||||
att = _render_report(
|
att = _render_report(
|
||||||
'fusion_plating_reports.action_report_fp_packing_slip_portrait', delivery,
|
'fusion_plating_reports.action_report_fp_packing_slip_delivery_portrait', delivery,
|
||||||
)
|
)
|
||||||
if att:
|
if att:
|
||||||
ids.append(att)
|
ids.append(att)
|
||||||
|
|||||||
@@ -461,4 +461,214 @@
|
|||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- ============================================================= -->
|
||||||
|
<!-- LOCAL DELIVERY variant (fusion.plating.delivery) -->
|
||||||
|
<!-- The stock.picking templates above don't fit shops that ship -->
|
||||||
|
<!-- via fusion.plating.delivery (no picking). This variant -->
|
||||||
|
<!-- resolves the SO + lines from the delivery's job_ref (same -->
|
||||||
|
<!-- pattern as the BoL report) and reuses the shared styles / -->
|
||||||
|
<!-- address / signoff bits. Items come from the SO lines (vs -->
|
||||||
|
<!-- stock moves). -->
|
||||||
|
<!-- ============================================================= -->
|
||||||
|
|
||||||
|
<!-- Items table sourced from sale.order.line (not stock.move) -->
|
||||||
|
<template id="fp_packing_slip_items_lines">
|
||||||
|
<table class="bordered fp-ps-items-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th t-att-style="w_ordered or 'width: 8%;'">
|
||||||
|
Ordered<span class="fp-fr">Comm.</span>
|
||||||
|
</th>
|
||||||
|
<th t-att-style="w_shipped or 'width: 8%;'">
|
||||||
|
Shipped<span class="fp-fr">EXP</span>
|
||||||
|
</th>
|
||||||
|
<th t-att-style="w_bo or 'width: 8%;'">
|
||||||
|
B/O<span class="fp-fr">À venir</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-start" t-att-style="w_part or 'width: 17%;'">
|
||||||
|
Part Number<span class="fp-fr">N° de pièce</span>
|
||||||
|
</th>
|
||||||
|
<th t-att-style="w_po or 'width: 11%;'">
|
||||||
|
PO<span class="fp-fr">B/C</span>
|
||||||
|
</th>
|
||||||
|
<th t-att-style="w_wo or 'width: 11%;'">
|
||||||
|
WO<span class="fp-fr">B/T</span>
|
||||||
|
</th>
|
||||||
|
<th t-att-style="w_process or 'width: 14%;'">
|
||||||
|
Process<span class="fp-fr">Procédé</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-start" t-att-style="w_desc or 'width: 23%;'">
|
||||||
|
Description
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="lines" t-as="line">
|
||||||
|
<t t-set="ordered_qty" t-value="line.product_uom_qty or 0.0"/>
|
||||||
|
<t t-set="wo_job" t-value="line.env['fp.job'].sudo().search([('sale_order_line_ids', 'in', line.ids)], limit=1)"/>
|
||||||
|
<t t-set="done_qty" t-value="(wo_job.qty_done if wo_job and wo_job.qty_done else ordered_qty)"/>
|
||||||
|
<t t-set="bo_qty" t-value="ordered_qty - done_qty if ordered_qty > done_qty else 0.0"/>
|
||||||
|
<t t-set="proc_variant" t-value="(line.x_fc_process_variant_id if 'x_fc_process_variant_id' in line._fields else False)"/>
|
||||||
|
<t t-set="proc_label" t-value="(proc_variant.variant_label or proc_variant.name) if proc_variant else ((line.x_fc_part_catalog_id.default_process_id.variant_label or line.x_fc_part_catalog_id.default_process_id.name) if line.x_fc_part_catalog_id and line.x_fc_part_catalog_id.default_process_id else '')"/>
|
||||||
|
<tr>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<span t-esc="int(ordered_qty) if ordered_qty == int(ordered_qty) else ordered_qty"/>
|
||||||
|
</td>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<span t-esc="int(done_qty) if done_qty == int(done_qty) else done_qty"/>
|
||||||
|
</td>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<span t-esc="int(bo_qty) if bo_qty == int(bo_qty) else bo_qty"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-call="fusion_plating_reports.customer_line_part_number"/>
|
||||||
|
</td>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<span t-esc="po_number or '-'"/>
|
||||||
|
</td>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<t t-if="wo_job"><span t-esc="wo_job.name"/></t>
|
||||||
|
<t t-else="">-</t>
|
||||||
|
</td>
|
||||||
|
<td class="fp-ps-num">
|
||||||
|
<span t-esc="proc_label or '-'"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-call="fusion_plating_reports.customer_line_description"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="report_fp_packing_slip_delivery_portrait">
|
||||||
|
<t t-call="web.html_container">
|
||||||
|
<t t-foreach="docs" t-as="doc">
|
||||||
|
<t t-call="web.external_layout">
|
||||||
|
<t t-call="fusion_plating_reports.fp_portrait_styles"/>
|
||||||
|
<t t-call="fusion_plating_reports.fp_packing_slip_styles"/>
|
||||||
|
|
||||||
|
<!-- Resolve SO + lines from the delivery's job_ref
|
||||||
|
(mirrors the BoL report's resolution). -->
|
||||||
|
<t t-set="_job" t-value="env['fp.job'].sudo().search([('name', '=', doc.job_ref)], limit=1) if doc.job_ref else env['fp.job']"/>
|
||||||
|
<t t-set="_so" t-value="_job.sale_order_id if _job else False"/>
|
||||||
|
<t t-set="_lines" t-value="_so.order_line.filtered(lambda l: l.product_id and not l.display_type and l.product_uom_qty > 0) if _so else False"/>
|
||||||
|
|
||||||
|
<t t-set="bill_partner" t-value="(_so.partner_invoice_id if _so and _so.partner_invoice_id else (doc.partner_id.commercial_partner_id or doc.partner_id))"/>
|
||||||
|
<t t-set="ship_partner" t-value="doc.delivery_address_id or doc.partner_id"/>
|
||||||
|
<t t-set="has_carrier" t-value="'x_fc_carrier_id' in doc._fields and doc.x_fc_carrier_id"/>
|
||||||
|
<t t-set="ship_via" t-value="(doc.x_fc_carrier_id.name if has_carrier else (_so.x_fc_ship_via if _so and 'x_fc_ship_via' in _so._fields and _so.x_fc_ship_via else 'CUSTOMER PICKUP'))"/>
|
||||||
|
<t t-set="tracking_text" t-value="'Ready for pick up' if not has_carrier else '—'"/>
|
||||||
|
<t t-set="po_number" t-value="(_so.client_order_ref if _so and _so.client_order_ref else '')"/>
|
||||||
|
|
||||||
|
<t t-set="so_name_raw" t-value="_so.name if _so else (doc.name or '')"/>
|
||||||
|
<t t-set="ps_number" t-value="so_name_raw.rsplit('-', 1)[-1] if '-' in so_name_raw else so_name_raw"/>
|
||||||
|
<t t-set="ps_barcode_uri" t-value="doc.env['ir.actions.report'].sudo().barcode_data_uri('Code128', ps_number, 600, 100) if ps_number else False"/>
|
||||||
|
<t t-set="qr_payload" t-value="doc.name or ''"/>
|
||||||
|
<t t-set="qr_uri" t-value="doc.env['ir.actions.report'].sudo().barcode_data_uri('QR', qr_payload, 220, 220) if qr_payload else False"/>
|
||||||
|
|
||||||
|
<div class="fp-report fp-ps">
|
||||||
|
<div class="page">
|
||||||
|
<div class="fp-ps-titlebar">
|
||||||
|
<t t-if="ps_barcode_uri">
|
||||||
|
<div class="fp-ps-barcode">
|
||||||
|
<div class="fp-bc-wrap">
|
||||||
|
<img t-att-src="ps_barcode_uri" alt="Packing Slip Barcode"/>
|
||||||
|
<div class="fp-bc-label"><t t-esc="ps_number"/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<span class="fp-ps-title-en">
|
||||||
|
Packing Slip<span class="fp-ps-title-num"># <t t-esc="ps_number"/></span>
|
||||||
|
</span>
|
||||||
|
<span class="fp-ps-title-fr">Bordereau d'expédition</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="bordered fp-ps-addrtable">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 50%;">
|
||||||
|
<t t-call="fusion_plating_reports.fp_packing_slip_addr_block">
|
||||||
|
<t t-set="label" t-value="'Bill To:'"/>
|
||||||
|
<t t-set="partner" t-value="bill_partner"/>
|
||||||
|
</t>
|
||||||
|
</td>
|
||||||
|
<td style="width: 50%;">
|
||||||
|
<t t-call="fusion_plating_reports.fp_packing_slip_addr_block">
|
||||||
|
<t t-set="label" t-value="'Ship To:'"/>
|
||||||
|
<t t-set="partner" t-value="ship_partner"/>
|
||||||
|
</t>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="bordered fp-ps-info-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 33%;">
|
||||||
|
Ship Via<span class="fp-fr" style="display:block; font-weight:normal; color:#555; font-size:8pt;">Mode d'expédition</span>
|
||||||
|
</th>
|
||||||
|
<th style="width: 33%;">
|
||||||
|
Shipping Date<span class="fp-fr" style="display:block; font-weight:normal; color:#555; font-size:8pt;">Date d'expédition</span>
|
||||||
|
</th>
|
||||||
|
<th style="width: 34%;">
|
||||||
|
Tracking #<span class="fp-fr" style="display:block; font-weight:normal; color:#555; font-size:8pt;">N° de suivi</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><span t-esc="ship_via"/></td>
|
||||||
|
<td>
|
||||||
|
<t t-if="doc.scheduled_date">
|
||||||
|
<span t-field="doc.scheduled_date" t-options="{'widget': 'date'}"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">—</t>
|
||||||
|
</td>
|
||||||
|
<td><span t-esc="tracking_text"/></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<t t-if="_lines">
|
||||||
|
<t t-call="fusion_plating_reports.fp_packing_slip_items_lines">
|
||||||
|
<t t-set="lines" t-value="_lines"/>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<p style="margin-top: 10px; color: #555;">
|
||||||
|
No order lines are linked to this delivery
|
||||||
|
(job <span t-esc="doc.job_ref or doc.name"/>).
|
||||||
|
</p>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<t t-if="doc.notes">
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<strong>Notes:</strong>
|
||||||
|
<div t-field="doc.notes"/>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<t t-call="fusion_plating_reports.fp_packing_slip_signoff"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<record id="action_report_fp_packing_slip_delivery_portrait" model="ir.actions.report">
|
||||||
|
<field name="name">Packing Slip</field>
|
||||||
|
<field name="model">fusion.plating.delivery</field>
|
||||||
|
<field name="report_type">qweb-pdf</field>
|
||||||
|
<field name="report_name">fusion_plating_reports.report_fp_packing_slip_delivery_portrait</field>
|
||||||
|
<field name="report_file">fusion_plating_reports.report_fp_packing_slip_delivery_portrait</field>
|
||||||
|
<field name="print_report_name">'Packing Slip - %s' % (object.name or '')</field>
|
||||||
|
<field name="binding_model_id" ref="fusion_plating_logistics.model_fusion_plating_delivery"/>
|
||||||
|
<field name="binding_type">report</field>
|
||||||
|
<field name="paperformat_id" ref="paperformat_fp_a4_portrait"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Reference in New Issue
Block a user