[REF] account_edi*: Improve the tax details computation for EDI
Add a generic method to compute taxes and group results together. closes odoo/odoo#71743 Related: odoo/enterprise#18758 Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
@@ -135,6 +136,187 @@ class AccountMove(models.Model):
|
||||
# Export Electronic Document
|
||||
####################################################
|
||||
|
||||
@api.model
|
||||
def _add_edi_tax_values(self, results, grouping_key, serialized_grouping_key, tax_values):
|
||||
# Add to global results.
|
||||
results['tax_amount'] += tax_values['tax_amount']
|
||||
results['tax_amount_currency'] += tax_values['tax_amount_currency']
|
||||
|
||||
# Add to tax details.
|
||||
if serialized_grouping_key not in results['tax_details']:
|
||||
tax_details = results['tax_details'][serialized_grouping_key]
|
||||
|
||||
tax_details.update(grouping_key)
|
||||
tax_details.update({
|
||||
'base_amount': tax_values['base_amount'],
|
||||
'base_amount_currency': tax_values['base_amount_currency'],
|
||||
})
|
||||
else:
|
||||
tax_details = results['tax_details'][serialized_grouping_key]
|
||||
tax_details['tax_amount'] += tax_values['tax_amount']
|
||||
tax_details['tax_amount_currency'] += tax_values['tax_amount_currency']
|
||||
tax_details['group_tax_details'].append(tax_values)
|
||||
|
||||
def _prepare_edi_tax_details(self, filter_to_apply=None, grouping_key_generator=None):
|
||||
''' Compute amounts related to taxes for the current invoice.
|
||||
|
||||
:param filter_to_apply: Optional filter to exclude some tax values from the final results.
|
||||
The filter is defined as a method getting a dictionary as parameter
|
||||
representing the tax values for a single repartition line.
|
||||
This dictionary contains:
|
||||
|
||||
'base_line_id': An account.move.line record.
|
||||
'tax_id': An account.tax record.
|
||||
'tax_repartition_line_id': An account.tax.repartition.line record.
|
||||
'base_amount': The tax base amount expressed in company currency.
|
||||
'tax_amount': The tax amount expressed in company currency.
|
||||
'base_amount_currency': The tax base amount expressed in foreign currency.
|
||||
'tax_amount_currency': The tax amount expressed in foreign currency.
|
||||
|
||||
If the filter is returning False, it means the current tax values will be
|
||||
ignored when computing the final results.
|
||||
|
||||
:param grouping_key_generator: Optional method used to group tax values together. By default, the tax values
|
||||
are grouped by tax. This parameter is a method getting a dictionary as parameter
|
||||
(same signature as 'filter_to_apply').
|
||||
|
||||
This method must returns a dictionary where values will be used to create the
|
||||
grouping_key to aggregate tax values together. The returned dictionary is added
|
||||
to each tax details in order to retrieve the full grouping_key later.
|
||||
|
||||
:return: The full tax details for the current invoice and for each invoice line
|
||||
separately. The returned dictionary is the following:
|
||||
|
||||
'base_amount': The total tax base amount in company currency for the whole invoice.
|
||||
'tax_amount': The total tax amount in company currency for the whole invoice.
|
||||
'base_amount_currency': The total tax base amount in foreign currency for the whole invoice.
|
||||
'tax_amount_currency': The total tax amount in foreign currency for the whole invoice.
|
||||
'tax_details': A mapping of each grouping key (see 'grouping_key_generator') to a dictionary
|
||||
containing:
|
||||
|
||||
'base_amount': The tax base amount in company currency for the current group.
|
||||
'tax_amount': The tax amount in company currency for the current group.
|
||||
'base_amount_currency': The tax base amount in foreign currency for the current group.
|
||||
'tax_amount_currency': The tax amount in foreign currency for the current group.
|
||||
'group_tax_details': The list of all tax values aggregated into this group.
|
||||
|
||||
'invoice_line_tax_details': A mapping of each invoice line to a dictionary containing:
|
||||
|
||||
'base_amount': The total tax base amount in company currency for the whole invoice line.
|
||||
'tax_amount': The total tax amount in company currency for the whole invoice line.
|
||||
'base_amount_currency': The total tax base amount in foreign currency for the whole invoice line.
|
||||
'tax_amount_currency': The total tax amount in foreign currency for the whole invoice line.
|
||||
'tax_details': A mapping of each grouping key (see 'grouping_key_generator') to a dictionary
|
||||
containing:
|
||||
|
||||
'base_amount': The tax base amount in company currency for the current group.
|
||||
'tax_amount': The tax amount in company currency for the current group.
|
||||
'base_amount_currency': The tax base amount in foreign currency for the current group.
|
||||
'tax_amount_currency': The tax amount in foreign currency for the current group.
|
||||
'group_tax_details': The list of all tax values aggregated into this group.
|
||||
|
||||
'''
|
||||
self.ensure_one()
|
||||
|
||||
def _serialize_python_dictionary(vals):
|
||||
return '-'.join(str(vals[k]) for k in sorted(vals.keys()))
|
||||
|
||||
def default_grouping_key_generator(tax_values):
|
||||
return {'tax': tax_values['tax_id']}
|
||||
|
||||
# Compute the taxes values for each invoice line.
|
||||
|
||||
invoice_lines = self.invoice_line_ids.filtered(lambda line: not line.display_type)
|
||||
invoice_lines_tax_values_dict = {}
|
||||
sign = -1 if self.is_inbound() else 1
|
||||
for invoice_line in invoice_lines:
|
||||
taxes_res = invoice_line.tax_ids.compute_all(
|
||||
invoice_line.price_unit * (1 - (invoice_line.discount / 100.0)),
|
||||
currency=invoice_line.currency_id,
|
||||
quantity=invoice_line.quantity,
|
||||
product=invoice_line.product_id,
|
||||
partner=invoice_line.partner_id,
|
||||
is_refund=invoice_line.move_id.move_type in ('in_refund', 'out_refund'),
|
||||
)
|
||||
tax_values_list = invoice_lines_tax_values_dict[invoice_line] = []
|
||||
rate = abs(invoice_line.balance) / abs(invoice_line.amount_currency) if invoice_line.amount_currency else 0.0
|
||||
for tax_res in taxes_res['taxes']:
|
||||
tax_values_list.append({
|
||||
'base_line_id': invoice_line,
|
||||
'tax_id': self.env['account.tax'].browse(tax_res['id']),
|
||||
'tax_repartition_line_id': self.env['account.tax.repartition.line'].browse(tax_res['tax_repartition_line_id']),
|
||||
'base_amount': sign * invoice_line.company_currency_id.round(tax_res['base'] / rate if rate else 0.0),
|
||||
'tax_amount': sign * invoice_line.company_currency_id.round(tax_res['amount'] / rate if rate else 0.0),
|
||||
'base_amount_currency': sign * tax_res['base'],
|
||||
'tax_amount_currency': sign * tax_res['amount'],
|
||||
})
|
||||
grouping_key_generator = grouping_key_generator or default_grouping_key_generator
|
||||
|
||||
# Apply 'filter_to_apply'.
|
||||
|
||||
if filter_to_apply:
|
||||
invoice_lines_tax_values_dict = {
|
||||
invoice_line: [x for x in tax_values_list if filter_to_apply(x)]
|
||||
for invoice_line, tax_values_list in invoice_lines_tax_values_dict.items()
|
||||
}
|
||||
|
||||
# Initialize the results dict.
|
||||
|
||||
invoice_global_tax_details = {
|
||||
'base_amount': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'base_amount_currency': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'tax_details': defaultdict(lambda: {
|
||||
'base_amount': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'base_amount_currency': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'group_tax_details': [],
|
||||
}),
|
||||
'invoice_line_tax_details': defaultdict(lambda: {
|
||||
'base_amount': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'base_amount_currency': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'tax_details': defaultdict(lambda: {
|
||||
'base_amount': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'base_amount_currency': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'group_tax_details': [],
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
# Apply 'grouping_key_generator' to 'invoice_lines_tax_values_list' and add all values to the final results.
|
||||
|
||||
for invoice_line in invoice_lines:
|
||||
tax_values_list = invoice_lines_tax_values_dict[invoice_line]
|
||||
|
||||
# Add to invoice global tax amounts.
|
||||
invoice_global_tax_details['base_amount'] += invoice_line.balance
|
||||
invoice_global_tax_details['base_amount_currency'] += invoice_line.amount_currency
|
||||
|
||||
for tax_values in tax_values_list:
|
||||
grouping_key = grouping_key_generator(tax_values)
|
||||
serialized_grouping_key = _serialize_python_dictionary(grouping_key)
|
||||
|
||||
# Add to invoice line global tax amounts.
|
||||
if serialized_grouping_key not in invoice_global_tax_details['invoice_line_tax_details'][invoice_line]:
|
||||
invoice_line_global_tax_details = invoice_global_tax_details['invoice_line_tax_details'][invoice_line]
|
||||
invoice_line_global_tax_details.update({
|
||||
'base_amount': invoice_line.balance,
|
||||
'base_amount_currency': invoice_line.amount_currency,
|
||||
})
|
||||
else:
|
||||
invoice_line_global_tax_details = invoice_global_tax_details['invoice_line_tax_details'][invoice_line]
|
||||
|
||||
self._add_edi_tax_values(invoice_global_tax_details, grouping_key, serialized_grouping_key, tax_values)
|
||||
self._add_edi_tax_values(invoice_line_global_tax_details, grouping_key, serialized_grouping_key, tax_values)
|
||||
|
||||
return invoice_global_tax_details
|
||||
|
||||
def _prepare_edi_vals_to_export(self):
|
||||
''' The purpose of this helper is to prepare values in order to export an invoice through the EDI system.
|
||||
This includes the computation of the tax details for each invoice line that could be very difficult to
|
||||
@@ -144,59 +326,18 @@ class AccountMove(models.Model):
|
||||
'''
|
||||
self.ensure_one()
|
||||
|
||||
def convert(amount):
|
||||
return self.currency_id._convert(amount, self.company_currency_id, self.company_id, self.date)
|
||||
|
||||
res = {
|
||||
'record': self,
|
||||
'balance_multiplicator': -1 if self.is_inbound() else 1,
|
||||
'invoice_line_vals_list': [],
|
||||
}
|
||||
|
||||
# Invoice lines details.
|
||||
tax_detail_per_tax = {}
|
||||
added_base_amount_keys = set()
|
||||
for index, line in enumerate(self.invoice_line_ids.filtered(lambda line: not line.display_type), start=1):
|
||||
line_vals = line._prepare_edi_vals_to_export()
|
||||
line_vals['index'] = index
|
||||
res['invoice_line_vals_list'].append(line_vals)
|
||||
|
||||
# Tax details.
|
||||
for tax_vals in line_vals['tax_detail_vals_list']:
|
||||
tax_detail_per_tax.setdefault(tax_vals['tax'], {
|
||||
'tax': tax_vals['tax'],
|
||||
'orig_tax': tax_vals['orig_tax'],
|
||||
'tax_base_amount_currency': 0.0,
|
||||
'tax_amount': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'tax_amount_closing': 0.0,
|
||||
'tax_amount_currency_closing': 0.0,
|
||||
'tag_ids': set(),
|
||||
})
|
||||
vals = tax_detail_per_tax[tax_vals['tax']]
|
||||
|
||||
# Avoid adding multiple times the same base (e.g. with multiple taxes on the same line or multiple
|
||||
# repartition lines).
|
||||
base_amount_key = (line.id, tax_vals['tax']['id'])
|
||||
if base_amount_key not in added_base_amount_keys:
|
||||
vals['tax_base_amount_currency'] += tax_vals['tax_base_amount_currency']
|
||||
added_base_amount_keys.add(base_amount_key)
|
||||
|
||||
vals['tax_amount_currency'] += tax_vals['tax_amount_currency']
|
||||
vals['tax_amount_currency_closing'] += tax_vals['tax_amount_currency_closing']
|
||||
for tag in tax_vals['tags']:
|
||||
vals['tag_ids'].add(tag.id)
|
||||
|
||||
# Format the aggregated tax details as a list.
|
||||
res['tax_detail_vals_list'] = []
|
||||
for tax_detail_vals in tax_detail_per_tax.values():
|
||||
res['tax_detail_vals_list'].append({
|
||||
**tax_detail_vals,
|
||||
'tags': self.env['account.account.tag'].browse(tax_detail_vals['tag_ids']),
|
||||
'tax_base_amount': convert(tax_detail_vals['tax_base_amount_currency']),
|
||||
'tax_amount': convert(tax_detail_vals['tax_amount_currency']),
|
||||
'tax_amount_closing': convert(tax_detail_vals['tax_amount_currency_closing']),
|
||||
})
|
||||
|
||||
# Totals.
|
||||
res.update({
|
||||
'total_price_subtotal_before_discount': sum(x['price_subtotal_before_discount'] for x in res['invoice_line_vals_list']),
|
||||
@@ -390,9 +531,6 @@ class AccountMoveLine(models.Model):
|
||||
'''
|
||||
self.ensure_one()
|
||||
|
||||
def convert(amount):
|
||||
return self.currency_id._convert(amount, self.company_currency_id, self.company_id, self.date)
|
||||
|
||||
res = {
|
||||
'line': self,
|
||||
'price_unit_after_discount': self.price_unit * (1 - (self.discount / 100.0)),
|
||||
@@ -403,50 +541,6 @@ class AccountMoveLine(models.Model):
|
||||
|
||||
res['price_discount'] = res['price_subtotal_before_discount'] - self.price_subtotal
|
||||
|
||||
# Tax details.
|
||||
tax_detail_per_tax = {}
|
||||
taxes_res = self.tax_ids.compute_all(
|
||||
res['price_unit_after_discount'],
|
||||
currency=self.currency_id,
|
||||
quantity=self.quantity,
|
||||
product=self.product_id,
|
||||
partner=self.partner_id,
|
||||
is_refund=self.move_id.move_type in ('in_refund', 'out_refund'),
|
||||
)
|
||||
taxes_added_to_base = set()
|
||||
for tax_vals in taxes_res['taxes']:
|
||||
tax_rep = self.env['account.tax.repartition.line'].browse(tax_vals['tax_repartition_line_id'])
|
||||
tax = tax_rep.tax_id
|
||||
tax_detail_per_tax.setdefault(tax, {
|
||||
'tax': tax,
|
||||
'orig_tax': tax_vals['group'].id if tax_vals['group'] else tax.id,
|
||||
'tax_base_amount_currency': 0.0,
|
||||
'tax_amount_currency': 0.0,
|
||||
'tax_amount_currency_closing': 0.0,
|
||||
'tag_ids': set(),
|
||||
})
|
||||
vals = tax_detail_per_tax[tax]
|
||||
|
||||
# Avoid adding multiple times the same base (e.g. with multiple repartition lines).
|
||||
if tax.id not in taxes_added_to_base:
|
||||
vals['tax_base_amount_currency'] = tax_vals['base']
|
||||
taxes_added_to_base.add(tax.id)
|
||||
|
||||
vals['tax_amount_currency'] += tax_vals['amount']
|
||||
vals['tax_amount_currency_closing'] += tax_vals['amount'] if tax_rep.use_in_tax_closing else 0
|
||||
for tag_id in tax_rep.tag_ids:
|
||||
vals['tag_ids'].add(tag_id)
|
||||
|
||||
res['tax_detail_vals_list'] = []
|
||||
for tax_detail_vals in tax_detail_per_tax.values():
|
||||
res['tax_detail_vals_list'].append({
|
||||
**tax_detail_vals,
|
||||
'tags': self.env['account.account.tag'].browse(tax_detail_vals['tag_ids']),
|
||||
'tax_base_amount': convert(tax_detail_vals['tax_base_amount_currency']),
|
||||
'tax_amount': convert(tax_detail_vals['tax_amount_currency']),
|
||||
'tax_amount_closing': convert(tax_detail_vals['tax_amount_currency_closing']),
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
def reconcile(self):
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<t t-foreach="line_vals['tax_detail_vals_list']" t-as="tax_detail_vals">
|
||||
<t t-foreach="tax_details['invoice_line_tax_details'][line]['tax_details'].values()"
|
||||
t-as="tax_detail_vals">
|
||||
<t t-set="tax" t-value="tax_detail_vals['tax']"/>
|
||||
<ram:ApplicableTradeTax t-if="tax.amount_type == 'percent'">
|
||||
<ram:RateApplicablePercent t-esc="tax.amount"/>
|
||||
@@ -182,15 +183,15 @@
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
|
||||
<!-- Tax Summary. -->
|
||||
<t t-foreach="tax_detail_vals_list" t-as="tax_detail_vals">
|
||||
<t t-foreach="tax_details['tax_details'].values()" t-as="tax_detail_vals">
|
||||
<t t-set="tax" t-value="tax_detail_vals['tax']"/>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount
|
||||
t-att-currencyID="record.currency_id.name"
|
||||
t-esc="format_monetary(tax_detail_vals['tax_amount_currency'], record.currency_id)"/>
|
||||
t-esc="format_monetary(balance_multiplicator * tax_detail_vals['tax_amount_currency'], record.currency_id)"/>
|
||||
<ram:BasisAmount
|
||||
t-att-currencyID="record.currency_id.name"
|
||||
t-esc="format_monetary(tax_detail_vals['tax_base_amount_currency'], record.currency_id)"/>
|
||||
t-esc="format_monetary(balance_multiplicator * tax_detail_vals['base_amount_currency'], record.currency_id)"/>
|
||||
<ram:RateApplicablePercent
|
||||
t-if="tax.amount_type == 'percent'"
|
||||
t-esc="tax.amount"/>
|
||||
|
||||
@@ -59,6 +59,7 @@ class AccountEdiFormat(models.Model):
|
||||
# Create file content.
|
||||
template_values = {
|
||||
**invoice._prepare_edi_vals_to_export(),
|
||||
'tax_details': invoice._prepare_edi_tax_details(),
|
||||
'format_date': format_date,
|
||||
'format_monetary': format_monetary,
|
||||
'is_html_empty': is_html_empty,
|
||||
|
||||
@@ -82,11 +82,11 @@
|
||||
t-att-currencyID="line.currency_id.name"
|
||||
t-esc="format_monetary(line.price_subtotal)"/>
|
||||
<cac:TaxTotal
|
||||
t-foreach="line_vals['tax_detail_vals_list']"
|
||||
t-foreach="tax_details['invoice_line_tax_details'][line]['tax_details'].values()"
|
||||
t-as="tax_detail_vals">
|
||||
<cbc:TaxAmount
|
||||
t-att-currencyID="line.currency_id.name"
|
||||
t-esc="format_monetary(tax_detail_vals['tax_amount_currency'])"/>
|
||||
t-esc="format_monetary(-tax_detail_vals['tax_amount_currency'])"/>
|
||||
</cac:TaxTotal>
|
||||
<cac:Item>
|
||||
<cbc:Description t-if="line.name" t-esc="line.name.replace('\n', ', ')"/>
|
||||
|
||||
@@ -190,6 +190,7 @@ class AccountEdiFormat(models.Model):
|
||||
|
||||
return {
|
||||
**invoice._prepare_edi_vals_to_export(),
|
||||
'tax_details': invoice._prepare_edi_tax_details(),
|
||||
'ubl_version': 2.1,
|
||||
'type_code': 380 if invoice.move_type == 'out_invoice' else 381,
|
||||
'payment_means_code': 42 if invoice.journal_id.bank_account_id else 31,
|
||||
|
||||
@@ -82,9 +82,11 @@
|
||||
<cac:SellersItemIdentification t-if="line.product_id.default_code">
|
||||
<cbc:ID t-esc="line.product_id.default_code"/>
|
||||
</cac:SellersItemIdentification>
|
||||
<cac:ClassifiedTaxCategory>
|
||||
<cbc:ID t-esc="line_vals['tax_detail_vals']['tax_category']"/>
|
||||
<cbc:Percent t-esc="line_vals['tax_detail_vals']['tax_percent']"/>
|
||||
<cac:ClassifiedTaxCategory
|
||||
t-foreach="tax_details['invoice_line_tax_details'][line]['tax_details'].values()"
|
||||
t-as="tax_detail_vals">
|
||||
<cbc:ID t-esc="tax_detail_vals['tax_category']"/>
|
||||
<cbc:Percent t-esc="tax_detail_vals['tax_percent']"/>
|
||||
<cac:TaxScheme>
|
||||
<cbc:ID>VAT</cbc:ID>
|
||||
</cac:TaxScheme>
|
||||
@@ -139,14 +141,14 @@
|
||||
<cac:TaxTotal>
|
||||
<cbc:TaxAmount
|
||||
t-att-currencyID="record.currency_id.name"
|
||||
t-esc="format_monetary(total_tax_amount_currency)"/>
|
||||
<cac:TaxSubtotal t-foreach="tax_detail_vals_list" t-as="tax_detail_vals">
|
||||
t-esc="format_monetary(balance_multiplicator * tax_details['tax_amount_currency'])"/>
|
||||
<cac:TaxSubtotal t-foreach="tax_details['tax_details'].values()" t-as="tax_detail_vals">
|
||||
<cbc:TaxableAmount
|
||||
t-att-currencyID="record.currency_id.name"
|
||||
t-esc="format_monetary(tax_detail_vals['base_currency'])"/>
|
||||
t-esc="format_monetary(balance_multiplicator * tax_detail_vals['base_amount_currency'])"/>
|
||||
<cbc:TaxAmount
|
||||
t-att-currencyID="record.currency_id.name"
|
||||
t-esc="format_monetary(tax_detail_vals['amount_currency'])"/>
|
||||
t-esc="format_monetary(balance_multiplicator * tax_detail_vals['tax_amount_currency'])"/>
|
||||
<cac:TaxCategory>
|
||||
<cbc:ID t-esc="tax_detail_vals['tax_category']"/>
|
||||
<cbc:Percent t-esc="tax_detail_vals['tax_percent']"/>
|
||||
@@ -159,7 +161,7 @@
|
||||
<cac:TaxTotal t-if="record.currency_id != record.company_currency_id">
|
||||
<cbc:TaxAmount
|
||||
t-att-currencyID="record.company_currency_id.name"
|
||||
t-esc="format_monetary(total_tax_amount)"/>
|
||||
t-esc="format_monetary(balance_multiplicator * tax_details['tax_amount'])"/>
|
||||
</cac:TaxTotal>
|
||||
<cac:LegalMonetaryTotal>
|
||||
<cbc:LineExtensionAmount
|
||||
|
||||
@@ -65,54 +65,34 @@ class AccountEdiFormat(models.Model):
|
||||
'profile_id': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
|
||||
})
|
||||
|
||||
all_tax_detail_per_tax = {}
|
||||
# Tax details.
|
||||
|
||||
def grouping_key_generator(tax_values):
|
||||
tax = tax_values['tax_id']
|
||||
return {
|
||||
'tax_percent': tax.amount,
|
||||
'tax_category': 'S' if tax.amount else 'Z',
|
||||
}
|
||||
|
||||
values['tax_details'] = invoice._prepare_edi_tax_details(
|
||||
filter_to_apply=lambda x: x['tax_repartition_line_id'].use_in_tax_closing,
|
||||
grouping_key_generator=grouping_key_generator,
|
||||
)
|
||||
for line_vals in values['invoice_line_vals_list']:
|
||||
line_vals['price_subtotal_with_no_tax_closing'] = line_vals['line'].price_subtotal
|
||||
tax_detail_per_tax = {}
|
||||
for tax_detail_vals in line_vals['tax_detail_vals_list']:
|
||||
tax = tax_detail_vals['tax']
|
||||
|
||||
tax_percent = tax.amount
|
||||
tax_category = 'S' if tax_percent else 'Z'
|
||||
key = (tax_category, tax_percent)
|
||||
tax_detail_per_tax.setdefault(key, {
|
||||
'base': tax_detail_vals['tax_base_amount'],
|
||||
'base_currency': tax_detail_vals['tax_base_amount_currency'],
|
||||
'amount': 0.0,
|
||||
'amount_currency': 0.0,
|
||||
'tax_percent': tax_percent,
|
||||
'tax_category': tax_category,
|
||||
})
|
||||
vals = tax_detail_per_tax[key]
|
||||
|
||||
vals['amount'] += tax_detail_vals['tax_amount_closing']
|
||||
vals['amount_currency'] += tax_detail_vals['tax_amount_currency_closing']
|
||||
delta_tax = tax_detail_vals['tax_amount_currency'] - tax_detail_vals['tax_amount_currency_closing']
|
||||
line_vals['price_subtotal_with_no_tax_closing'] += delta_tax
|
||||
|
||||
if len(tax_detail_per_tax) > 1:
|
||||
if len(values['tax_details']['invoice_line_tax_details'][line_vals['line']]['tax_details']) > 1:
|
||||
raise UserError("Multiple vat percentage not supported on the same invoice line")
|
||||
|
||||
line_vals['tax_detail_vals'] = list(tax_detail_per_tax.values())[0]
|
||||
tax_details_no_tax_closing = invoice._prepare_edi_tax_details(
|
||||
filter_to_apply=lambda x: not x['tax_repartition_line_id'].use_in_tax_closing,
|
||||
)
|
||||
for line_vals in values['invoice_line_vals_list']:
|
||||
line_vals['price_subtotal_with_no_tax_closing'] = line_vals['line'].price_subtotal
|
||||
for tax_detail in tax_details_no_tax_closing['invoice_line_tax_details'][line_vals['line']]['tax_details'].values():
|
||||
line_vals['price_subtotal_with_no_tax_closing'] += tax_detail['tax_amount_currency']
|
||||
|
||||
for key, tax_vals in tax_detail_per_tax.items():
|
||||
all_tax_detail_per_tax.setdefault(key, {
|
||||
**tax_vals,
|
||||
'base': 0.0,
|
||||
'base_currency': 0.0,
|
||||
'amount': 0.0,
|
||||
'amount_currency': 0.0,
|
||||
})
|
||||
vals = all_tax_detail_per_tax[key]
|
||||
vals['base'] += tax_vals['base']
|
||||
vals['base_currency'] += tax_vals['base_currency']
|
||||
vals['amount'] += tax_vals['amount']
|
||||
vals['amount_currency'] += tax_vals['amount_currency']
|
||||
|
||||
values['tax_detail_vals_list'] = list(all_tax_detail_per_tax.values())
|
||||
values['total_untaxed_amount'] = sum(x['price_subtotal_with_no_tax_closing'] for x in values['invoice_line_vals_list'])
|
||||
values['total_tax_amount'] = sum(x['amount'] for x in values['tax_detail_vals_list'])
|
||||
values['total_tax_amount_currency'] = sum(x['amount_currency'] for x in values['tax_detail_vals_list'])
|
||||
|
||||
# Misc.
|
||||
|
||||
for partner_vals in (values['customer_vals'], values['supplier_vals']):
|
||||
partner = partner_vals['partner']
|
||||
|
||||
Reference in New Issue
Block a user