fix(plating): show additional charge under subtotal on SO + invoice PDFs
Tooling/additional charge lines (any product line with no part catalog) no longer print in the parts table — they render in the totals block under the subtotal with their entered label + amount. Subtotal is now parts-only; tax + grand total are unchanged (the charge is still a real taxed line in the data). Applies to SO confirmation and invoice, both portrait and landscape. Also aligns the invoice S/N cell to the SO's multi-serial rendering. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
{
|
||||
'name': 'Fusion Plating — Reports',
|
||||
'version': '19.0.11.32.0',
|
||||
'version': '19.0.11.33.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'PDF reports for Fusion Plating: quote, SO, WO, packing, BoL, CoC, invoice, receipt, quality + compliance.',
|
||||
'depends': [
|
||||
|
||||
@@ -221,7 +221,8 @@
|
||||
<t t-elif="line.display_type == 'line_note'">
|
||||
<tr class="note-row"><td colspan="6"><span t-field="line.name"/></td></tr>
|
||||
</t>
|
||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||
<!-- Charge / fee lines render in the totals block, not here. -->
|
||||
<t t-elif="(not line.display_type or line.display_type == 'product') and line.x_fc_part_catalog_id">
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Three stacked lines: Part #, Name, S/N -->
|
||||
@@ -238,8 +239,8 @@
|
||||
</div>
|
||||
<div>
|
||||
<strong>S/N:</strong>
|
||||
<t t-if="'x_fc_serial_id' in line._fields and line.x_fc_serial_id">
|
||||
<span t-esc="line.x_fc_serial_id.name"/>
|
||||
<t t-if="line.x_fc_serial_ids">
|
||||
<span t-esc="', '.join(line.x_fc_serial_ids.mapped('name'))"/>
|
||||
</t>
|
||||
<t t-else="">—</t>
|
||||
</div>
|
||||
@@ -279,15 +280,31 @@
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-6" style="text-align: right;">
|
||||
<!-- Additional charges (tooling, rush, etc.) carry from
|
||||
the SO as real taxed invoice lines but render here
|
||||
under the subtotal, NOT in the parts table above.
|
||||
Subtotal is parts-only so tax + grand total stay the
|
||||
standard Odoo figures. -->
|
||||
<t t-set="fp_charge_lines" t-value="doc.invoice_line_ids.filtered(lambda l: (not l.display_type or l.display_type == 'product') and not l.x_fc_part_catalog_id)"/>
|
||||
<t t-set="fp_charge_total" t-value="sum(fp_charge_lines.mapped('price_subtotal'))"/>
|
||||
<t t-set="fp_parts_subtotal" t-value="doc.amount_untaxed - fp_charge_total"/>
|
||||
<table class="totals-table" style="width: auto; margin-left: auto;">
|
||||
<tr>
|
||||
<td style="min-width: 150px;">
|
||||
<span class="fp-bl-en">Subtotal</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Sous-total</span>
|
||||
</td>
|
||||
<td class="text-end" style="min-width: 110px;">
|
||||
<span t-field="doc.amount_untaxed" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
<span t-out="fp_parts_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-foreach="fp_charge_lines" t-as="cl">
|
||||
<tr>
|
||||
<td><span t-esc="cl.name or 'Additional Charge'"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="cl.price_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fp-bl-en">Taxes</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Taxes</span>
|
||||
@@ -559,7 +576,8 @@
|
||||
<t t-elif="line.display_type == 'line_note'">
|
||||
<tr class="note-row"><td t-att-colspan="col_count"><span t-field="line.name"/></td></tr>
|
||||
</t>
|
||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||
<!-- Charge / fee lines render in the totals block, not here. -->
|
||||
<t t-elif="(not line.display_type or line.display_type == 'product') and line.x_fc_part_catalog_id">
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Three stacked lines: Part #, Name, S/N -->
|
||||
@@ -576,8 +594,8 @@
|
||||
</div>
|
||||
<div>
|
||||
<strong>S/N:</strong>
|
||||
<t t-if="'x_fc_serial_id' in line._fields and line.x_fc_serial_id">
|
||||
<span t-esc="line.x_fc_serial_id.name"/>
|
||||
<t t-if="line.x_fc_serial_ids">
|
||||
<span t-esc="', '.join(line.x_fc_serial_ids.mapped('name'))"/>
|
||||
</t>
|
||||
<t t-else="">—</t>
|
||||
</div>
|
||||
@@ -620,15 +638,28 @@
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-5" style="text-align: right;">
|
||||
<!-- Additional charges render under the subtotal (see the
|
||||
portrait template for the rationale). -->
|
||||
<t t-set="fp_charge_lines" t-value="doc.invoice_line_ids.filtered(lambda l: (not l.display_type or l.display_type == 'product') and not l.x_fc_part_catalog_id)"/>
|
||||
<t t-set="fp_charge_total" t-value="sum(fp_charge_lines.mapped('price_subtotal'))"/>
|
||||
<t t-set="fp_parts_subtotal" t-value="doc.amount_untaxed - fp_charge_total"/>
|
||||
<table class="totals-table" style="width: auto; margin-left: auto;">
|
||||
<tr>
|
||||
<td style="min-width: 200px;">
|
||||
<span class="fp-bl-en">Subtotal</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Sous-total</span>
|
||||
</td>
|
||||
<td class="text-end" style="min-width: 150px;">
|
||||
<span t-field="doc.amount_untaxed" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
<span t-out="fp_parts_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-foreach="fp_charge_lines" t-as="cl">
|
||||
<tr>
|
||||
<td><span t-esc="cl.name or 'Additional Charge'"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="cl.price_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fp-bl-en">Taxes</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Taxes</span>
|
||||
|
||||
@@ -392,7 +392,10 @@
|
||||
<t t-elif="line.display_type == 'line_note'">
|
||||
<tr class="note-row"><td colspan="6"><span t-field="line.name"/></td></tr>
|
||||
</t>
|
||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||
<!-- Charge / fee lines (product line with no part
|
||||
catalog) are skipped here and rendered in the
|
||||
totals block under the subtotal. -->
|
||||
<t t-elif="(not line.display_type or line.display_type == 'product') and line.x_fc_part_catalog_id">
|
||||
<tr>
|
||||
<td>
|
||||
<!-- Three stacked lines:
|
||||
@@ -455,15 +458,32 @@
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-6" style="text-align: right;">
|
||||
<!-- Additional charges (tooling, rush, etc.) are real
|
||||
taxed SO lines but render here under the subtotal,
|
||||
NOT in the parts table above. Any product line with
|
||||
no part catalog is treated as a charge. Subtotal is
|
||||
parts-only (amount_untaxed minus the charges), so the
|
||||
tax + grand total stay the standard Odoo figures. -->
|
||||
<t t-set="fp_charge_lines" t-value="doc.order_line.filtered(lambda l: (not l.display_type or l.display_type == 'product') and not l.x_fc_part_catalog_id)"/>
|
||||
<t t-set="fp_charge_total" t-value="sum(fp_charge_lines.mapped('price_subtotal'))"/>
|
||||
<t t-set="fp_parts_subtotal" t-value="doc.amount_untaxed - fp_charge_total"/>
|
||||
<table class="totals-table" style="width: auto; margin-left: auto;">
|
||||
<tr>
|
||||
<td style="min-width: 150px;">
|
||||
<span class="fp-bl-en">Subtotal</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Sous-total</span>
|
||||
</td>
|
||||
<td class="text-end" style="min-width: 110px;">
|
||||
<span t-field="doc.amount_untaxed" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
<span t-out="fp_parts_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-foreach="fp_charge_lines" t-as="cl">
|
||||
<tr>
|
||||
<td><span t-esc="cl.name or 'Additional Charge'"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="cl.price_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fp-bl-en">Taxes</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Taxes</span>
|
||||
@@ -668,7 +688,8 @@
|
||||
<t t-elif="line.display_type == 'line_note'">
|
||||
<tr class="note-row"><td t-att-colspan="col_count"><span t-field="line.name"/></td></tr>
|
||||
</t>
|
||||
<t t-elif="not line.display_type or line.display_type == 'product'">
|
||||
<!-- Charge / fee lines render in the totals block, not here. -->
|
||||
<t t-elif="(not line.display_type or line.display_type == 'product') and line.x_fc_part_catalog_id">
|
||||
<tr>
|
||||
<td>
|
||||
<t t-call="fusion_plating_reports.customer_line_part_number"/>
|
||||
@@ -718,13 +739,26 @@
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-5" style="text-align: right;">
|
||||
<!-- Additional charges render under the subtotal (see
|
||||
the portrait template for the rationale). -->
|
||||
<t t-set="fp_charge_lines" t-value="doc.order_line.filtered(lambda l: (not l.display_type or l.display_type == 'product') and not l.x_fc_part_catalog_id)"/>
|
||||
<t t-set="fp_charge_total" t-value="sum(fp_charge_lines.mapped('price_subtotal'))"/>
|
||||
<t t-set="fp_parts_subtotal" t-value="doc.amount_untaxed - fp_charge_total"/>
|
||||
<table class="totals-table" style="width: auto; margin-left: auto;">
|
||||
<tr>
|
||||
<td style="min-width: 200px;">Subtotal</td>
|
||||
<td class="text-end" style="min-width: 150px;">
|
||||
<span t-field="doc.amount_untaxed" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
<span t-out="fp_parts_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-foreach="fp_charge_lines" t-as="cl">
|
||||
<tr>
|
||||
<td><span t-esc="cl.name or 'Additional Charge'"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="cl.price_subtotal" t-options='{"widget": "monetary", "display_currency": doc.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr>
|
||||
<td>Taxes</td>
|
||||
<td class="text-end">
|
||||
|
||||
Reference in New Issue
Block a user