feat(reports+configurator): invoice PDF uses macro; x_fc_part_catalog_id on account.move.line (Sub 2 Task 19)
Invoice PDF (portrait + landscape) now collapses SKU + Description into a single Part column rendered via fusion_plating_reports.customer_line_header, so customer-facing invoices print the customer's part number (with revision) instead of the internal service SKU. To feed the macro on invoice lines, add x_fc_part_catalog_id to account.move.line and override sale.order.line._prepare_invoice_line so the part reference propagates automatically when an SO is invoiced.
This commit is contained in:
@@ -13,6 +13,7 @@ from . import fp_sale_description_template
|
|||||||
from . import fp_quote_configurator
|
from . import fp_quote_configurator
|
||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import sale_order_line
|
from . import sale_order_line
|
||||||
|
from . import account_move_line
|
||||||
from . import fp_sale_assembly
|
from . import fp_sale_assembly
|
||||||
from . import res_partner
|
from . import res_partner
|
||||||
from . import fp_process_node
|
from . import fp_process_node
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2026 Nexa Systems Inc.
|
||||||
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
# Part of the Fusion Plating product family.
|
||||||
|
#
|
||||||
|
# Sub 2 Task 19 — propagate the customer part reference from SO line to
|
||||||
|
# invoice line so customer-facing invoice PDFs can print the part number
|
||||||
|
# via the shared fusion_plating_reports.customer_line_header macro.
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class AccountMoveLine(models.Model):
|
||||||
|
_inherit = 'account.move.line'
|
||||||
|
|
||||||
|
x_fc_part_catalog_id = fields.Many2one(
|
||||||
|
'fp.part.catalog',
|
||||||
|
string='Part',
|
||||||
|
help="Copied from sale.order.line on invoice creation so customer-"
|
||||||
|
"facing invoice PDFs can render the customer's part number.",
|
||||||
|
)
|
||||||
@@ -89,3 +89,15 @@ class SaleOrderLine(models.Model):
|
|||||||
def action_unarchive_line(self):
|
def action_unarchive_line(self):
|
||||||
self.write({'x_fc_archived': False})
|
self.write({'x_fc_archived': False})
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _prepare_invoice_line(self, **optional_values):
|
||||||
|
"""Carry x_fc_part_catalog_id from SO line to invoice line.
|
||||||
|
|
||||||
|
Sub 2 Task 19 — lets the customer-facing invoice PDF render the
|
||||||
|
customer's part number via the shared customer_line_header macro
|
||||||
|
instead of the internal service SKU.
|
||||||
|
"""
|
||||||
|
vals = super()._prepare_invoice_line(**optional_values)
|
||||||
|
if self.x_fc_part_catalog_id:
|
||||||
|
vals['x_fc_part_catalog_id'] = self.x_fc_part_catalog_id.id
|
||||||
|
return vals
|
||||||
|
|||||||
@@ -80,8 +80,7 @@
|
|||||||
<table class="bordered">
|
<table class="bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 12%;">SKU</th>
|
<th class="text-start" style="width: 52%;">PART</th>
|
||||||
<th class="text-start" style="width: 40%;">DESCRIPTION</th>
|
|
||||||
<th style="width: 8%;">QTY</th>
|
<th style="width: 8%;">QTY</th>
|
||||||
<th style="width: 8%;">UOM</th>
|
<th style="width: 8%;">UOM</th>
|
||||||
<th style="width: 12%;">UNIT PRICE</th>
|
<th style="width: 12%;">UNIT PRICE</th>
|
||||||
@@ -92,20 +91,15 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<t t-foreach="doc.invoice_line_ids" t-as="line">
|
<t t-foreach="doc.invoice_line_ids" t-as="line">
|
||||||
<t t-if="line.display_type == 'line_section'">
|
<t t-if="line.display_type == 'line_section'">
|
||||||
<tr class="section-row"><td colspan="7"><strong t-field="line.name"/></td></tr>
|
<tr class="section-row"><td colspan="6"><strong t-field="line.name"/></td></tr>
|
||||||
</t>
|
</t>
|
||||||
<t t-elif="line.display_type == 'line_note'">
|
<t t-elif="line.display_type == 'line_note'">
|
||||||
<tr class="note-row"><td colspan="7"><span t-field="line.name"/></td></tr>
|
<tr class="note-row"><td colspan="6"><span t-field="line.name"/></td></tr>
|
||||||
</t>
|
</t>
|
||||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><span t-esc="line.product_id.default_code or ''"/></td>
|
|
||||||
<td>
|
<td>
|
||||||
<t t-set="clean_name" t-value="line.name"/>
|
<t t-call="fusion_plating_reports.customer_line_header"/>
|
||||||
<t t-if="line.name and '] ' in line.name">
|
|
||||||
<t t-set="clean_name" t-value="line.name.split('] ', 1)[1]"/>
|
|
||||||
</t>
|
|
||||||
<span t-esc="clean_name"/>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span t-esc="int(line.quantity) if line.quantity == int(line.quantity) else line.quantity"/>
|
<span t-esc="int(line.quantity) if line.quantity == int(line.quantity) else line.quantity"/>
|
||||||
@@ -268,12 +262,11 @@
|
|||||||
|
|
||||||
<!-- Lines — hide discount column unless at least one line has a discount -->
|
<!-- Lines — hide discount column unless at least one line has a discount -->
|
||||||
<t t-set="has_discount" t-value="any(l.discount for l in doc.invoice_line_ids)"/>
|
<t t-set="has_discount" t-value="any(l.discount for l in doc.invoice_line_ids)"/>
|
||||||
<t t-set="col_count" t-value="8 if has_discount else 7"/>
|
<t t-set="col_count" t-value="7 if has_discount else 6"/>
|
||||||
<table class="bordered">
|
<table class="bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 10%;">SKU</th>
|
<th class="text-start" style="width: 42%;">PART</th>
|
||||||
<th class="text-start" style="width: 32%;">DESCRIPTION</th>
|
|
||||||
<th style="width: 8%;">QTY</th>
|
<th style="width: 8%;">QTY</th>
|
||||||
<th style="width: 8%;">UOM</th>
|
<th style="width: 8%;">UOM</th>
|
||||||
<th style="width: 12%;">UNIT PRICE</th>
|
<th style="width: 12%;">UNIT PRICE</th>
|
||||||
@@ -292,13 +285,8 @@
|
|||||||
</t>
|
</t>
|
||||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><span t-esc="line.product_id.default_code or ''"/></td>
|
|
||||||
<td>
|
<td>
|
||||||
<t t-set="clean_name" t-value="line.name"/>
|
<t t-call="fusion_plating_reports.customer_line_header"/>
|
||||||
<t t-if="line.name and '] ' in line.name">
|
|
||||||
<t t-set="clean_name" t-value="line.name.split('] ', 1)[1]"/>
|
|
||||||
</t>
|
|
||||||
<span t-esc="clean_name"/>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span t-esc="int(line.quantity) if line.quantity == int(line.quantity) else line.quantity"/>
|
<span t-esc="int(line.quantity) if line.quantity == int(line.quantity) else line.quantity"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user