210 lines
12 KiB
Python
210 lines
12 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.tools import parse_date
|
|
from odoo.tools.float_utils import float_round
|
|
|
|
|
|
class AccountReport(models.Model):
|
|
_inherit = 'account.report'
|
|
|
|
def assets_init_custom_options(self, options, previous_options):
|
|
super().assets_init_custom_options(options, previous_options)
|
|
if self.env.company.country_id.code == 'LU':
|
|
options.setdefault('buttons', []).append({
|
|
'name': _('XML'), 'sequence': 30, 'action': 'l10n_lu_export_asset_report_to_xml', 'file_export_type': _('XML')
|
|
})
|
|
|
|
def l10n_lu_export_asset_report_to_xml(self, options):
|
|
new_context = self.env.context.copy()
|
|
new_context['report_generation_options'] = options
|
|
new_context['report_generation_options']['report_id'] = self.id
|
|
generate_xml = self.env['l10n_lu.generate.asset.report'].with_context(new_context).create({})
|
|
return generate_xml.get_xml()
|
|
|
|
def l10n_lu_asset_report_get_xml_2_0_report_values(self, options):
|
|
"""
|
|
Returns the formatted values for the LU eCDF declaration "Tables of acquisitions / amortisable expenditures".
|
|
(https://ecdf-developer.b2g.etat.lu/ecdf/forms/popup/AN_TABACAM_TYPE/2020/en/1/preview)
|
|
"""
|
|
def _get_assets_data(lines):
|
|
"""
|
|
Retrieves additional data (VAT paid, depreciable values) needed for the eCDF declaration
|
|
"Tables of acquisitions / amortisable expenditures", that is not present in the result from _get_lines.
|
|
The information about the VAT paid for the asset is retrieved from the tax's account.move.line
|
|
of the account.move, taken in proportion to the price of the asset.
|
|
|
|
:param lines: the result from _get_lines (the various assets)
|
|
:return a dictionary containing:
|
|
* 'tax_amounts': The VAT paid for each asset
|
|
* 'depreciable_values': The depreciable value of each asset
|
|
"""
|
|
# ids of asset lines are in the form <account_group>_<asset_id>
|
|
asset_ids = {}
|
|
for line in lines:
|
|
res_model, model_id = self._get_model_info_from_id(line['id'])
|
|
if res_model == 'account.asset':
|
|
asset_ids[model_id] = line['id']
|
|
assets = self.env['account.asset'].search([('id', 'in', list(asset_ids.keys()))])
|
|
# Check that all assets are in EUR and that the company has EUR as its currency;
|
|
asset_currencies = assets.mapped('currency_id')
|
|
if any([curr != self.env.ref('base.EUR') for curr in list(asset_currencies) + [self.env.company.currency_id]]):
|
|
raise ValidationError(_("Only assets having EUR currency for companies using EUR currency can be reported."))
|
|
depreciable_values = {
|
|
asset_ids.get(asset_id): float(original_value) - float(salvage_value)
|
|
for (asset_id, salvage_value, original_value) in assets.mapped(
|
|
lambda r: (r.id, r.salvage_value, r.original_value)
|
|
)
|
|
}
|
|
# The tax paid for the products in the asset must be retrieved from the original_move_line_ids
|
|
tax_amounts = {}
|
|
for asset in assets:
|
|
total_tax = 0.00
|
|
for ml in asset.original_move_line_ids:
|
|
balance = ml.balance
|
|
if asset.account_asset_id.multiple_assets_per_line and len(asset.original_move_line_ids) == 1:
|
|
balance /= max(1, int(ml.quantity))
|
|
for tax in ml.tax_ids:
|
|
# Take the corresponding tax account.move.line on the account.move if the tax is VAT and debit
|
|
tax_line = ml.move_id.line_ids.filtered(lambda r: r.tax_line_id == tax and r.tax_repartition_line_id and r.debit)
|
|
if tax_line:
|
|
total_tax += tax_line.balance * balance / tax_line.tax_base_amount
|
|
if total_tax: # only keep taxes with amounts different from 0
|
|
tax_amounts[asset_ids.get(asset['id'])] = total_tax
|
|
return depreciable_values, tax_amounts
|
|
|
|
lu_template_values = self.env['l10n_lu.report.handler'].get_electronic_report_values(options)
|
|
|
|
date_from = fields.Date.from_string(options['date'].get('date_from'))
|
|
date_to = fields.Date.from_string(options['date'].get('date_to'))
|
|
values = {
|
|
'233': {'field_type': 'number', 'value': date_from.day},
|
|
'234': {'field_type': 'number', 'value': date_from.month},
|
|
'235': {'field_type': 'number', 'value': date_to.day},
|
|
'236': {'field_type': 'number', 'value': date_to.month}
|
|
}
|
|
options.update({'filter_unfolded_lines': True})
|
|
lines = self._get_lines(options)
|
|
# get additional data not shown in the assets report (tax paid, depreciable value)
|
|
depreciable_values, tax_amounts = _get_assets_data(lines)
|
|
# format the values for XML report
|
|
update_values, expenditures_table, depreciations_table = self._l10n_lu_get_expenditures_and_depreciations_tables(
|
|
lines, tax_amounts, depreciable_values
|
|
)
|
|
values.update(update_values)
|
|
# only add the tables if they contain data
|
|
tables = [table for table in (expenditures_table, depreciations_table) if table]
|
|
|
|
lu_template_values.update({
|
|
'forms': [{
|
|
'declaration_type': 'AN_TABACAM',
|
|
'year': date_from.year,
|
|
'period': '1',
|
|
'currency': self.env.company.currency_id.name,
|
|
'model': '1',
|
|
'field_values': values,
|
|
'tables': tables
|
|
}]
|
|
})
|
|
return lu_template_values
|
|
|
|
def _l10n_lu_get_expenditures_and_depreciations_tables(self, lines, tax_amounts, depreciable_values):
|
|
"""
|
|
Returns the table to fill in the LU declaration "Tables of acquisitions / amortisable expenditures".
|
|
|
|
:param lines: the lines from account.report's _get_lines
|
|
:param tax_amounts: dict containing the total tax paid on each asset
|
|
:param depreciable_values: dict containing the depreciable amounts for each asset
|
|
:return the formatted "Table of acquisitions", "Table of amortisable expenditures", and the table totals
|
|
"""
|
|
update_values = {}
|
|
expenditures_table = []
|
|
depreciations_table = []
|
|
|
|
n_expenditure = 0
|
|
for line in lines:
|
|
acquisition_date = parse_date(self.env, parse_date(self.env, line['columns'][0].get('name', '')))
|
|
if self._get_model_info_from_id(line['id'])[0] != 'account.asset' or isinstance(acquisition_date, (str, type(None))):
|
|
# only 2 levels are possible, level 0 are totals
|
|
continue
|
|
acquisition_date = acquisition_date.strftime('%d%m%Y')
|
|
# Update expenditures table
|
|
n_expenditure += 1
|
|
name = line['name']
|
|
acquisition_cost_no_vat = float(line['columns'][3].get('no_format', 0)) + float(line['columns'][4].get('no_format', 0))
|
|
vat = float(tax_amounts.get(line['id'], 0.))
|
|
value_to_be_depreciated = float(depreciable_values.get(line['id'], 0))
|
|
expenditures_line = {
|
|
'501': {'field_type': 'number', 'value': str(n_expenditure)},
|
|
'502': {'field_type': 'char', 'value': acquisition_date},
|
|
'503': {'field_type': 'char', 'value': name}
|
|
}
|
|
if vat:
|
|
expenditures_line.update({
|
|
'504': {'field_type': 'float', 'value': float_round((acquisition_cost_no_vat + vat), 2)},
|
|
'505': {'field_type': 'float', 'value': float_round(vat, 2)},
|
|
})
|
|
expenditures_line['506'] = {'field_type': 'float', 'value': float_round(acquisition_cost_no_vat, 2)}
|
|
expenditures_line['508'] = {'field_type': 'float', 'value': float_round(value_to_be_depreciated, 2)}
|
|
expenditures_table.append(expenditures_line)
|
|
|
|
# Update Depreciation/amortisation table
|
|
depreciation_or_amortisation = float(line['columns'][2].get('name', '')[:-2] or 0) # remove ' %' sign
|
|
# Book value at the beginning of the reported accounting period (not reported by super's _get_lines)
|
|
# asset_opening (acquisition price at the beginning of the accounting period)
|
|
# - depreciation_opening (depreciated value at the beginning of the accounting period)
|
|
book_value_beginning = float(line['columns'][3].get('no_format', 0)) - float(line['columns'][8].get('no_format', 0))
|
|
acquisitions = float(line['columns'][4].get('no_format', 0))
|
|
sales = float(line['columns'][5].get('no_format', 0))
|
|
# Depreciation reported from _get_lines divided in value decrease (+) and value increase (-);
|
|
# depreciation is the net difference
|
|
depreciation = float(line['columns'][8].get('no_format', 0)) - float(line['columns'][9].get('no_format', 0))
|
|
book_value_end = float(line['columns'][11].get('no_format', 0))
|
|
depreciations_line = {
|
|
'617': {'field_type': 'number', 'value': str(n_expenditure)},
|
|
'602': {'field_type': 'char', 'value': acquisition_date},
|
|
'601': {'field_type': 'char', 'value': name},
|
|
'603': {'field_type': 'float', 'value': float_round(value_to_be_depreciated, 2)},
|
|
'604': {'field_type': 'float', 'value': float_round(depreciation_or_amortisation, 2)},
|
|
'605': {'field_type': 'float', 'value': float_round(book_value_beginning, 2)},
|
|
'606': {'field_type': 'float', 'value': float_round(acquisitions, 2)},
|
|
'607': {'field_type': 'float', 'value': float_round(sales, 2)},
|
|
'608': {'field_type': 'float', 'value': float_round(depreciation, 2)},
|
|
'609': {'field_type': 'float', 'value': float_round(book_value_end, 2)}
|
|
}
|
|
# the following fields are not required in the report; only report if they are different from 0
|
|
for key in range(604, 610):
|
|
if depreciations_line.get(str(key)) and depreciations_line[str(key)]['value'] == 0.00:
|
|
depreciations_line.pop(str(key))
|
|
depreciations_table.append(depreciations_line)
|
|
|
|
# Expenditures table totals
|
|
total_vat = sum([i.get('505', {'value': 0.00})['value'] for i in expenditures_table])
|
|
total_acquisition_cost = sum([i['506']['value'] for i in expenditures_table])
|
|
totals_expenditures_table = {
|
|
'509': {'field_type': 'float', 'value': total_vat},
|
|
'510': {'field_type': 'float', 'value': total_acquisition_cost}
|
|
}
|
|
# Depreciations table totals
|
|
total_book_value_beginning = sum([i.get('605') and i['605']['value'] or 0.0 for i in depreciations_table])
|
|
total_acquisitions = sum([i.get('606') and i['606']['value'] or 0.0 for i in depreciations_table])
|
|
total_sales = sum([i.get('607') and i['607']['value'] or 0.0 for i in depreciations_table])
|
|
total_depreciation = sum([i.get('608') and i['608']['value'] or 0.0 for i in depreciations_table])
|
|
total_book_value_end = sum([i.get('609') and i['609']['value'] or 0.0 for i in depreciations_table])
|
|
totals_depreciations_table = {
|
|
'610': {'field_type': 'float', 'value': total_book_value_beginning},
|
|
'611': {'field_type': 'float', 'value': total_acquisitions},
|
|
'612': {'field_type': 'float', 'value': total_sales},
|
|
'613': {'field_type': 'float', 'value': total_depreciation},
|
|
'614': {'field_type': 'float', 'value': total_book_value_end}
|
|
}
|
|
# for now, everything is considered business portion; so no private part => 615 not filled in
|
|
if totals_depreciations_table['613']['value'] != 0.00:
|
|
totals_depreciations_table['616'] = {'field_type': 'float', 'value': totals_depreciations_table['613']['value']}
|
|
|
|
update_values.update(totals_expenditures_table)
|
|
update_values.update(totals_depreciations_table)
|
|
return update_values, expenditures_table, depreciations_table
|