Since BS5 integration in v16.0, the pdf of the invoices has changed. Borders would be present in the body of the invoice and the total detail. Came back to v15 display by using the table-borderless class on those elements. closes odoo/odoo#107257 X-original-commit: 1a46b6f9231c5d49d70bfa9eb8d434c1f092c1c7 Signed-off-by: Laurent Smet <las@odoo.com> Signed-off-by: Camille Spiritus (casp) <casp@odoo.com>
358 lines
23 KiB
XML
358 lines
23 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data>
|
|
<template id="report_invoice_document">
|
|
<t t-call="web.external_layout">
|
|
<t t-set="o" t-value="o.with_context(lang=lang)" />
|
|
<t t-set="forced_vat" t-value="o.fiscal_position_id.foreign_vat"/> <!-- So that it appears in the footer of the report instead of the company VAT if it's set -->
|
|
<div class="row">
|
|
<t t-if="o.partner_shipping_id and (o.partner_shipping_id != o.partner_id)">
|
|
<div class="col-6">
|
|
<t t-set="information_block">
|
|
<div groups="account.group_delivery_invoice_address" name="shipping_address_block">
|
|
<strong>Shipping Address:</strong>
|
|
<div t-field="o.partner_shipping_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div class="col-6" name="address_not_same_as_shipping">
|
|
<t t-set="address">
|
|
<address class="mb-0" t-field="o.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
|
|
<div t-if="o.partner_id.vat">
|
|
<t t-if="o.company_id.account_fiscal_country_id.vat_label" t-out="o.company_id.account_fiscal_country_id.vat_label" id="inv_tax_id_label"/>
|
|
<t t-else="">Tax ID</t>: <span t-field="o.partner_id.vat"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
<t t-elif="o.partner_shipping_id and (o.partner_shipping_id == o.partner_id)">
|
|
<div class="offset-col-6 col-6" name="address_same_as_shipping">
|
|
<t t-set="address">
|
|
<address class="mb-0" t-field="o.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
|
|
<div t-if="o.partner_id.vat">
|
|
<t t-if="o.company_id.account_fiscal_country_id.vat_label" t-out="o.company_id.account_fiscal_country_id.vat_label" id="inv_tax_id_label"/>
|
|
<t t-else="">Tax ID</t>: <span t-field="o.partner_id.vat"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
<t t-else="">
|
|
<div class="offset-col-6 col-6" name="no_shipping">
|
|
<t t-set="address">
|
|
<address class="mb-0" t-field="o.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
|
|
<div t-if="o.partner_id.vat">
|
|
<t t-if="o.company_id.account_fiscal_country_id.vat_label" t-out="o.company_id.account_fiscal_country_id.vat_label" id="inv_tax_id_label"/>
|
|
<t t-else="">Tax ID</t>: <span t-field="o.partner_id.vat"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div class="mt-5">
|
|
<div class="page">
|
|
<h2>
|
|
<span t-if="o.move_type == 'out_invoice' and o.state == 'posted'">Invoice</span>
|
|
<span t-elif="o.move_type == 'out_invoice' and o.state == 'draft'">Draft Invoice</span>
|
|
<span t-elif="o.move_type == 'out_invoice' and o.state == 'cancel'">Cancelled Invoice</span>
|
|
<span t-elif="o.move_type == 'out_refund' and o.state == 'posted'">Credit Note</span>
|
|
<span t-elif="o.move_type == 'out_refund' and o.state == 'draft'">Draft Credit Note</span>
|
|
<span t-elif="o.move_type == 'out_refund' and o.state == 'cancel'">Cancelled Credit Note</span>
|
|
<span t-elif="o.move_type == 'in_refund'">Vendor Credit Note</span>
|
|
<span t-elif="o.move_type == 'in_invoice'">Vendor Bill</span>
|
|
<span t-if="o.name != '/'" t-field="o.name"/>
|
|
</h2>
|
|
|
|
<div id="informations" class="row mt-4 mb-4">
|
|
<div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_date" name="invoice_date">
|
|
<t t-if="o.move_type == 'out_invoice'"><strong>Invoice Date:</strong></t>
|
|
<t t-elif="o.move_type == 'out_refund'"><strong>Credit Note Date:</strong></t>
|
|
<t t-elif="o.move_type == 'out_receipt'"><strong>Receipt Date:</strong></t>
|
|
<t t-else=""><strong>Date:</strong></t>
|
|
<p class="m-0" t-field="o.invoice_date"/>
|
|
</div>
|
|
<div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_date_due and o.move_type == 'out_invoice' and o.state == 'posted'" name="due_date">
|
|
<strong>Due Date:</strong>
|
|
<p class="m-0" t-field="o.invoice_date_due"/>
|
|
</div>
|
|
<div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_origin" name="origin">
|
|
<strong>Source:</strong>
|
|
<p class="m-0" t-field="o.invoice_origin"/>
|
|
</div>
|
|
<div class="col-auto col-3 mw-100 mb-2" t-if="o.partner_id.ref" name="customer_code">
|
|
<strong>Customer Code:</strong>
|
|
<p class="m-0" t-field="o.partner_id.ref"/>
|
|
</div>
|
|
<div class="col-auto col-3 mw-100 mb-2" t-if="o.ref" name="reference">
|
|
<strong>Reference:</strong>
|
|
<p class="m-0" t-field="o.ref"/>
|
|
</div>
|
|
</div>
|
|
|
|
<t t-set="display_discount" t-value="any(l.discount for l in o.invoice_line_ids)"/>
|
|
|
|
<table class="table table-sm o_main_table table-borderless" name="invoice_line_table">
|
|
<thead>
|
|
<tr>
|
|
<th name="th_description" class="text-start"><span>Description</span></th>
|
|
<th name="th_quantity" class="text-end"><span>Quantity</span></th>
|
|
<th name="th_priceunit" t-attf-class="text-end {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Unit Price</span></th>
|
|
<th name="th_price_unit" t-if="display_discount" t-attf-class="text-end {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
|
|
<span>Disc.%</span>
|
|
</th>
|
|
<th name="th_taxes" t-attf-class="text-start {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Taxes</span></th>
|
|
<th name="th_subtotal" class="text-end">
|
|
<span groups="account.group_show_line_subtotals_tax_excluded">Amount</span>
|
|
<span groups="account.group_show_line_subtotals_tax_included">Total Price</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="invoice_tbody">
|
|
<t t-set="current_subtotal" t-value="0"/>
|
|
<t t-set="lines" t-value="o.invoice_line_ids.sorted(key=lambda l: (-l.sequence, l.date, l.move_name, -l.id), reverse=True)"/>
|
|
|
|
<t t-foreach="lines" t-as="line">
|
|
<t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
|
|
<t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
|
|
|
|
<tr t-att-class="'bg-200 fw-bold o_line_section' if line.display_type == 'line_section' else 'fst-italic o_line_note' if line.display_type == 'line_note' else ''">
|
|
<t t-if="line.display_type == 'product'" name="account_invoice_line_accountable">
|
|
<td name="account_invoice_line_name"><span t-field="line.name" t-options="{'widget': 'text'}"/></td>
|
|
<td class="text-end">
|
|
<span t-field="line.quantity"/>
|
|
<span t-field="line.product_uom_id" groups="uom.group_uom"/>
|
|
</td>
|
|
<td t-attf-class="text-end {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
|
|
<span class="text-nowrap" t-field="line.price_unit"/>
|
|
</td>
|
|
<td t-if="display_discount" t-attf-class="text-end {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
|
|
<span class="text-nowrap" t-field="line.discount"/>
|
|
</td>
|
|
<td t-attf-class="text-start {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
|
|
<span t-out="', '.join(map(lambda x: (x.description or x.name), line.tax_ids))" id="line_tax_ids"/>
|
|
</td>
|
|
<td class="text-end o_price_total">
|
|
<span class="text-nowrap" t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
|
|
<span class="text-nowrap" t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
|
|
</td>
|
|
</t>
|
|
<t t-if="line.display_type == 'line_section'">
|
|
<td colspan="99">
|
|
<span t-field="line.name" t-options="{'widget': 'text'}"/>
|
|
</td>
|
|
<t t-set="current_section" t-value="line"/>
|
|
<t t-set="current_subtotal" t-value="0"/>
|
|
</t>
|
|
<t t-if="line.display_type == 'line_note'">
|
|
<td colspan="99">
|
|
<span t-field="line.name" t-options="{'widget': 'text'}"/>
|
|
</td>
|
|
</t>
|
|
</tr>
|
|
|
|
<t t-if="current_section and (line_last or lines[line_index+1].display_type == 'line_section')">
|
|
<tr class="is-subtotal text-end">
|
|
<td colspan="99">
|
|
<strong class="mr16">Subtotal</strong>
|
|
<span
|
|
t-out="current_subtotal"
|
|
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</t>
|
|
</t>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="clearfix mb-4">
|
|
<div id="total" class="row">
|
|
<div t-attf-class="#{'col-6' if report_type != 'html' else 'col-sm-7 col-md-6'} ms-auto">
|
|
<table class="table table-sm table-borderless" style="page-break-inside: avoid;">
|
|
|
|
<!--Tax totals-->
|
|
<t t-set="tax_totals" t-value="o.tax_totals"/>
|
|
<t t-call="account.document_tax_totals"/>
|
|
|
|
<!--Payments-->
|
|
<t t-if="print_with_payments">
|
|
<t t-if="o.payment_state != 'invoicing_legacy'">
|
|
<t t-set="payments_vals" t-value="o.sudo().invoice_payments_widget and o.sudo().invoice_payments_widget['content'] or []"/>
|
|
<t t-foreach="payments_vals" t-as="payment_vals">
|
|
<tr t-if="payment_vals['is_exchange'] == 0">
|
|
<td>
|
|
<i class="oe_form_field text-end oe_payment_label">Paid on <t t-out="payment_vals['date']" t-options='{"widget": "date"}'/></i>
|
|
</td>
|
|
<td class="text-end">
|
|
<span t-out="payment_vals['amount']" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
|
|
</td>
|
|
</tr>
|
|
</t>
|
|
<t t-if="len(payments_vals) > 0">
|
|
<tr class="border-black">
|
|
<td><strong>Amount Due</strong></td>
|
|
<td class="text-end">
|
|
<span t-field="o.amount_residual"/>
|
|
</td>
|
|
</tr>
|
|
</t>
|
|
</t>
|
|
</t>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p t-if="o.move_type in ('out_invoice', 'in_refund') and o.payment_reference" name="payment_communication" class="mt-4">
|
|
Please use the following communication for your payment : <b><span t-field="o.payment_reference"/></b>
|
|
</p>
|
|
<t t-set="payment_term_details" t-value="o.payment_term_details"/>
|
|
<div t-field="o.invoice_payment_term_id.note" name="payment_term"/>
|
|
<t t-if="o.invoice_payment_term_id.display_on_invoice and payment_term_details">
|
|
<div t-if='o.show_payment_term_details' id="total_payment_term_details_table" class="row">
|
|
<div t-attf-class="#{'col-10' if report_type != 'html' else 'col-sm-10 col-md-9'}">
|
|
<t t-if="len(payment_term_details) == 1 and payment_term_details[0].get('discount_date')">
|
|
<td>
|
|
<span t-options='{"widget": "monetary", "display_currency": o.currency_id}'
|
|
t-out="payment_term_details[0].get('discount_amount_currency')"/> due if paid before
|
|
<span t-out="payment_term_details[0].get('discount_date')"/>
|
|
</td>
|
|
</t>
|
|
|
|
<t t-set="i" t-value="1"/>
|
|
<t t-if="len(payment_term_details) > 1" t-foreach="payment_term_details" t-as="term">
|
|
<tr>
|
|
<span t-out="i"/> - Installment of
|
|
<td t-options='{"widget": "monetary", "display_currency": o.currency_id}' t-out="term.get('amount')" class="text-end"/>
|
|
<span> due on </span>
|
|
<td t-out="term.get('date')" class="text-start"/>
|
|
<td t-if="term.get('discount_date')" class="text-end">(
|
|
<span t-options='{"widget": "monetary", "display_currency": o.currency_id}'
|
|
t-out="term.get('discount_amount_currency')"/> if paid before
|
|
<span t-out="term.get('discount_date')"/>)
|
|
</td>
|
|
<br/>
|
|
</tr>
|
|
<t t-set="i" t-value="i+1"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
<br/>
|
|
</t>
|
|
<div t-if="not is_html_empty(o.narration)" name="comment">
|
|
<span t-field="o.narration"/>
|
|
</div>
|
|
<p t-if="not is_html_empty(o.fiscal_position_id.note)" name="note">
|
|
<span t-field="o.fiscal_position_id.note"/>
|
|
</p>
|
|
<p t-if="o.invoice_incoterm_id" name="incoterm">
|
|
<strong>Incoterm: </strong><span t-field="o.invoice_incoterm_id.code"/> - <span t-field="o.invoice_incoterm_id.name"/>
|
|
</p>
|
|
<div id="qrcode" t-if="o.display_qr_code and o.amount_residual > 0">
|
|
<t t-set="qr_code_url" t-value="o._generate_qr_code()"/>
|
|
<p t-if="qr_code_url">
|
|
<strong class="text-center">Scan me with your banking app.</strong><br/><br/>
|
|
<img class="border border-dark rounded" t-att-src="qr_code_url"/>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="document_tax_totals">
|
|
<!--
|
|
Generic template to display tax totals in pdf reports.
|
|
Used by invoices, SO and PO.
|
|
|
|
ARGUMENTS:
|
|
- tax_totals: dict in the form generated by account.move's _get_tax_totals.
|
|
-->
|
|
<t t-foreach="tax_totals['subtotals']" t-as="subtotal">
|
|
<tr class="border-black o_subtotal">
|
|
<td><strong t-out="subtotal['name']"/></td>
|
|
|
|
<td class="text-end">
|
|
<span
|
|
t-att-class="oe_subtotal_footer_separator"
|
|
t-out="subtotal['formatted_amount']"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
|
|
<t t-set="subtotal_to_show" t-value="subtotal['name']"/>
|
|
<t t-call="account.tax_groups_totals"/>
|
|
</t>
|
|
|
|
<!--Total amount with all taxes-->
|
|
<tr class="border-black o_total">
|
|
<td><strong>Total</strong></td>
|
|
<td class="text-end">
|
|
<span t-out="tax_totals['formatted_amount_total']"/>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
|
|
<template id="tax_groups_totals">
|
|
<!--
|
|
Generic template to display a list of tax groups with the related amounts.
|
|
|
|
ARGUMENTS:
|
|
- tax_totals: dict in the form generated by account.move's _get_tax_totals.
|
|
- subtotal_to_show: The subtotal we need to render the groups from
|
|
-->
|
|
<t t-foreach="tax_totals['groups_by_subtotal'][subtotal_to_show]" t-as="amount_by_group">
|
|
<tr>
|
|
<t t-if="tax_totals['display_tax_base']">
|
|
<td>
|
|
<span t-out="amount_by_group['tax_group_name']"/>
|
|
<span class="text-nowrap"> on
|
|
<t t-out="amount_by_group['formatted_tax_group_base_amount']"/>
|
|
</span>
|
|
</td>
|
|
<td class="text-end o_price_total">
|
|
<span class="text-nowrap" t-out="amount_by_group['formatted_tax_group_amount']"/>
|
|
</td>
|
|
</t>
|
|
<t t-else="">
|
|
<td><span class="text-nowrap" t-out="amount_by_group['tax_group_name']"/></td>
|
|
<td class="text-end o_price_total">
|
|
<span class="text-nowrap" t-out="amount_by_group['formatted_tax_group_amount']" />
|
|
</td>
|
|
</t>
|
|
</tr>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="report_invoice">
|
|
<t t-call="web.html_container">
|
|
<t t-foreach="docs" t-as="o">
|
|
<t t-set="lang" t-value="o.partner_id.lang"/>
|
|
<t t-if="o._get_name_invoice_report() == 'account.report_invoice_document'"
|
|
t-call="account.report_invoice_document" t-lang="lang"/>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="report_invoice_with_payments">
|
|
<t t-call="web.html_container">
|
|
<t t-foreach="docs" t-as="o">
|
|
<t t-set="lang" t-value="o.partner_id.lang"/>
|
|
<t t-set="print_with_payments" t-value="True"/>
|
|
<t t-if="o._get_name_invoice_report() == 'account.report_invoice_document'"
|
|
t-call="account.report_invoice_document" t-lang="lang"/>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<!--We need to create the following empty report template for the action report
|
|
"action_account_original_vendor_bill" to work. The action is merging the
|
|
original vendor bill(s) that were used to create the vendor bill(s) into one PDF. -->
|
|
<template id="report_original_vendor_bill">
|
|
<t t-call="web.html_container">
|
|
<t t-foreach="docs" t-as="o">
|
|
<div class="article" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id" t-att-data-oe-lang="o and o.env.context.get('lang')"></div>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
</data>
|
|
</odoo>
|