From fca42acaa629e70b58affcad3968412a47bcc872 Mon Sep 17 00:00:00 2001 From: alex_cam Date: Fri, 26 Jun 2020 09:41:15 +0200 Subject: [PATCH 01/52] [12.0][ADD] New module for assets management --- assets_management/__init__.py | 7 + assets_management/__manifest__.py | 52 + assets_management/data/asset_data.xml | 45 + assets_management/data/ir_cron.xml | 17 + assets_management/i18n/it.po | 3241 +++++++++++++++++ assets_management/models/__init__.py | 22 + assets_management/models/account_account.py | 29 + .../models/account_fiscal_year.py | 39 + assets_management/models/account_invoice.py | 128 + .../models/account_invoice_line.py | 91 + assets_management/models/account_journal.py | 21 + assets_management/models/account_move.py | 128 + assets_management/models/account_move_line.py | 72 + assets_management/models/asset.py | 280 ++ .../models/asset_accounting_info.py | 258 ++ assets_management/models/asset_category.py | 142 + .../asset_category_depreciation_type.py | 61 + .../models/asset_depreciation.py | 628 ++++ .../models/asset_depreciation_line.py | 518 +++ .../models/asset_depreciation_line_type.py | 66 + .../models/asset_depreciation_mode.py | 104 + .../models/asset_depreciation_mode_line.py | 83 + .../models/asset_depreciation_type.py | 49 + assets_management/models/asset_tag.py | 25 + assets_management/readme/CONTRIBUTORS.rst | 3 + assets_management/readme/DESCRIPTION.rst | 1 + assets_management/readme/USAGE.rst | 25 + assets_management/report/__init__.py | 8 + assets_management/report/asset_journal.py | 932 +++++ .../report/asset_journal_xlsx.py | 553 +++ assets_management/report/asset_previsional.py | 965 +++++ .../report/asset_previsional_xlsx.py | 514 +++ assets_management/report/layout.xml | 58 + assets_management/report/paperformat.xml | 34 + assets_management/report/reports.xml | 50 + .../report/templates/asset_journal.xml | 798 ++++ .../report/templates/asset_previsional.xml | 700 ++++ .../security/ir.model.access.csv | 12 + assets_management/security/res_groups.xml | 14 + assets_management/security/rules.xml | 105 + assets_management/static/description/icon.png | Bin 0 -> 10456 bytes assets_management/static/src/css/report.css | 103 + assets_management/views/account_invoice.xml | 134 + assets_management/views/account_move.xml | 95 + assets_management/views/action_client.xml | 18 + assets_management/views/asset.xml | 180 + .../views/asset_accounting_info.xml | 113 + assets_management/views/asset_category.xml | 84 + .../views/asset_depreciation.xml | 132 + .../views/asset_depreciation_line.xml | 144 + .../views/asset_depreciation_line_type.xml | 46 + .../views/asset_depreciation_mode.xml | 66 + .../views/asset_depreciation_type.xml | 46 + assets_management/views/asset_menuitems.xml | 39 + assets_management/views/asset_tag.xml | 42 + assets_management/wizard/__init__.py | 9 + .../wizard/account_invoice_manage_asset.py | 637 ++++ .../account_invoice_manage_asset_view.xml | 232 ++ .../wizard/account_move_manage_asset.py | 649 ++++ .../wizard/account_move_manage_asset_view.xml | 200 + .../wizard/asset_generate_depreciation.py | 96 + .../asset_generate_depreciation_view.xml | 69 + .../wizard/asset_journal_report.py | 186 + .../wizard/asset_journal_report_view.xml | 77 + .../wizard/asset_previsional_report.py | 182 + .../wizard/asset_previsional_report_view.xml | 77 + 66 files changed, 14534 insertions(+) create mode 100644 assets_management/__init__.py create mode 100644 assets_management/__manifest__.py create mode 100644 assets_management/data/asset_data.xml create mode 100644 assets_management/data/ir_cron.xml create mode 100644 assets_management/i18n/it.po create mode 100644 assets_management/models/__init__.py create mode 100644 assets_management/models/account_account.py create mode 100644 assets_management/models/account_fiscal_year.py create mode 100644 assets_management/models/account_invoice.py create mode 100644 assets_management/models/account_invoice_line.py create mode 100644 assets_management/models/account_journal.py create mode 100644 assets_management/models/account_move.py create mode 100644 assets_management/models/account_move_line.py create mode 100644 assets_management/models/asset.py create mode 100644 assets_management/models/asset_accounting_info.py create mode 100644 assets_management/models/asset_category.py create mode 100644 assets_management/models/asset_category_depreciation_type.py create mode 100644 assets_management/models/asset_depreciation.py create mode 100644 assets_management/models/asset_depreciation_line.py create mode 100644 assets_management/models/asset_depreciation_line_type.py create mode 100644 assets_management/models/asset_depreciation_mode.py create mode 100644 assets_management/models/asset_depreciation_mode_line.py create mode 100644 assets_management/models/asset_depreciation_type.py create mode 100644 assets_management/models/asset_tag.py create mode 100644 assets_management/readme/CONTRIBUTORS.rst create mode 100644 assets_management/readme/DESCRIPTION.rst create mode 100644 assets_management/readme/USAGE.rst create mode 100644 assets_management/report/__init__.py create mode 100644 assets_management/report/asset_journal.py create mode 100644 assets_management/report/asset_journal_xlsx.py create mode 100644 assets_management/report/asset_previsional.py create mode 100644 assets_management/report/asset_previsional_xlsx.py create mode 100644 assets_management/report/layout.xml create mode 100644 assets_management/report/paperformat.xml create mode 100644 assets_management/report/reports.xml create mode 100644 assets_management/report/templates/asset_journal.xml create mode 100644 assets_management/report/templates/asset_previsional.xml create mode 100755 assets_management/security/ir.model.access.csv create mode 100644 assets_management/security/res_groups.xml create mode 100644 assets_management/security/rules.xml create mode 100644 assets_management/static/description/icon.png create mode 100644 assets_management/static/src/css/report.css create mode 100644 assets_management/views/account_invoice.xml create mode 100644 assets_management/views/account_move.xml create mode 100644 assets_management/views/action_client.xml create mode 100755 assets_management/views/asset.xml create mode 100644 assets_management/views/asset_accounting_info.xml create mode 100644 assets_management/views/asset_category.xml create mode 100644 assets_management/views/asset_depreciation.xml create mode 100644 assets_management/views/asset_depreciation_line.xml create mode 100644 assets_management/views/asset_depreciation_line_type.xml create mode 100644 assets_management/views/asset_depreciation_mode.xml create mode 100644 assets_management/views/asset_depreciation_type.xml create mode 100644 assets_management/views/asset_menuitems.xml create mode 100644 assets_management/views/asset_tag.xml create mode 100644 assets_management/wizard/__init__.py create mode 100644 assets_management/wizard/account_invoice_manage_asset.py create mode 100644 assets_management/wizard/account_invoice_manage_asset_view.xml create mode 100644 assets_management/wizard/account_move_manage_asset.py create mode 100644 assets_management/wizard/account_move_manage_asset_view.xml create mode 100644 assets_management/wizard/asset_generate_depreciation.py create mode 100644 assets_management/wizard/asset_generate_depreciation_view.xml create mode 100644 assets_management/wizard/asset_journal_report.py create mode 100644 assets_management/wizard/asset_journal_report_view.xml create mode 100644 assets_management/wizard/asset_previsional_report.py create mode 100644 assets_management/wizard/asset_previsional_report_view.xml diff --git a/assets_management/__init__.py b/assets_management/__init__.py new file mode 100644 index 000000000000..d37ed07fa5c3 --- /dev/null +++ b/assets_management/__init__.py @@ -0,0 +1,7 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models +from . import report +from . import wizard diff --git a/assets_management/__manifest__.py b/assets_management/__manifest__.py new file mode 100644 index 000000000000..a081ef3672aa --- /dev/null +++ b/assets_management/__manifest__.py @@ -0,0 +1,52 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + 'name': 'ITA - Gestione Cespiti', + 'version': '12.0.1.0.0', + 'category': 'Localization/Italy', + 'summary': "Gestione Cespiti", + 'author': 'Openforce, Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/l10n-italy/tree/12.0/assets_management', + 'license': 'AGPL-3', + 'depends': [ + 'account', + 'account_cancel', + 'account_financial_report', + 'account_fiscal_year', + 'mail', + ], + 'data': [ + 'security/ir.model.access.csv', + 'security/res_groups.xml', + 'security/rules.xml', + 'data/ir_cron.xml', + 'data/asset_data.xml', + 'report/layout.xml', + 'report/paperformat.xml', + 'report/templates/asset_journal.xml', + 'report/templates/asset_previsional.xml', + 'report/reports.xml', + 'views/action_client.xml', + 'views/asset_menuitems.xml', + 'views/account_invoice.xml', + 'views/account_move.xml', + 'views/asset.xml', + 'views/asset_accounting_info.xml', + 'views/asset_category.xml', + 'views/asset_depreciation.xml', + 'views/asset_depreciation_line.xml', + 'views/asset_depreciation_line_type.xml', + 'views/asset_depreciation_mode.xml', + 'views/asset_depreciation_type.xml', + 'views/asset_tag.xml', + 'wizard/account_invoice_manage_asset_view.xml', + 'wizard/account_move_manage_asset_view.xml', + 'wizard/asset_generate_depreciation_view.xml', + 'wizard/asset_journal_report_view.xml', + 'wizard/asset_previsional_report_view.xml', + ], + 'development_status': 'Beta', + 'installable': True, +} diff --git a/assets_management/data/asset_data.xml b/assets_management/data/asset_data.xml new file mode 100644 index 000000000000..dec82812daf7 --- /dev/null +++ b/assets_management/data/asset_data.xml @@ -0,0 +1,45 @@ + + + + + + Civilistico + 1 + 1 + + + Fiscale + 0 + 1 + + + + + Rivalutazione + RIV + in + + + + Svalutazione + SVA + out + + + + + IMMATERIALE + 1 + + + MATERIALE + 1 + + + + 1 + 1 + 0.5 + + + diff --git a/assets_management/data/ir_cron.xml b/assets_management/data/ir_cron.xml new file mode 100644 index 000000000000..b4f3434c46da --- /dev/null +++ b/assets_management/data/ir_cron.xml @@ -0,0 +1,17 @@ + + + + + Vacuum Empty Asset Accounting Info + + + 5 + minutes + -1 + + + code + model.cron_vacuum_table() + + + diff --git a/assets_management/i18n/it.po b/assets_management/i18n/it.po new file mode 100644 index 000000000000..03c05cc49fe4 --- /dev/null +++ b/assets_management/i18n/it.po @@ -0,0 +1,3241 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * assets_management +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-06-26 05:37+0000\n" +"PO-Revision-Date: 2020-06-26 05:37+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.document_layout +msgid "
\n" +" TIN: " +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_body +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_body +msgid "\n" +" Totals\n" +" " +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_category_data +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_category_data +msgid "Asset Category: " +msgstr "Categoria: " + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_title +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_title +msgid "Asset: " +msgstr "Bene ammortizzabile: " + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_table_header +msgid "Code" +msgstr "Codice" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Curr. Year Dep. Fund" +msgstr "Fondo Amm.to anno corrente" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Customer Credit Notes" +msgstr "Note credito cliente" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Customer Invoices" +msgstr "Fatture cliente" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Dep. Amount" +msgstr "Valore ammortizzabile" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Dep. Percentage (%)" +msgstr "Amm.to (%)" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Depreciable Amount" +msgstr "Valore ammortizzabile" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Depreciation Mode" +msgstr "Metodo" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Depreciation Type" +msgstr "Natura" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Depreciation" +msgstr "Ammortamento" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_accounting_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_accounting_table_header +msgid "Document Date" +msgstr "Documento data" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_accounting_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_accounting_table_header +msgid "Document Nr" +msgstr "Documento Nr" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Gain / Loss" +msgstr "Plusvalenza / Minusvalenza" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "In Amount" +msgstr "Valore +" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Out Amount" +msgstr "Valore -" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_accounting_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_accounting_table_header +msgid "Partner" +msgstr "Partner" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Prev. Year Dep. Fund" +msgstr "Fondo Amm.to anno precedente" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Pro Rata Temporis" +msgstr "Pro Rata Temporis" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_table_header +msgid "Purchase Amount" +msgstr "Valore acquisto" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_table_header +msgid "Purchased as New / Used" +msgstr "Acquistato Nuovo / Usato" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_accounting_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_accounting_table_header +msgid "Ref" +msgstr "Ref" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Residual" +msgstr "Residuo da ammortizzare" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_depreciation_table_header +msgid "Starting From" +msgstr "Data inizio amm.to" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_table_header +msgid "Status" +msgstr "Stato" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_category_totals +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_category_totals +msgid "Totals for: " +msgstr "Totali per: " + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_totals_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_totals_header +msgid "Type" +msgstr "Tipo" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_accounting_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_accounting_table_header +msgid "VAT" +msgstr "P.IVA" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Vendor Bills" +msgstr "Fatture fornitore" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Vendor Credit Notes" +msgstr "Note credito fornitore" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_journal_asset_year_depreciation_table_header +#: model_terms:ir.ui.view,arch_db:assets_management.template_asset_previsional_asset_year_depreciation_table_header +msgid "Year" +msgstr "Anno" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__access_warning +msgid "Access warning" +msgstr "Avviso di accesso" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_account +msgid "Account" +msgstr "Conto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__asset_accounting_info_ids +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__asset_accounting_info_ids +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Accounting Info" +msgstr "Info contabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_needaction +msgid "Action Needed" +msgstr "Azione richiesta" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_ids +msgid "Activities" +msgstr "Attività" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_state +msgid "Activity State" +msgstr "Stato delle Attività" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:250 +#: code:addons/assets_management/report/asset_journal_xlsx.py:352 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:248 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:321 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__amount +#, python-format +msgid "Amount" +msgstr "Importo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_depreciable +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_depreciable +msgid "Amount Depreciable" +msgstr "Valore ammortizzabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_depreciable_updated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_depreciable_updated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_depreciable_updated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_depreciable_updated +msgid "Amount Depreciable Updated" +msgstr "Valore ammortizzabile aggiornato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_depreciated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_depreciated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_depreciated +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_depreciated +msgid "Amount Depreciated" +msgstr "Valore ammortizzato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_depreciation_fund_curr_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_depreciation_fund_curr_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_depreciation_fund_curr_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_depreciation_fund_curr_year +msgid "Amount Depreciation Fund Curr Year" +msgstr "F.do amm.to Anno Corrente" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_depreciation_fund_prev_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_depreciation_fund_prev_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_depreciation_fund_prev_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_depreciation_fund_prev_year +msgid "Amount Depreciation Fund Prev Year" +msgstr "F.do amm.to Anno Precedente" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_gain +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_gain +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_gain +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_gain +msgid "Amount Gain" +msgstr "Plusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_gain_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_gain_total +msgid "Amount Gain Total" +msgstr "Totale Plusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_historical +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_historical +msgid "Amount Historical" +msgstr "Valore Storico" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_in +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_in +msgid "Amount In" +msgstr "Valore +" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_in_detail +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_in_detail +msgid "Amount In Detail" +msgstr "Dettaglio Valore +" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_in_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_in_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_in_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_in_total +msgid "Amount In Total" +msgstr "Totale Valore +" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_loss +msgid "Amount Loss" +msgstr "Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_loss_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_loss_total +msgid "Amount Loss Total" +msgstr "Totale Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_out +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_out +msgid "Amount Out" +msgstr "Valore -" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_out_detail +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_out_detail +msgid "Amount Out Detail" +msgstr "Dettaglio Valore -" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_out_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_out_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_out_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_out_total +msgid "Amount Out Total" +msgstr "Totale Valore -" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__amount_residual +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__amount_residual +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__amount_residual +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__amount_residual +msgid "Amount Residual" +msgstr "Importo residuo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__application +msgid "Application by" +msgstr "Applica su" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:154 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:152 +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__asset_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__asset_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__asset_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__asset_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__asset_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_accounting_info_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#, python-format +msgid "Asset" +msgstr "Bene ammortizzabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__asset_account_id +msgid "Asset Account" +msgstr "Conto bene ammortizzabile" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_accounting_info +msgid "Asset Accounting Relations" +msgstr "Collegamenti contabili" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_category +msgid "Asset Category" +msgstr "Categorie beni ammortizzabili" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_category_depreciation_type +msgid "Asset Category - Depreciation Type" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_code +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_code +msgid "Asset Code" +msgstr "Codice" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_configuration +msgid "Asset Configuration" +msgstr "Configurazione" + +#. module: assets_management +#: selection:asset.accounting.info,relation_type:0 +msgid "Asset Creation" +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "Asset Depreciation" +msgstr "Ammortamento" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation_mode +msgid "Asset Depreciation Mode" +msgstr "Metodi Ammortamento" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation_mode_line +msgid "Asset Depreciation Mode Line" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation_type +msgid "Asset Depreciation Type" +msgstr "Natura Ammortamento" + +#. module: assets_management +#: selection:asset.accounting.info,relation_type:0 +msgid "Asset Dismissal" +msgstr "Dismissioni" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_wizard_asset_journal_report +#: model:ir.ui.menu,name:assets_management.menu_wizard_asset_journal_report +msgid "Asset Journal" +msgstr "Registro beni ammortizzabili" + +#. module: assets_management +#: model:ir.actions.client,name:assets_management.act_client_asset_journal_report +msgid "Asset Journal Report" +msgstr "Registro beni ammortizzabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_name +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Asset Name" +msgstr "Nome bene ammortizzabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__asset_order_fname +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__asset_order_fname +msgid "Asset Order Fname" +msgstr "" + +#. module: assets_management +#: selection:asset.accounting.info,relation_type:0 +msgid "Asset Partial Dismissal" +msgstr "Dismissione parziale" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_wizard_asset_previsional_report +#: model:ir.actions.client,name:assets_management.act_client_asset_previsional_report +#: model:ir.ui.menu,name:assets_management.menu_wizard_asset_previsional_report +msgid "Asset Previsional Report" +msgstr "Registro Previsionale" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_previsional_html +msgid "Asset Previsional Report HTML" +msgstr "Registro Previsionale HTML" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_previsional_pdf +msgid "Asset Previsional Report PDF" +msgstr "Registro Previsionale PDF" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_previsional_xlsx +msgid "Asset Previsional Report XLSX" +msgstr "Registro Previsionale XLSX" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__asset_order_fname +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__asset_order_fname +msgid "Asset Print Order" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_purchase_amount +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_purchase_amount +msgid "Asset Purchase Amount" +msgstr "Valore Acquisto" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_journal_html +msgid "Asset Report HTML" +msgstr "" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_journal_pdf +msgid "Asset Report PDF" +msgstr "Registro beni ammortizzabili - PDF" + +#. module: assets_management +#: model:ir.actions.report,name:assets_management.report_asset_journal_xlsx +msgid "Asset Report XLSX" +msgstr "Registro beni ammortizzabili - XLSX" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_reports +msgid "Asset Reports" +msgstr "Registro beni ammortizzabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_state +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_state +msgid "Asset State" +msgstr "Stato" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_tag +msgid "Asset Tags" +msgstr "Tag" + +#. module: assets_management +#: selection:asset.accounting.info,relation_type:0 +msgid "Asset Update" +msgstr "Aggiornamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__asset_used +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__asset_used +msgid "Asset Used" +msgstr "Bene usato" + +#. module: assets_management +#: model:res.groups,name:assets_management.group_asset_user +msgid "Asset Users" +msgstr "Utenti" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__depreciation_id +msgid "Asset depreciation" +msgstr "Ammortamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__depreciation_type_id +msgid "Asset depreciation type" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:489 +#: code:addons/assets_management/models/asset_depreciation.py:496 +#: code:addons/assets_management/models/asset_depreciation.py:507 +#, python-format +msgid "Asset dismissal: " +msgstr "Dismissione bene: " + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:389 +#, python-format +msgid "Asset: " +msgstr "Bene ammortizzabile" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset +#: model:ir.model,name:assets_management.model_asset_asset +#: model:ir.model.fields,field_description:assets_management.field_account_invoice__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_account_invoice_line__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move_line__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__asset_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__asset_ids +#: model:ir.ui.menu,name:assets_management.menu_asset +#: model:ir.ui.menu,name:assets_management.menu_asset_asset +#: model_terms:ir.ui.view,arch_db:assets_management.invoice_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.invoice_supplier_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_invoice_line_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_move_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_move_line_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "Assets" +msgstr "Beni ammortizzabili" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_accounting_info +#: model:ir.model.fields,field_description:assets_management.field_account_invoice__asset_accounting_info_ids +#: model:ir.model.fields,field_description:assets_management.field_account_invoice_line__asset_accounting_info_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move__asset_accounting_info_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move_line__asset_accounting_info_ids +#: model:ir.ui.menu,name:assets_management.menu_asset_accounting_info +msgid "Assets Accounting Info" +msgstr "Info contabili" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_depreciation_mode +msgid "Assets Depreciation Mode" +msgstr "Metodi ammortamento" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_depreciation_type +msgid "Assets Depreciation Type" +msgstr "Natura ammortamento" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation +msgid "Assets Depreciations" +msgstr "Ammortamenti" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:301 +#, python-format +msgid "Assets Depreciations " +msgstr "Ammortamenti " + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation_line +msgid "Assets Depreciations Lines" +msgstr "Linee ammortamento" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_management +msgid "Assets Management" +msgstr "Gestione" + +#. module: assets_management +#: code:addons/assets_management/report/asset_previsional.py:332 +#, python-format +msgid "Assets Previsional Depreciations " +msgstr "Ammortamenti previsionali " + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_search_view +msgid "Assets asset" +msgstr "Beni ammortizzabili" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_category +msgid "Assets category" +msgstr "Categorie beni ammortizzabili" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_tag +msgid "Assets tag" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:199 +#, python-format +msgid "At least one invoice line is mandatory to create a new asset!" +msgstr "Indicare almeno una riga di fattura per creare un nuovo cespite" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:229 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:273 +#, python-format +msgid "At least one invoice line is mandatory to dismiss an asset!" +msgstr "Indicare almeno una riga di fattura per dismettere un cespite" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:310 +#, python-format +msgid "At least one invoice line is mandatory to update an asset!" +msgstr "Indicare almeno una riga di fattura per aggiornare un cespite" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:193 +#, python-format +msgid "At least one move line is mandatory to create a new asset!" +msgstr "Indicare almeno una riga di fattura per creare un nuovo cespite" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:225 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:269 +#, python-format +msgid "At least one move line is mandatory to dismiss an asset!" +msgstr "Indicare almeno una riga di fattura per dismettere un cespite" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:306 +#, python-format +msgid "At least one move line is mandatory to update an asset!" +msgstr "Indicare almeno una riga di fattura per aggiornare un cespite" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_attachment_count +msgid "Attachment Count" +msgstr "Numero allegati" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +msgid "Attention! You cannot create an asset from accounting moves related to sale documents." +msgstr "Attenzione! Non è possibile creare un bene ammortizzabile da una registrazione contabile collegata ad un documento di vendita" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Attention! You cannot create an asset from customer invoices or vendor bills refunds." +msgstr "Attenzione! Non è possibile creare un bene ammortizzabile da una fattura cliente o da una nota credito fornitore" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +msgid "Attention! You cannot dismiss an asset from accounting moves related to purchase documents." +msgstr "Attenzione! Non è possibile dismettere un bene da registrazioni contabili collegate a documenti di acquisto" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Attention! You cannot dismiss an asset from vendor bills or customer refunds." +msgstr "Attenzione! Non è possibile dismettere un bene dalle fatture fornitori o da note credito clienti" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__balance +msgid "Balance" +msgstr "Saldo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__base +msgid "Base" +msgstr "Imponibile" + +#. module: assets_management +#: code:addons/assets_management/models/asset_category.py:33 +#, python-format +msgid "Before creating new categories, please complete the assets' configuration for both depreciation types and modes." +msgstr "Prima di creare nuove categorie, completare la configurazione per i metodi e la natura di ammortamento" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_generate_depreciation_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Cancel" +msgstr "Annulla" + +#. module: assets_management +#: code:addons/assets_management/models/asset.py:193 +#, python-format +msgid "Cannot change category for an asset that's already been depreciated." +msgstr "Non puoi cancelare la categoria: è già presente in qualche ammortamento" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:531 +#, python-format +msgid "Cannot compute pro rata temporis for unknown date." +msgstr "Non è possibile calcolare il pro rata temporis se non viene indicata la data" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:618 +#, python-format +msgid "Cannot create a depreciation line without a date" +msgstr "Non puoi creare ammortamenti senza data" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:463 +#, python-format +msgid "Cannot create account move lines for lines of type `Historical`" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:469 +#, python-format +msgid "Cannot create account move lines for lines of type `In`" +msgstr "Non è possibile creare registrazioni per le linee di tipo IN" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:492 +#, python-format +msgid "Cannot create account move lines for lines of type `Out`" +msgstr "Non è possibile creare registrazioni per le linee di tipo OUT" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:397 +#, python-format +msgid "Cannot create account move lines: no method is specified." +msgstr "Non è possibile creare registrazioni: nessun metodo specificato." + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:286 +#, python-format +msgid "Cannot create any depreciation according to current settings." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:205 +#, python-format +msgid "Cannot create asset if lines come from different invoices!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:199 +#, python-format +msgid "Cannot create asset if move lines come from different account moves!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/account_account.py:26 +#, python-format +msgid "Cannot delete accounts while they're still used by asset categories." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_category.py:133 +#, python-format +msgid "Cannot delete categories while they're still linked to an asset." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_mode.py:62 +#, python-format +msgid "Cannot delete depreciation modes while they're still linked to categories." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_mode.py:69 +#, python-format +msgid "Cannot delete depreciation modes while they're still linked to depreciations." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_type.py:46 +#, python-format +msgid "Cannot delete depreciation types while they're still used by categories." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:193 +#, python-format +msgid "Cannot delete depreciations if there is any depreciation line linked to it." +msgstr "Non è possibile elimare ammortamenti se ci sono righe di amm.to collegate." + +#. module: assets_management +#: code:addons/assets_management/models/account_journal.py:18 +#, python-format +msgid "Cannot delete journals while they're still used by asset categories." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:380 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:466 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:379 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:468 +#, python-format +msgid "Cannot dismiss an asset earlier than the last depreciation date.\n" +"(Dismiss date: {}, last depreciation date: {})." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:388 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:477 +#, python-format +msgid "Cannot dismiss asset from non-sale type moves!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:389 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:475 +#, python-format +msgid "Cannot dismiss asset from supplier bills or customer refunds!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:235 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:279 +#, python-format +msgid "Cannot dismiss asset if lines come from different invoices!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:231 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:275 +#, python-format +msgid "Cannot dismiss asset if move lines come from different account moves!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:573 +#, python-format +msgid "Cannot get pro rata temporis multiplier for mode `{}`" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:577 +#, python-format +msgid "Cannot get pro rata temporis multiplier for unspecified mode" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line_type.py:48 +#, python-format +msgid "Cannot remove type {}: there is some depreciation line linked to it." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:305 +#, python-format +msgid "Cannot update the following assets which contain newer depreciations for the chosen types:\n" +"{}" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:321 +#, python-format +msgid "Cannot update the following assets which contain posted depreciation for the chosen date and types:\n" +"{}" +msgstr "" + +#. module: assets_management +#: selection:asset.depreciation.line,move_type:0 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_gain +msgid "Capital Gain" +msgstr "Plusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__gain_account_id +msgid "Capital Gain Account" +msgstr "Conto Plusvalenza" + +#. module: assets_management +#: selection:asset.depreciation.line,move_type:0 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_loss +msgid "Capital Loss" +msgstr "Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__loss_account_id +msgid "Capital Loss Account" +msgstr "Conto Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__category_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__category_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__category_ids +#: model:ir.ui.menu,name:assets_management.menu_asset_category +msgid "Categories" +msgstr "Categorie" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:142 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:140 +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__category_id +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__category_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__category_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__category_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__category_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__category_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__category_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__category_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_search_view +#, python-format +msgid "Category" +msgstr "Categoria" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__category_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__category_name +msgid "Category Name" +msgstr "Nome categoria" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Choose Your Asset" +msgstr "Scegli il bene ammortizzabile" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:158 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:156 +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__code +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__code +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__code +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__code +#, python-format +msgid "Code" +msgstr "Codice" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_depreciation__base_coeff +msgid "Coeff to compute amount depreciable from purchase amount" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_category_depreciation_type__base_coeff +msgid "Coeff to compute depreciable amount from purchase amount" +msgstr "" + +#. module: assets_management +#: selection:asset.depreciation.mode.line,application:0 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__coefficient +msgid "Coefficient" +msgstr "Coefficiente" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__comment +msgid "Comment" +msgstr "Commento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_category__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__company_id +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__company_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__company_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__company_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__company_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__company_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__company_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__company_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__company_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_search_view +msgid "Company" +msgstr "Azienda" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:173 +#, python-format +msgid "Could not determine how to link invoice lines to asset in mode `{}`." +msgstr "Non è possibile " + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:167 +#, python-format +msgid "Could not determine how to link move lines to asset in mode `{}`." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:573 +#, python-format +msgid "Could not retrieve depreciation line type from invoice `{}` (type `{}`)." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:581 +#, python-format +msgid "Could not retrieve depreciation line type from move `{}` (type `{}`)." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:594 +#, python-format +msgid "Could not update `{}`: not enough residual amount to write off invoice `{}`.\n" +"(Amount to write off: {}; residual amount: {}.)\n" +"Maybe you should try to dismiss this asset instead?" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:604 +#, python-format +msgid "Could not update `{}`: not enough residual amount to write off move `{}`.\n" +"(Amount to write off: {}; residual amount: {}.)\n" +"Maybe you should try to dismiss this asset instead?" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:618 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:628 +#, python-format +msgid "Could not update `{}`: not enough residual amount to write off.\n" +"(Amount to write off: {}; residual amount: {}.)\n" +"Maybe you should try to dismiss this asset instead?" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:261 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:257 +#, python-format +msgid "Couldn't determine which action should be done." +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Create Asset" +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Create Asset and Show" +msgstr "" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,management_type:0 +#: selection:wizard.invoice.manage.asset,management_type:0 +msgid "Create New" +msgstr "Crea Nuovo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_category__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__create_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__create_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__create_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__create_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__create_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__create_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__create_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_category__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__create_date +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__create_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__create_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__create_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__create_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__create_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__create_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:275 +#: code:addons/assets_management/report/asset_journal_xlsx.py:377 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:273 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:346 +#, python-format +msgid "Curr. Year Dep. Fund" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__currency_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__currency_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__currency_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__currency_id +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__currency_id +msgid "Currency" +msgstr "Valuta" + +#. module: assets_management +#: code:addons/assets_management/models/asset.py:222 +#, python-format +msgid "Current asset has already been depreciated. Changes upon its purchase value will not be automatically reflected upon depreciation lines, which will have to be updated manually." +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__customer_id +msgid "Customer" +msgstr "Cliente" + +#. module: assets_management +#: selection:wizard.invoice.manage.asset,invoice_type:0 +msgid "Customer Credit Note" +msgstr "Note credito cliente" + +#. module: assets_management +#: selection:wizard.invoice.manage.asset,invoice_type:0 +msgid "Customer Invoice" +msgstr "Fatture cliente" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__access_url +msgid "Customer Portal URL" +msgstr "URL del portale clienti" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__date +msgid "Date" +msgstr "Data" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_date_range +msgid "Date Range" +msgstr "Intervallo data" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__date_start +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__date_start +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__date_start +msgid "Date Start" +msgstr "Data inizio" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__default +msgid "Default Mode" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_category__print_by_default +#: model:ir.model.fields,help:assets_management.field_asset_depreciation_type__print_by_default +msgid "Defines whether a category should be added by default when printing assets' reports." +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__dep_amount_depreciable +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__dep_amount_depreciable +msgid "Dep Amount Depreciable" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__base_coeff +msgid "Dep Base Coeff" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__dep_date_start +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__dep_date_start +msgid "Dep Date Start" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__dep_line_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__dep_line_ids +msgid "Dep Line" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__mode_id +msgid "Dep Mode" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__dep_percentage +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__dep_percentage +msgid "Dep Percentage" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__dep_pro_rata_temporis +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__dep_pro_rata_temporis +msgid "Dep Pro Rata Temporis" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__depreciation_nr +msgid "Dep. Num" +msgstr "Amm.to Nr" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:229 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:227 +#, python-format +msgid "Dep. Percentage (%)" +msgstr "Amm.to %" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:220 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:218 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_depreciable +#, python-format +msgid "Depreciable Amount" +msgstr "Valore ammortizzabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__base_coeff +msgid "Depreciable Base Coeff" +msgstr "Coeff. base Amm.to" + +#. module: assets_management +#: selection:asset.asset,state:0 +#: selection:asset.depreciation,state:0 +msgid "Depreciated" +msgstr "Ammortizzato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_depreciated +msgid "Depreciated Amount" +msgstr "Valore ammortizzato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__depreciated_fund_amount +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__depreciated_fund_amount +msgid "Depreciated Fund Amount" +msgstr "Valore F.do Amm.to" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:270 +#: code:addons/assets_management/report/asset_journal_xlsx.py:372 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:268 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:341 +#: selection:asset.depreciation.line,move_type:0 +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__depreciation_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__depreciation_id +#, python-format +msgid "Depreciation" +msgstr "Ammortamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__percentage +msgid "Depreciation %" +msgstr "Ammortamento %" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__percentage +msgid "Depreciation (%)" +msgstr "Ammortamento (%)" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__depreciation_account_id +msgid "Depreciation Account" +msgstr "Conto ammortamento" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_generate_depreciation_form_view +msgid "Depreciation Data" +msgstr "Dati ammortamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__date_dep +msgid "Depreciation Date" +msgstr "Data Ammortamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__dep_line_id +msgid "Depreciation Line" +msgstr "Riga ammortamento" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_depreciation_line_type +#: model:ir.ui.menu,name:assets_management.menu_asset_depreciation_line_type +msgid "Depreciation Line Amount Types" +msgstr "Tipi operazione" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_asset_depreciation_line_type +msgid "Depreciation Line Type" +msgstr "Tipo riga amm.to" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_asset_dep_line +#: model:ir.model.fields,field_description:assets_management.field_account_invoice__dep_line_ids +#: model:ir.model.fields,field_description:assets_management.field_account_invoice_line__dep_line_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move__dep_line_ids +#: model:ir.model.fields,field_description:assets_management.field_account_move_line__dep_line_ids +#: model:ir.ui.menu,name:assets_management.menu_asset_dep_line +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.view_asset_depreciation_form +#: model_terms:ir.ui.view,arch_db:assets_management.view_invoice_line_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_move_line_form_inherit +msgid "Depreciation Lines" +msgstr "Righe Ammortamento" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:216 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:214 +#, python-format +msgid "Depreciation Mode" +msgstr "Metodi ammortamento" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_depreciation_mode +msgid "Depreciation Modes" +msgstr "Metodi ammortamento" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:212 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:210 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__type_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__depreciation_line_type_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#, python-format +msgid "Depreciation Type" +msgstr "Natura ammortamento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__type_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__depreciation_type_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__type_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__type_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__type_ids +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__depreciation_type_ids +#: model:ir.ui.menu,name:assets_management.menu_asset_depreciation_type +msgid "Depreciation Types" +msgstr "Natura ammortamento" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:200 +#, python-format +msgid "Depreciation number can't be a negative number." +msgstr "Nr di ammortamento non può essere negativo." + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__depreciation_ids +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Depreciations" +msgstr "Ammortamenti" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:432 +#, python-format +msgid "Depreciations cannot start before {}." +msgstr "Gli Amm.ti non possono iniziare prima {}." + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +#: selection:wizard.account.move.manage.asset,management_type:0 +#: selection:wizard.invoice.manage.asset,management_type:0 +msgid "Dismiss Asset" +msgstr "Dismetti bene ammortizzabile" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Dismiss Asset and Show" +msgstr "Dismetti bene ammortizzabile e Mostra" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__dismiss_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__dismiss_date +msgid "Dismiss Date" +msgstr "Data dismissione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__dismiss_move_id +msgid "Dismiss Move" +msgstr "Registrazione contabile dismissione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_category__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__display_name +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_journal_xlsx__display_name +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_previsional_xlsx__display_name +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__display_name +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__display_name +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__display_name +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__display_name +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:196 +#: code:addons/assets_management/report/asset_journal_xlsx.py:328 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:194 +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__document_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__document_date +#, python-format +msgid "Document Date" +msgstr "Documento Data" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:192 +#: code:addons/assets_management/report/asset_journal_xlsx.py:324 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:190 +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__document_nr +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__document_nr +#, python-format +msgid "Document Nr" +msgstr "Documento Nr" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:256 +#, python-format +msgid "Every invoice line must share the same account!" +msgstr "Ogni riga di fattura deve lo stesso conto!" + +#. module: assets_management +#: code:addons/assets_management/models/account_invoice.py:100 +#: code:addons/assets_management/models/account_move.py:100 +#, python-format +msgid "Every line is already linked to an asset." +msgstr "Ogni riga è già collegata ad un cespite." + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:252 +#, python-format +msgid "Every move line must share the same account!" +msgstr "Ogni riga di registrazione deve avere lo stesso conto!" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +msgid "Export Journal Report" +msgstr "Export Excel" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "Export Previsional Report" +msgstr "Export Excel" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:246 +#, python-format +msgid "Fields `Force All Dep. Num` and `Force First Dep. Num` cannot be both active." +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_generate_depreciation_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "Filters" +msgstr "Filtri" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__first_dep_nr +msgid "First Dep. Num" +msgstr "Primo Amm.to Nr" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__fiscal_year_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__fiscal_year_id +msgid "Fiscal Year" +msgstr "Anno fiscale" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_channel_ids +msgid "Followers (Channels)" +msgstr "Followers (Canali)" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_partner_ids +msgid "Followers (Partners)" +msgstr "Followers (Partner)" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:171 +#, python-format +msgid "Following lines are linked to posted account moves, and cannot be deleted:\n" +"" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:203 +#, python-format +msgid "Following lines are linked to posted account moves, and cannot be deleted:\n" +"{}" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__force_all_dep_nr +msgid "Force All Dep. Num" +msgstr "Forza TUTTI Nr amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__force_dep_nr +msgid "Force Dep. Num" +msgstr "Primo Nr amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__force_first_dep_nr +msgid "Force First Dep. Num" +msgstr "Forza PRIMO Nr amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__from_nr +msgid "From Nr" +msgstr "Dal Nr" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:421 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:438 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:612 +#, python-format +msgid "From invoice(s) " +msgstr "Dalla fattura/e " + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:423 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:440 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:622 +#, python-format +msgid "From move(s) " +msgstr "Dalla registrazione/i " + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__fund_account_id +msgid "Fund Account" +msgstr "Conto fondo bene ammortizzabile" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "Gain" +msgstr "Plusvalenza" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:280 +#: code:addons/assets_management/report/asset_journal_xlsx.py:382 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:278 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:351 +#, python-format +msgid "Gain / Loss" +msgstr "Plusvalenza / Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__gain_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__gain_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__gain_loss +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__gain_loss +msgid "Gain Loss" +msgstr "Plusvalenza / Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__gain_loss_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__gain_loss_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__gain_loss_total +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__gain_loss_total +msgid "Gain Loss Total" +msgstr "Totale Plusvalenza / Minusvalenza" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +msgid "General Info" +msgstr "Info generali" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:278 +#: code:addons/assets_management/report/asset_previsional.py:311 +#, python-format +msgid "General Total" +msgstr "Totale generale" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_generate_depreciation_form_view +msgid "Generate" +msgstr "Genera" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_wizard_asset_generate_depreciation +#: model:ir.ui.menu,name:assets_management.menu_wizard_asset_generate_depreciation +msgid "Generate Depreciations" +msgstr "Genera ammortamenti" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.view_asset_depreciation_form +msgid "Generate Move" +msgstr "Genera registrazione" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Generate depreciations" +msgstr "Genera ammortamenti" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_accounting_info_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_search_view +msgid "Group By" +msgstr "Raggruppa per" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__has_amount_detail +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__has_amount_detail +msgid "Has Amount Detail" +msgstr "Con dettaglio valore" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__hidden +msgid "Hidden" +msgstr "Nascosto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_account_invoice__hide_link_asset_button +#: model:ir.model.fields,field_description:assets_management.field_account_move__hide_link_asset_button +msgid "Hide Asset Button" +msgstr "Nascondo pulsante Bene Amm.le" + +#. module: assets_management +#: selection:asset.depreciation.line,move_type:0 +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "Historical" +msgstr "Storico" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_historical +msgid "Historical Amount" +msgstr "Valore storico" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__id +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__id +#: model:ir.model.fields,field_description:assets_management.field_asset_category__id +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__id +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__id +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_journal_xlsx__id +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_previsional_xlsx__id +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__id +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__id +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__id +msgid "ID" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_unread +msgid "If checked new messages require your attention." +msgstr "Se selezionato, nuovi messaggi richiedono attenzione." + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Se selezionato, nuovi messaggi richiedono attenzione." + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "Se selezionato, alcuni messaggi presentano un errore di consegna. " + +#. module: assets_management +#: selection:asset.depreciation.line,move_type:0 +#: selection:asset.depreciation.line.type,type:0 +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "In" +msgstr "Rettifica positiva" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:255 +#: code:addons/assets_management/report/asset_journal_xlsx.py:357 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:253 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:326 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_in +#, python-format +msgid "In Amount" +msgstr "Rettifica positiva" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:299 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:297 +#, python-format +msgid "In Amount - Detail" +msgstr "Rettifica positiva - Dettaglio" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_tree_view +#: model_terms:ir.ui.view,arch_db:assets_management.view_asset_depreciation_form +#: model_terms:ir.ui.view,arch_db:assets_management.view_invoice_line_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_move_line_form_inherit +msgid "In/Out Amount Type" +msgstr "+/- Tipo operazione" + +#. module: assets_management +#: code:addons/assets_management/models/asset_accounting_info.py:163 +#, python-format +msgid "Incoherent asset data." +msgstr "Dati cespite incoerenti" + +#. module: assets_management +#: code:addons/assets_management/models/asset_accounting_info.py:152 +#, python-format +msgid "Incoherent company data." +msgstr "Dati azienda incoerenti" + +#. module: assets_management +#: code:addons/assets_management/models/asset_accounting_info.py:171 +#, python-format +msgid "Incoherent invoice data." +msgstr "Dati fattura incoerenti" + +#. module: assets_management +#: code:addons/assets_management/models/asset_accounting_info.py:179 +#, python-format +msgid "Incoherent move data." +msgstr "Dati registrazione incoerenti" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:221 +#, python-format +msgid "Invalid search operator!" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_invoice +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__invoice_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_accounting_info_search_view +msgid "Invoice" +msgstr "Fattura" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_invoice_line +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__invoice_line_id +msgid "Invoice Line" +msgstr "Riga fattura" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__invoice_line_ids +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Invoice Lines" +msgstr "Righe fattura" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__is_invoice_state_ok +msgid "Invoice State" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__invoice_type +msgid "Invoice Type" +msgstr "Tipo fattura" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Invoice lines" +msgstr "Righe fattura" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__invoice_ids +msgid "Invoices" +msgstr "Fatture" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_is_follower +msgid "Is Follower" +msgstr "È Follower" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_journal +#: model:ir.model.fields,field_description:assets_management.field_asset_category__journal_id +msgid "Journal" +msgstr "Registro" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_move +msgid "Journal Entries" +msgstr "Registrazioni contabili" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_account_move_line +msgid "Journal Item" +msgstr "Movimento contabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__last_depreciation_date +msgid "Last Dep." +msgstr "Ultimo amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_asset____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_category____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type____last_update +#: model:ir.model.fields,field_description:assets_management.field_asset_tag____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_journal_xlsx____last_update +#: model:ir.model.fields,field_description:assets_management.field_report_assets_management_report_asset_previsional_xlsx____last_update +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset____last_update +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation____last_update +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report____last_update +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report____last_update +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_category__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__write_uid +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__write_uid +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__write_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__write_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__write_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__write_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__write_uid +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_category__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__write_date +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__write_date +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__write_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__write_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_generate_depreciation__write_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__write_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__write_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__line_ids +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__line_ids +msgid "Lines" +msgstr "Righe" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.invoice_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.invoice_supplier_form_inherit +#: model_terms:ir.ui.view,arch_db:assets_management.view_move_form_inherit +msgid "Link to Asset" +msgstr "Beni ammortizzabili" + +#. module: assets_management +#: model:ir.actions.act_window,name:assets_management.action_wizard_account_move_manage_asset +#: model:ir.actions.act_window,name:assets_management.action_wizard_invoice_manage_asset +msgid "Link to Assets" +msgstr "Beni ammortizzabili" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "Loss" +msgstr "Minusvalenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_main_attachment_id +msgid "Main Attachment" +msgstr "Allegato principale" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__management_type +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__management_type +msgid "Management Type" +msgstr "Management Type" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_has_error +msgid "Message Delivery error" +msgstr "Errore di consegna messaggio" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_ids +msgid "Messages" +msgstr "Messaggi" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,move_type:0 +msgid "Miscellaneous" +msgstr "Varie" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__mode_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__mode_id +msgid "Mode" +msgstr "Metodo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__mode_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__mode_name +msgid "Mode Name" +msgstr "Metodo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__move_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__move_id +#: model_terms:ir.ui.view,arch_db:assets_management.asset_accounting_info_search_view +msgid "Move" +msgstr "Registrazione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__move_line_id +msgid "Move Line" +msgstr "Riga movimento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__move_line_ids +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +msgid "Move Lines" +msgstr "Righe di Movimento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__is_move_state_ok +msgid "Move State" +msgstr "Stato registrazione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__move_type +msgid "Move Type" +msgstr "Tipo movimento" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__move_ids +msgid "Moves" +msgstr "Registrazioni contabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__name +#: model:ir.model.fields,field_description:assets_management.field_asset_category__name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__name +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__name +#: model:ir.model.fields,field_description:assets_management.field_asset_tag__name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__name +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__name +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__name +msgid "Name" +msgstr "Nome" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__needs_previsional +msgid "Needs Previsional" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:465 +#: code:addons/assets_management/report/asset_previsional.py:500 +#, python-format +msgid "New" +msgstr "Nuovo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Scadenza prossima attività" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_summary +msgid "Next Activity Summary" +msgstr "Riepilogo prossima attività" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_type_id +msgid "Next Activity Type" +msgstr "Tipo Prossima Attività" + +#. module: assets_management +#: code:addons/assets_management/models/date_range.py:33 +#, python-format +msgid "No fiscal year defined for date " +msgstr "Nessun anno fiscale definito per questa data " + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:541 +#, python-format +msgid "No fiscal year defined for date {}" +msgstr "Nessun anno fiscale definito per la data {}" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:129 +#: code:addons/assets_management/report/asset_previsional.py:134 +#, python-format +msgid "No report has been defined for type `{}`." +msgstr "Nessun report è stato definito per il tipo `{}`." + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:134 +#: code:addons/assets_management/report/asset_previsional.py:139 +#, python-format +msgid "No report type has been declared for current print." +msgstr "" + +#. module: assets_management +#: selection:asset.asset,state:0 +#: selection:asset.depreciation,state:0 +msgid "Non Depreciated" +msgstr "Non ammortizzato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_needaction_counter +msgid "Number of Actions" +msgstr "Numero di Azioni" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_has_error_counter +msgid "Number of error" +msgstr "Numero di errori" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "Numero di messaggi che richiedono un'azione" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Numero di messaggi con errore di consegna" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__message_unread_counter +msgid "Number of unread messages" +msgstr "Numero di messaggi non letti" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Only confirmed invoices can be used to create, update or dismiss assets!
\n" +" Please select only open or paid invoices." +msgstr "Solo con le fatture validate è possibile creare, aggiornare o dismettere un bene ammortizzabile!
\n" +" Scegli solo le fatture aperte o pagate." + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +msgid "Only posted moves can be used to create, update or dismiss assets!
\n" +" Please select posted moves only." +msgstr "Solo con le registrazioni contabili emesse è possibile creare, aggiornare o dismettere un bene ammortizzabile!
\n" +" Scegli solo le registrazioni emesse." + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "Options" +msgstr "Opzioni" + +#. module: assets_management +#: selection:asset.depreciation.line,move_type:0 +#: selection:asset.depreciation.line.type,type:0 +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_search_view +msgid "Out" +msgstr "Rettifica negativa" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:260 +#: code:addons/assets_management/report/asset_journal_xlsx.py:362 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:258 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:331 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_out +#, python-format +msgid "Out Amount" +msgstr "Rettifica negativa" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:303 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:301 +#, python-format +msgid "Out Amount - Detail" +msgstr "Rettifica negativa - Dettaglio" + +#. module: assets_management +#: selection:asset.asset,activity_state:0 +msgid "Overdue" +msgstr "" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,management_type:0 +#: selection:wizard.invoice.manage.asset,management_type:0 +msgid "Partial Dismiss" +msgstr "Dismissione Parziale" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Partial Dismiss Asset" +msgstr "Dismissione Parziale" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Partial Dismiss Asset and Show" +msgstr "Dismetti Cespite e Mostra" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__partial_dismissal +msgid "Partial Dismissal" +msgstr "Dismissione Parziale" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:494 +#, python-format +msgid "Partial dismissal from invoice(s) {}" +msgstr "Dismissione Parziale dalla fattura/e {}" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:495 +#, python-format +msgid "Partial dismissal from move(s) {}" +msgstr "Dismissione Parziale dalla registrazione/i {}" + +#. module: assets_management +#: selection:asset.asset,state:0 +#: selection:asset.depreciation,state:0 +msgid "Partially Depreciated" +msgstr "Parzialmente ammortizzato" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:184 +#: code:addons/assets_management/report/asset_journal_xlsx.py:316 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:182 +#, python-format +msgid "Partner" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__partner_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__partner_name +msgid "Partner Name" +msgstr "Nome partner" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__partner_ref +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__partner_ref +msgid "Partner Ref" +msgstr "Riferimento partner" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__partner_vat +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__partner_vat +msgid "Partner Vat" +msgstr "P.IVA partner" + +#. module: assets_management +#: selection:asset.depreciation.mode.line,application:0 +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__percentage +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__percentage +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__percentage +msgid "Percentage" +msgstr "Percentuale" + +#. module: assets_management +#: selection:asset.asset,activity_state:0 +msgid "Planned" +msgstr "Pianificato" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:224 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:268 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:300 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:220 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:264 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:296 +#, python-format +msgid "Please choose an asset before continuing!" +msgstr "Scegli un Cespite prima di continuare!" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:305 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:301 +#, python-format +msgid "Please choose at least one depreciation type!" +msgstr "Scegli almeno una riga di tipo ammortamento" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Please select only invoices of the same type!
\n" +" Choose one of the following invoices type:" +msgstr "Scegli solo le fatture dello stesso tipo!
\n" +" Scegli i seguenti tipi di fatture:" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__access_url +msgid "Portal Access URL" +msgstr "URL di accesso al portale" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:265 +#: code:addons/assets_management/report/asset_journal_xlsx.py:367 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:263 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:336 +#, python-format +msgid "Prev. Year Dep. Fund" +msgstr "Fondo amm.to anno precedente" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__previsional_line_ids +msgid "Previsional Line" +msgstr "Riga previsionale" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__print_by_default +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__print_by_default +msgid "Print By Default" +msgstr "Stampa su registro beni ammortizzabili" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +msgid "Print Journal Report" +msgstr "Stampa PDF" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "Print Previsional Report" +msgstr "Stampa PDF" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:233 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:231 +#, python-format +msgid "Pro Rata Temporis" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__pro_rata_temporis +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__pro_rata_temporis +msgid "Pro-rata Temporis" +msgstr "" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,move_type:0 +msgid "Purchase" +msgstr "Acquisto" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:162 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:160 +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__asset_purchase_amount +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__asset_purchase_amount +#, python-format +msgid "Purchase Amount" +msgstr "Valore acquisto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__purchase_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__purchase_date +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__purchase_date +#: model_terms:ir.ui.view,arch_db:assets_management.asset_search_view +msgid "Purchase Date" +msgstr "Data acquisto" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Purchase Info" +msgstr "Informazioni acquisto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__purchase_invoice_id +msgid "Purchase Invoice" +msgstr "Fattura acquisto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__purchase_move_id +msgid "Purchase Move" +msgstr "Registrazione acquisto" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__purchase_amount +msgid "Purchase Value" +msgstr "Valore acquisto" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:167 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:165 +#, python-format +msgid "Purchased as New / Used" +msgstr "Acquistato Nuovo / Usato" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.view_asset_depreciation_form +msgid "Regenerate Move" +msgstr "Rigenera registrazione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_accounting_info__relation_type +msgid "Relation Type" +msgstr "Tipo relazione" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Remove" +msgstr "Rimuovi" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.view_asset_depreciation_form +msgid "Remove Move" +msgstr "Rimuovi registrazione" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__report_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__report_id +msgid "Report" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__report_accounting_doc_ids +msgid "Report Accounting Doc" +msgstr "Report documenti contabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__report_asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__report_asset_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__report_asset_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__report_asset_id +msgid "Report Asset" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_category_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__report_category_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__report_category_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_category_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__report_category_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__report_category_id +msgid "Report Category" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_depreciation_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__report_depreciation_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__report_depreciation_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_depreciation_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__report_depreciation_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__report_depreciation_id +msgid "Report Depreciation" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_depreciation_line_year_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_depreciation_line_year_ids +msgid "Report Depreciation Line Year" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__report_depreciation_year_line_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__report_depreciation_year_line_ids +msgid "Report Depreciation Year Line" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_footer_year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_footer_year +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__report_footer_year +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__report_footer_year +msgid "Report Footer Year" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_name +msgid "Report Name" +msgstr "Nome del report" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__report_purchase_doc_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__report_purchase_doc_id +msgid "Report Purchase Doc" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_asset__report_sale_doc_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_asset__report_sale_doc_id +msgid "Report Sale Doc" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__report_total_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_category__report_total_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__report_total_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_category__report_total_ids +msgid "Report Total" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__requires_account_move +msgid "Required Account Move" +msgstr "Genera registrazioni contabili" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__requires_account_move +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_type__requires_account_move +msgid "Requires Account Move" +msgstr "Richiede registrazione contabile" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__requires_depreciation_nr +msgid "Requires Dep Num" +msgstr "Richiede Nr Amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__res_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__res_id +msgid "Res" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__res_model +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__res_model +msgid "Res Model" +msgstr "Modello res" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:285 +#: code:addons/assets_management/report/asset_journal_xlsx.py:387 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:283 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:356 +#, python-format +msgid "Residual" +msgstr "Residuo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_residual +msgid "Residual Amount" +msgstr "Importo residuo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__activity_user_id +msgid "Responsible User" +msgstr "Utente Responsabile" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,move_type:0 +msgid "Sale" +msgstr "Vendita" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__sale_date +msgid "Sale Date" +msgstr "Data vendita" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "Sale Info" +msgstr "Informazioni vendita" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__sale_invoice_id +msgid "Sale Invoice" +msgstr "Fattura vendita" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__sale_move_id +msgid "Sale Move" +msgstr "Registrazione contabile vendita" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__sale_amount +msgid "Sale Value" +msgstr "Valore vendita" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__access_token +msgid "Security Token" +msgstr "Token di sicurezza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_accounting_doc__sequence +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__sequence +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_accounting_doc__sequence +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__sequence +msgid "Sequence" +msgstr "Sequenza" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__show_category_totals +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__show_category_totals +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__show_category_totals +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__show_category_totals +msgid "Show Category Totals" +msgstr "Mostra totali categoria" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__show_totals +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__show_totals +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__show_totals +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__show_totals +msgid "Show Totals" +msgstr "Mostra totali" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__sold +msgid "Sold" +msgstr "Venduto" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:225 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:223 +#, python-format +msgid "Starting From" +msgstr "Data inzio amm.to" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__state +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__state +msgid "State" +msgstr "Stato" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:171 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:169 +#, python-format +msgid "Status" +msgstr "Stato" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__activity_state +msgid "Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "Stato basato sulle attività:\n" +"In ritardo: la data pianificata è scaduta\n" +"Oggi: la data dell'attività è oggi\n" +"Pianificata: attività future." + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__supplier_id +msgid "Supplier" +msgstr "Fornitore" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:200 +#: code:addons/assets_management/report/asset_journal_xlsx.py:332 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:198 +#, python-format +msgid "Supplier Ref" +msgstr "Rif. documento fornitore" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__supplier_ref +msgid "Supplier Ref." +msgstr "Rif. documento fornitore" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_category__tag_ids +msgid "Tag" +msgstr "" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_tag +msgid "Tags" +msgstr "" + +#. module: assets_management +#: model:ir.ui.menu,name:assets_management.menu_asset_technical_data +msgid "Technical Data" +msgstr "Dati tecnici" + +#. module: assets_management +#: code:addons/assets_management/models/asset.py:159 +#, python-format +msgid "The assets you are trying to delete are currently linked to accounting info. Please remove them if necessary before removing these assets:\n" +"" +msgstr "Stai cercando di cancellare registrazioni collegate al cespite. Occore rimuoverle per completare l'operazione" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:161 +#, python-format +msgid "The lines you you are trying to delete are currently linked to accounting info. Please remove them if necessary before removing these lines:\n" +"" +msgstr "Stai cercando di cancellare registrazioni collegate al cespite. Occore rimuoverle per completare l'operazione" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_mode.py:83 +#, python-format +msgid "There can be no more than 1 default depreciation mode for each company." +msgstr "" + +#. module: assets_management +#: model_terms:ir.actions.act_window,help:assets_management.action_asset_accounting_info +msgid "There is no archive about assets, invoices and account moves... yet!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:209 +#: code:addons/assets_management/report/asset_previsional.py:212 +#, python-format +msgid "There is nothing to print according to current settings!" +msgstr "Non c’è nulla da stampare in base ai parametri scelti!" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_journal_report__date +#: model:ir.model.fields,field_description:assets_management.field_wizard_asset_previsional_report__date +msgid "To Date" +msgstr "Alla Data" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode_line__to_nr +msgid "To Nr" +msgstr "Al Nr" + +#. module: assets_management +#: selection:asset.asset,activity_state:0 +msgid "Today" +msgstr "Oggi" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:344 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:313 +#, python-format +msgid "Total" +msgstr "Totale" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:348 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:317 +#: model:ir.model.fields,field_description:assets_management.field_asset_category_depreciation_type__depreciation_type_id +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line__move_type +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_line_type__type +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal__type_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__type_id +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional__type_ids +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__type_id +#, python-format +msgid "Type" +msgstr "Tipo" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation__type_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__type_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_totals__type_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation__type_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__type_name +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_totals__type_name +msgid "Type Name" +msgstr "Nome tipo" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:464 +#: code:addons/assets_management/report/asset_previsional.py:499 +#, python-format +msgid "Unknown" +msgstr "Non definito" + +#. module: assets_management +#: code:addons/assets_management/models/asset_accounting_info.py:246 +#, python-format +msgid "Unknown Asset" +msgstr "Cespite non definito" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_unread +msgid "Unread Messages" +msgstr "Messaggi Non Letti" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__message_unread_counter +msgid "Unread Messages Counter" +msgstr "Contatore di messaggi non letti" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Update Asset" +msgstr "Aggiorna Cespite" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_invoice_mange_asset_form_view +msgid "Update Asset and Show" +msgstr "Aggiorna Cespite e Mostra" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,management_type:0 +#: selection:wizard.invoice.manage.asset,management_type:0 +msgid "Update Existing" +msgstr "Aggiorna Esistente" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__amount_depreciable_updated +msgid "Updated Amount" +msgstr "Aggiorma Valore" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:465 +#: code:addons/assets_management/report/asset_previsional.py:500 +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__used +#: model:ir.model.fields,field_description:assets_management.field_wizard_account_move_manage_asset__used +#: model:ir.model.fields,field_description:assets_management.field_wizard_invoice_manage_asset__used +#, python-format +msgid "Used" +msgstr "Bene usato" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation_mode__used_asset_coeff +msgid "Used Asset Coeff." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:188 +#: code:addons/assets_management/report/asset_journal_xlsx.py:320 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:186 +#, python-format +msgid "VAT" +msgstr "P.IVA" + +#. module: assets_management +#: model:ir.actions.server,name:assets_management.clean_asset_accounting_info_cron_ir_actions_server +#: model:ir.cron,cron_name:assets_management.clean_asset_accounting_info_cron +#: model:ir.cron,name:assets_management.clean_asset_accounting_info_cron +msgid "Vacuum Empty Asset Accounting Info" +msgstr "" + +#. module: assets_management +#: selection:wizard.invoice.manage.asset,invoice_type:0 +msgid "Vendor Bill" +msgstr "Fattura fornitore" + +#. module: assets_management +#: selection:wizard.invoice.manage.asset,invoice_type:0 +msgid "Vendor Credit Note" +msgstr "Nota credito fornitore" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +msgid "View Journal Report" +msgstr "Vedi" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "View Previsional Report" +msgstr "Vedi" + +#. module: assets_management +#: code:addons/assets_management/models/asset.py:221 +#: code:addons/assets_management/models/asset_depreciation.py:245 +#, python-format +msgid "Warning!" +msgstr "Attenzione!" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_asset__website_message_ids +msgid "Website Messages" +msgstr "Messaggi sito web" + +#. module: assets_management +#: model:ir.model.fields,help:assets_management.field_asset_asset__website_message_ids +msgid "Website communication history" +msgstr "Storico comunicazione sito" + +#. module: assets_management +#: selection:wizard.account.move.manage.asset,move_type:0 +#: selection:wizard.invoice.manage.asset,invoice_type:0 +msgid "Wrong" +msgstr "Errore" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal_xlsx.py:246 +#: code:addons/assets_management/report/asset_previsional_xlsx.py:244 +#: model:ir.model.fields,field_description:assets_management.field_report_asset_journal_depreciation_line_year__year +#: model:ir.model.fields,field_description:assets_management.field_report_asset_previsional_depreciation_line_year__year +#, python-format +msgid "Year" +msgstr "Anno" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.asset_dep_line_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.asset_form_view +msgid "You confirm the removal of the current line? Depreciation line amounts will not be affected and will have to be updated manually." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:215 +#, python-format +msgid "You need to choose invoice lines with account `{}` if you need them to create an asset for category `{}`!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:247 +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:291 +#, python-format +msgid "You need to choose invoice lines with account `{}` if you need them to dismiss asset `{}`!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_invoice_manage_asset.py:322 +#, python-format +msgid "You need to choose invoice lines with account `{}` if you need them to update asset `{}`!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:210 +#, python-format +msgid "You need to choose move lines with account `{}` if you need them to create an asset for category `{}`!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:243 +#: code:addons/assets_management/wizard/account_move_manage_asset.py:287 +#, python-format +msgid "You need to choose move lines with account `{}` if you need them to dismiss asset `{}`!" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/wizard/account_move_manage_asset.py:318 +#, python-format +msgid "You need to choose move lines with account `{}` if you need them to update asset `{}`!" +msgstr "" + +#. module: assets_management +#: model:ir.model.fields,field_description:assets_management.field_asset_depreciation__zero_depreciation_until +msgid "Zero Depreciation Up To" +msgstr "Nessun Amm.to fino al" + +#. module: assets_management +#: code:addons/assets_management/models/asset.py:176 +#, python-format +msgid "`{}`: cannot change asset's company once it's already related to accounting info." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation_line.py:187 +#, python-format +msgid "`{}`: cannot change depreciation line's company once it's already related to an asset." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/account_invoice_line.py:38 +#, python-format +msgid "`{}`: cannot change invoice line's company once it's already related to an asset." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/account_invoice.py:44 +#, python-format +msgid "`{}`: cannot change invoice's company once it's already related to an asset." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/account_move_line.py:38 +#, python-format +msgid "`{}`: cannot change move line's company once it's already related to an asset." +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/account_move.py:44 +#, python-format +msgid "`{}`: cannot change move's company once it's already related to an asset." +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_account_move_mange_asset_form_view +msgid "move lines" +msgstr "" + +#. module: assets_management +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_generate_depreciation_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_journal_report_form_view +#: model_terms:ir.ui.view,arch_db:assets_management.wizard_asset_previsional_report_form_view +msgid "or" +msgstr "o" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_assets_management_report_asset_journal_xlsx +msgid "report.assets_management.report_asset_journal_xlsx" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_assets_management_report_asset_previsional_xlsx +msgid "report.assets_management.report_asset_previsional_xlsx" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal +msgid "report_asset_journal" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_accounting_doc +msgid "report_asset_journal_accounting_doc" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_asset +msgid "report_asset_journal_asset" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_category +msgid "report_asset_journal_category" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_depreciation +msgid "report_asset_journal_depreciation" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_depreciation_line_year +msgid "report_asset_journal_depreciation_line_year" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_journal_totals +msgid "report_asset_journal_totals" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional +msgid "report_asset_previsional" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_accounting_doc +msgid "report_asset_previsional_accounting_doc" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_asset +msgid "report_asset_previsional_asset" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_category +msgid "report_asset_previsional_category" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_depreciation +msgid "report_asset_previsional_depreciation" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_depreciation_line_year +msgid "report_asset_previsional_depreciation_line_year" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_report_asset_previsional_totals +msgid "report_asset_previsional_totals" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/report/asset_journal.py:303 +#: code:addons/assets_management/report/asset_previsional.py:334 +#, python-format +msgid "to date {}" +msgstr "alla data {}" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_wizard_account_move_manage_asset +msgid "wizard.account.move.manage.asset" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_wizard_asset_generate_depreciation +msgid "wizard.asset.generate.depreciation" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_wizard_asset_journal_report +msgid "wizard.asset.journal.report" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_wizard_asset_previsional_report +msgid "wizard.asset.previsional.report" +msgstr "" + +#. module: assets_management +#: model:ir.model,name:assets_management.model_wizard_invoice_manage_asset +msgid "wizard.invoice.manage.asset" +msgstr "" + +#. module: assets_management +#: code:addons/assets_management/models/asset_depreciation.py:627 +#, python-format +msgid "{} - Depreciation" +msgstr "{} - Ammortamento" + diff --git a/assets_management/models/__init__.py b/assets_management/models/__init__.py new file mode 100644 index 000000000000..2ab82465ee23 --- /dev/null +++ b/assets_management/models/__init__.py @@ -0,0 +1,22 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import account_account +from . import account_fiscal_year +from . import account_invoice +from . import account_invoice_line +from . import account_journal +from . import account_move +from . import account_move_line +from . import asset +from . import asset_accounting_info +from . import asset_category +from . import asset_category_depreciation_type +from . import asset_depreciation +from . import asset_depreciation_line +from . import asset_depreciation_line_type +from . import asset_depreciation_mode +from . import asset_depreciation_mode_line +from . import asset_depreciation_type +from . import asset_tag diff --git a/assets_management/models/account_account.py b/assets_management/models/account_account.py new file mode 100644 index 000000000000..9461fe000250 --- /dev/null +++ b/assets_management/models/account_account.py @@ -0,0 +1,29 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import UserError + + +class AccountAccount(models.Model): + _inherit = 'account.account' + + @api.multi + def unlink(self): + if self.env['asset.category'].sudo().search([ + '|', + '|', + '|', + '|', + ('asset_account_id', 'in', self.ids), + ('depreciation_account_id', 'in', self.ids), + ('fund_account_id', 'in', self.ids), + ('gain_account_id', 'in', self.ids), + ('loss_account_id', 'in', self.ids), + ]): + raise UserError( + _("Cannot delete accounts while they're still used" + " by asset categories.") + ) + return super().unlink() diff --git a/assets_management/models/account_fiscal_year.py b/assets_management/models/account_fiscal_year.py new file mode 100644 index 000000000000..1aa24a3484c1 --- /dev/null +++ b/assets_management/models/account_fiscal_year.py @@ -0,0 +1,39 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class AccountFiscalYear(models.Model): + _inherit = 'account.fiscal.year' + + @api.model + def get_fiscal_year_by_date( + self, date, limit=1, company=None, miss_raise=True + ): + """ + Retrieves fiscal year by given ``date`` (a datetime.date object). + + By default, only 1 fiscal year will be returned, unless specified + differently. + If ``miss_raise`` is True and no fiscal year is found, an error will be + raised. + """ + dom = self.get_fiscal_year_by_date_domain(date, company) + fiscal_years = self.search(dom, limit=limit) + if not fiscal_years and miss_raise: + date_str = fields.Date.to_string(date) + raise UserError(_("No fiscal year defined for date ") + date_str) + return fiscal_years + + @api.model + def get_fiscal_year_by_date_domain(self, date, company=None): + """ + Prepares a search() domain to retrieve fiscal years by given ``date``. + """ + domain = [('date_from', '<=', date), ('date_to', '>=', date)] + if company: + domain.append(('company_id', 'in', company.ids)) + return domain diff --git a/assets_management/models/account_invoice.py b/assets_management/models/account_invoice.py new file mode 100644 index 000000000000..859b5761e7db --- /dev/null +++ b/assets_management/models/account_invoice.py @@ -0,0 +1,128 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'invoice_id', + string="Assets Accounting Info" + ) + + asset_ids = fields.Many2many( + 'asset.asset', + compute='_compute_asset_data', + store=True, + string="Assets" + ) + + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + compute='_compute_asset_data', + store=True, + string="Depreciation Lines" + ) + + hide_link_asset_button = fields.Boolean( + compute='_compute_hide_link_asset_button', + default=True, + string="Hide Asset Button", + ) + + @api.constrains('company_id') + def check_company(self): + for inv in self: + comp = inv.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != inv.company_id): + raise ValidationError( + _("`{}`: cannot change invoice's company once it's already" + " related to an asset.") + .format(inv.name_get()[0][-1]) + ) + + @api.multi + def action_invoice_cancel(self): + res = super().action_invoice_cancel() + if self: + # Remove every a.a.info related to current invoices, and delete + # related depreciation lines + aa_infos = self.mapped(lambda i: i.get_linked_aa_info_records()) + dep_lines = aa_infos.mapped('dep_line_id') + aa_infos.unlink() + # Filtering needed: cannot delete dep lines with a.a.info + dep_lines.filtered( + lambda l: not l.asset_accounting_info_ids + ).unlink() + return res + + @api.multi + @api.depends( + 'asset_accounting_info_ids', + 'asset_accounting_info_ids.asset_id', + 'asset_accounting_info_ids.dep_line_id', + ) + def _compute_asset_data(self): + for inv in self: + aa_info = inv.get_linked_aa_info_records() + assets = aa_info.mapped('asset_id') + dep_lines = aa_info.mapped('dep_line_id') + if dep_lines: + assets += dep_lines.mapped('asset_id') + inv.update({ + 'asset_ids': [(6, 0, assets.ids)], + 'dep_line_ids': [(6, 0, dep_lines.ids)] + }) + + @api.multi + def _compute_hide_link_asset_button(self): + valid_account_ids = self.get_valid_accounts() + if not valid_account_ids: + self.update({'hide_link_asset_button': True}) + else: + for inv in self: + inv.hide_link_asset_button = not any([ + l.account_id.id in valid_account_ids.ids + for l in inv.invoice_line_ids + ]) or inv.state in ('draft', 'cancel') + + @api.multi + def open_wizard_manage_asset(self): + self.ensure_one() + lines = self.invoice_line_ids.filtered( + lambda l: not l.asset_accounting_info_ids + ) + if not lines: + raise ValidationError( + _("Every line is already linked to an asset.") + ) + + xmlid = 'assets_management.action_wizard_invoice_manage_asset' + act = self.env.ref(xmlid).read()[0] + ctx = dict(self._context) + ctx.update({ + 'default_company_id': self.company_id.id, + 'default_dismiss_date': self.date_invoice or self.date_due, + 'default_invoice_ids': [(6, 0, self.ids)], + 'default_invoice_line_ids': [(6, 0, lines.ids)], + 'default_purchase_date': self.date_invoice or self.date_due, + 'invoice_ids': self.ids, + }) + act.update({'context': ctx}) + return act + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.env['asset.accounting.info'].search([ + '|', + ('invoice_id', '=', self.id), + ('invoice_line_id.invoice_id', '=', self.id), + ]) + + def get_valid_accounts(self): + return self.env['asset.category'].search([]).mapped('asset_account_id') diff --git a/assets_management/models/account_invoice_line.py b/assets_management/models/account_invoice_line.py new file mode 100644 index 000000000000..9789781dfda2 --- /dev/null +++ b/assets_management/models/account_invoice_line.py @@ -0,0 +1,91 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountInvoiceLine(models.Model): + _inherit = 'account.invoice.line' + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'invoice_line_id', + string="Assets Accounting Info" + ) + + asset_ids = fields.Many2many( + 'asset.asset', + compute='_compute_asset_data', + store=True, + string="Assets" + ) + + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + compute='_compute_asset_data', + store=True, + string="Depreciation Lines" + ) + + @api.constrains('company_id') + def check_company(self): + for inv_line in self: + comp = inv_line.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != inv_line.company_id): + raise ValidationError( + _("`{}`: cannot change invoice line's company once it's" + " already related to an asset.") + .format(inv_line.name_get()[0][-1]) + ) + + @api.multi + @api.depends('asset_accounting_info_ids', + 'asset_accounting_info_ids.asset_id', + 'asset_accounting_info_ids.dep_line_id') + def _compute_asset_data(self): + for line in self: + aa_info = line.get_linked_aa_info_records() + assets = aa_info.mapped('asset_id') + dep_lines = aa_info.mapped('dep_line_id') + if dep_lines: + assets += dep_lines.mapped('asset_id') + line.update({ + 'asset_ids': [(6, 0, assets.ids)], + 'dep_line_ids': [(6, 0, dep_lines.ids)], + }) + + def get_asset_purchase_amount(self, currency=None): + purchase_amount = 0 + + for line in self: + # Standard line amount + purchase_amount += line.currency_id.compute( + line.price_subtotal, currency + ) + if line.invoice_line_tax_ids: + # Get taxes + discount = line.price_unit * (line.discount or 0.0) / 100 + price_unit = line.price_unit - discount + line_currency = line.currency_id + qty = line.quantity + product = line.product_id + partner = line.invoice_id.partner_id + taxes = line.invoice_line_tax_ids.compute_all( + price_unit, line_currency, qty, product, partner + ).get('taxes') or [] + # Add non-deductible taxes + for tax_dict in taxes: + if not (tax_dict.get('account_id') + or tax_dict.get('refund_account_id')) \ + and tax_dict.get('amount'): + purchase_amount += line.currency_id.compute( + tax_dict.get('amount'), currency + ) + + return purchase_amount + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.asset_accounting_info_ids diff --git a/assets_management/models/account_journal.py b/assets_management/models/account_journal.py new file mode 100644 index 000000000000..c831dc1b89e9 --- /dev/null +++ b/assets_management/models/account_journal.py @@ -0,0 +1,21 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import UserError + + +class AccountJournal(models.Model): + _inherit = 'account.journal' + + @api.multi + def unlink(self): + if self.env['asset.category'].sudo().search([ + ('journal_id', 'in', self.ids), + ]): + raise UserError( + _("Cannot delete journals while they're still used" + " by asset categories.") + ) + return super().unlink() diff --git a/assets_management/models/account_move.py b/assets_management/models/account_move.py new file mode 100644 index 000000000000..cb80fa0654a6 --- /dev/null +++ b/assets_management/models/account_move.py @@ -0,0 +1,128 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountMove(models.Model): + _inherit = 'account.move' + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'move_id', + string="Assets Accounting Info" + ) + + asset_ids = fields.Many2many( + 'asset.asset', + compute='_compute_asset_data', + store=True, + string="Assets" + ) + + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + compute='_compute_asset_data', + store=True, + string="Depreciation Lines" + ) + + hide_link_asset_button = fields.Boolean( + compute='_compute_hide_link_asset_button', + default=True, + string="Hide Asset Button", + ) + + @api.constrains('company_id') + def check_company(self): + for move in self: + comp = move.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != move.company_id): + raise ValidationError( + _("`{}`: cannot change move's company once it's already" + " related to an asset.") + .format(move.name_get()[0][-1]) + ) + + @api.multi + def button_cancel(self): + res = super().button_cancel() + if self: + # Remove every a.a.info related to current moves, and delete + # related depreciation lines + aa_infos = self.mapped(lambda m: m.get_linked_aa_info_records()) + dep_lines = aa_infos.mapped('dep_line_id') + aa_infos.unlink() + # Filtering needed: cannot delete dep lines with a.a.info + dep_lines.filtered( + lambda l: not l.asset_accounting_info_ids + ).unlink() + return res + + @api.multi + @api.depends( + 'asset_accounting_info_ids', + 'asset_accounting_info_ids.asset_id', + 'asset_accounting_info_ids.dep_line_id', + ) + def _compute_asset_data(self): + for move in self: + aa_info = move.get_linked_aa_info_records() + assets = aa_info.mapped('asset_id') + dep_lines = aa_info.mapped('dep_line_id') + if dep_lines: + assets += dep_lines.mapped('asset_id') + move.update({ + 'asset_ids': [(6, 0, assets.ids)], + 'dep_line_ids': [(6, 0, dep_lines.ids)] + }) + + @api.multi + def _compute_hide_link_asset_button(self): + valid_account_ids = self.get_valid_accounts() + if not valid_account_ids: + self.update({'hide_link_asset_button': True}) + else: + for move in self: + move.hide_link_asset_button = not any([ + l.account_id.id in valid_account_ids.ids + for l in move.line_ids + ]) or move.state != 'posted' + + @api.multi + def open_wizard_manage_asset(self): + self.ensure_one() + lines = self.line_ids.filtered( + lambda l: not l.asset_accounting_info_ids + ) + if not lines: + raise ValidationError( + _("Every line is already linked to an asset.") + ) + + xmlid = 'assets_management.action_wizard_account_move_manage_asset' + act = self.env.ref(xmlid).read()[0] + ctx = dict(self._context) + ctx.update({ + 'default_company_id': self.company_id.id, + 'default_dismiss_date': self.date or fields.Date.today(), + 'default_move_ids': [(6, 0, self.ids)], + 'default_move_line_ids': [(6, 0, lines.ids)], + 'default_purchase_date': self.date or fields.Date.today(), + 'move_ids': self.ids, + }) + act.update({'context': ctx}) + return act + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.env['asset.accounting.info'].search([ + '|', + ('move_id', '=', self.id), + ('move_line_id.move_id', '=', self.id), + ]) + + def get_valid_accounts(self): + return self.env['asset.category'].search([]).mapped('asset_account_id') diff --git a/assets_management/models/account_move_line.py b/assets_management/models/account_move_line.py new file mode 100644 index 000000000000..3be8346c9c65 --- /dev/null +++ b/assets_management/models/account_move_line.py @@ -0,0 +1,72 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountMoveLine(models.Model): + _inherit = 'account.move.line' + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'move_line_id', + string="Assets Accounting Info" + ) + + asset_ids = fields.Many2many( + 'asset.asset', + compute='_compute_asset_data', + store=True, + string="Assets" + ) + + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + compute='_compute_asset_data', + store=True, + string="Depreciation Lines" + ) + + @api.constrains('company_id') + def check_company(self): + for move_line in self: + comp = move_line.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != move_line.company_id): + raise ValidationError( + _("`{}`: cannot change move line's company once it's" + " already related to an asset.") + .format(move_line.name_get()[0][-1]) + ) + + @api.multi + @api.depends( + 'asset_accounting_info_ids', + 'asset_accounting_info_ids.asset_id', + 'asset_accounting_info_ids.dep_line_id', + ) + def _compute_asset_data(self): + for line in self: + aa_info = line.get_linked_aa_info_records() + assets = aa_info.mapped('asset_id') + dep_lines = aa_info.mapped('dep_line_id') + if dep_lines: + assets += dep_lines.mapped('asset_id') + line.update({ + 'asset_ids': [(6, 0, assets.ids)], + 'dep_line_ids': [(6, 0, dep_lines.ids)], + }) + + def get_asset_purchase_amount(self, currency=None): + purchase_amount = 0 + for line in self: + purchase_amount += line.currency_id.compute( + line.debit - line.credit, currency + ) + + return purchase_amount + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.asset_accounting_info_ids diff --git a/assets_management/models/asset.py b/assets_management/models/asset.py new file mode 100644 index 000000000000..7c9ebd3c7b60 --- /dev/null +++ b/assets_management/models/asset.py @@ -0,0 +1,280 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class Asset(models.Model): + _name = 'asset.asset' + _description = "Assets" + _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin'] + _order = 'purchase_date desc, name asc' + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'asset_id', + string="Accounting Info" + ) + + category_id = fields.Many2one( + 'asset.category', + required=True, + string="Category", + ) + + code = fields.Char( + default="", + string="Code", + ) + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + required=True, + string="Company", + track_visibility='onchange', + ) + + currency_id = fields.Many2one( + 'res.currency', + required=True, + string="Currency", + ) + + customer_id = fields.Many2one( + 'res.partner', + string="Customer" + ) + + depreciation_ids = fields.One2many( + 'asset.depreciation', + 'asset_id', + string="Depreciations", + ) + + name = fields.Char( + required=True, + string="Name", + track_visibility='onchange', + ) + + purchase_amount = fields.Monetary( + string="Purchase Value", + track_visibility='onchange', + ) + + purchase_date = fields.Date( + default=fields.Date.today(), + string="Purchase Date", + track_visibility='onchange', + ) + + purchase_invoice_id = fields.Many2one( + 'account.invoice', + string="Purchase Invoice" + ) + + purchase_move_id = fields.Many2one( + 'account.move', + string="Purchase Move" + ) + + sale_amount = fields.Monetary( + string="Sale Value", + ) + + sale_date = fields.Date( + string="Sale Date" + ) + + sale_invoice_id = fields.Many2one( + 'account.invoice', + string="Sale Invoice" + ) + + sale_move_id = fields.Many2one( + 'account.move', + string="Sale Move" + ) + + sold = fields.Boolean( + string="Sold" + ) + + state = fields.Selection( + [('non_depreciated', "Non Depreciated"), + ('partially_depreciated', "Partially Depreciated"), + ('totally_depreciated', "Depreciated")], + compute='_compute_state', + default='non_depreciated', + store=True, + string="State" + ) + + supplier_id = fields.Many2one( + 'res.partner', + string="Supplier" + ) + + supplier_ref = fields.Char( + string="Supplier Ref." + ) + + used = fields.Boolean( + string="Used", + ) + + @api.model + def create(self, vals): + # Add depreciation if it's missing while category is set + create_deps_from_categ = False + if vals.get('category_id') and not vals.get('depreciation_ids'): + create_deps_from_categ = True + if vals.get('code'): + vals['code'] = ' '.join(vals.get('code').split()) + asset = super().create(vals) + if create_deps_from_categ: + asset.onchange_category_id() + return asset + + @api.multi + def write(self, vals): + if vals.get('code'): + vals['code'] = ' '.join(vals.get('code').split()) + return super().write(vals) + + @api.multi + def unlink(self): + if self.mapped('asset_accounting_info_ids'): + assets = self.filtered('asset_accounting_info_ids') + name_list = "\n".join([a[-1] for a in assets.name_get()]) + raise ValidationError( + _("The assets you are trying to delete are currently linked" + " to accounting info. Please remove them if necessary" + " before removing these assets:\n") + name_list + ) + self.mapped('depreciation_ids').unlink() + return super().unlink() + + @api.multi + def name_get(self): + return [(asset.id, asset.make_name()) for asset in self] + + @api.constrains('company_id') + def check_company(self): + for asset in self: + comp = asset.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != asset.company_id): + raise ValidationError( + _("`{}`: cannot change asset's company once it's already" + " related to accounting info.") + .format(asset.make_name()) + ) + + @api.multi + @api.depends('depreciation_ids', 'depreciation_ids.state') + def _compute_state(self): + for asset in self: + asset.state = asset.get_asset_state() + + @api.onchange('category_id') + def onchange_category_id(self): + # Do not allow category changes if any depreciation line is already + # linked to an account move + if any(self.depreciation_ids.mapped('line_ids.move_id')): + raise ValidationError( + _("Cannot change category for an asset that's already been" + " depreciated.") + ) + + if self.category_id: + + # Remove depreciation lines + self.depreciation_ids = False + + # Set new lines + vals = self.category_id.get_depreciation_vals(self.purchase_amount) + self.depreciation_ids = [(0, 0, v) for v in vals] + self.onchange_purchase_amount() + self.onchange_purchase_date() + + @api.onchange('company_id') + def onchange_company_currency(self): + if self.company_id: + self.currency_id = self.company_id.currency_id + + @api.onchange('purchase_amount') + def onchange_purchase_amount(self): + if self.purchase_amount: + for dep in self.depreciation_ids: + dep.amount_depreciable = self.purchase_amount * dep.base_coeff + if self.depreciation_ids.mapped('line_ids').filtered( + lambda l: l.move_type == 'depreciated' + ): + title = _("Warning!") + msg = _( + "Current asset has already been depreciated. Changes upon" + " its purchase value will not be automatically reflected" + " upon depreciation lines, which will have to be updated" + " manually." + ) + return {'warning': {'title': title, 'message': msg}} + + @api.onchange('purchase_date') + def onchange_purchase_date(self): + if self.purchase_date: + for dep in self.depreciation_ids: + dep.date_start = self.purchase_date + + @api.multi + def launch_wizard_generate_depreciations(self): + self.ensure_one() + xmlid = 'assets_management.action_wizard_asset_generate_depreciation' + [act] = self.env.ref(xmlid).read() + ctx = dict(self._context) + ctx.update({ + 'default_asset_ids': [(6, 0, self.ids)], + 'default_category_ids': [(6, 0, self.category_id.ids)], + 'default_company_id': self.company_id.id, + 'default_date': fields.Date.today(), + 'default_type_ids': [ + (6, 0, self.depreciation_ids.mapped('type_id').ids) + ], + }) + act['context'] = ctx + return act + + def get_asset_state(self): + self.ensure_one() + if not self.depreciation_ids: + return 'non_depreciated' + + states = tuple(set(self.depreciation_ids.mapped('state'))) + + if not states: + return 'non_depreciated' + elif len(states) == 1: + return states[0] + else: + return 'partially_depreciated' + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.env['asset.accounting.info'].search([ + '|', + ('asset_id', '=', self.id), + ('dep_line_id.asset_id', '=', self.id), + ]) + + def make_name(self): + self.ensure_one() + name = self.name.strip() + if self.code: + return "[{}] {}".format(self.code.strip(), name) + return name diff --git a/assets_management/models/asset_accounting_info.py b/assets_management/models/asset_accounting_info.py new file mode 100644 index 000000000000..5fc088510029 --- /dev/null +++ b/assets_management/models/asset_accounting_info.py @@ -0,0 +1,258 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AssetAccountingInfo(models.Model): + """ + This model is necessary to manage info about the relationships between + assets and accounting records. We could have used `Many2many` fields to + create tables between assets, depreciation lines, invoices, invoice + lines, account moves and account move lines; but we need a custom + management, a bit more complex than the one provided by the standard + `Many2many` field. + + NB: a few methods could have been decorated with @api.constrains or + @api.depends, but that would have limited them by being triggered only + upon some fields' changes, and would have made it very hard to be + customizable by third party modules. + Therefore, it has been chosen to define them as simple Python methods which + are called right after ``create`` and ``write`` methods if some fields + (which can be retrieved by method ``get_main_fields``) are found within + ``vals`` dictionary. + """ + + _name = 'asset.accounting.info' + _description = "Asset Accounting Relations" + _table = 'asset_accounting_info' + + asset_id = fields.Many2one( + 'asset.asset', + ondelete='set null', + string="Asset" + ) + + company_id = fields.Many2one( + 'res.company', + readonly=True, + string="Company", + ) + + dep_line_id = fields.Many2one( + 'asset.depreciation.line', + ondelete='set null', + string="Depreciation Line" + ) + + invoice_id = fields.Many2one( + 'account.invoice', + ondelete='set null', + string="Invoice" + ) + + invoice_line_id = fields.Many2one( + 'account.invoice.line', + ondelete='set null', + string="Invoice Line" + ) + + move_id = fields.Many2one( + 'account.move', + ondelete='set null', + string="Move" + ) + + move_line_id = fields.Many2one( + 'account.move.line', + ondelete='set null', + string="Move Line" + ) + + relation_type = fields.Selection( + [('create', "Asset Creation"), + ('update', "Asset Update"), + ('partial_dismiss', "Asset Partial Dismissal"), + ('dismiss', "Asset Dismissal")], + required=True, + string="Relation Type" + ) + + @api.model + def create(self, vals): + info = super().create(vals) + info.check_and_normalize() + return info + + @api.multi + def write(self, vals): + fnames = self.get_main_fields() + + # ``load=''`` avoids returning tuple ``(rec.id, rec.name)`` for M2o + # fields and simply returns ``rec.id`` + old_info_vals = {d['id']: d for d in self.read(fnames, load='')} + res = super().write(vals) + new_info_vals = {d['id']: d for d in self.read(fnames, load='')} + + # old/new_info_vals dicts both have the same keys + to_check_ids = [] + for aa_info_id, old_vals in old_info_vals.items(): + new_vals = new_info_vals[aa_info_id] + common_fs = set(new_vals).intersection(old_vals) + extra_fs = set(new_vals).union(old_vals) - common_fs + if extra_fs or any(new_vals[k] != old_vals[k] for k in common_fs): + to_check_ids.append(aa_info_id) + + if to_check_ids: + self.browse(to_check_ids).check_and_normalize() + + return res + + @api.multi + def name_get(self): + return [(aa_info.id, aa_info.make_name()) for aa_info in self] + + @api.model + def cron_vacuum_table(self): + """ A cron that deletes obsolete records """ + aa_info = self.get_records_to_delete_by_cron() + aa_info.unlink() + + @api.model + def get_main_fields(self): + return [ + 'asset_id', 'dep_line_id', + 'invoice_id', 'invoice_line_id', + 'move_id', 'move_line_id' + ] + + @api.multi + def button_unlink(self): + """ Button action: deletes a.a.info """ + self.unlink() + + def check_and_normalize(self): + for info in self: + info.check_coherence() + info.normalize_info() + + def check_coherence(self): + """ Checks info coherence """ + self.check_company_coherence() + self.check_data_coherence() + + def check_company_coherence(self): + """ Checks companies """ + self.ensure_one() + companies = self.get_all_companies() + if len(companies) > 1: + raise ValidationError( + _("Incoherent company data.") + ) + + def check_data_coherence(self): + self.ensure_one() + + # If dep_line_id and asset_id are set, check whether the depreciation + # line belongs to the given asset + if self.asset_id and self.dep_line_id \ + and self.asset_id != self.dep_line_id.depreciation_id.asset_id: + raise ValidationError( + _("Incoherent asset data.") + ) + + # If invoice_line_id and invoice_id are set, check whether the invoice + # line belongs to the given invoice + if self.invoice_id and self.invoice_line_id \ + and self.invoice_id != self.invoice_line_id.invoice_id: + raise ValidationError( + _("Incoherent invoice data.") + ) + + # If move_line_id and move_id are set, check whether the move line + # belongs to the given move + if self.move_id and self.move_line_id \ + and self.move_id != self.move_line_id.move_id: + raise ValidationError( + _("Incoherent move data.") + ) + + def get_all_companies(self): + company_ids = [] + + fnames = self.get_main_fields() + for aa_info in self: + for fname in fnames: + # Using sudo() to avoid security problems during this check + rec = aa_info.sudo()[fname] + if rec and rec.company_id.id not in company_ids: + company_ids.append(rec.company_id.id) + + return self.env['res.company'].browse(company_ids) + + def get_normalized_info_vals(self): + self.ensure_one() + vals = {} + + # Set asset as dep line's asset if dep line is set + if not self.asset_id and self.dep_line_id: + vals['asset_id'] = self.dep_line_id.asset_id.id + + # Set invoice_id as invoice line's invoice if invoice line is set + if not self.invoice_id and self.invoice_line_id: + vals['invoice_id'] = self.invoice_line_id.invoice_id.id + + # Set move_id as move line's move if move line is set + if not self.move_id and self.move_line_id: + vals['move_id'] = self.move_line_id.move_id.id + + # Set company + companies = self.get_all_companies() + if len(companies) == 1: + vals['company_id'] = companies.id + else: + vals['company_id'] = False + + return vals + + def get_records_to_delete_by_cron(self): + """ + Returns every a.a.info that fits the condition: + (no asset AND no depreciation line) + OR + (no invoice AND no invoice line AND no move AND no move line) + """ + return self.search([ + '|', + '&', + ('asset_id', '=', False), + ('dep_line_id', '=', False), + '&', + '&', + '&', + ('invoice_id', '=', False), + ('invoice_line_id', '=', False), + ('move_id', '=', False), + ('move_line_id', '=', False), + ]) + + def make_name(self): + self.ensure_one() + if self.asset_id: + name = self.asset_id.make_name() + else: + name = _("Unknown Asset") + relation_name = dict(self._fields['relation_type'].selection) \ + .get(self.relation_type) + if relation_name: + name += " - " + relation_name + return name.strip() + + def normalize_info(self): + """ Normalize asset accounting info if needed """ + self.ensure_one() + vals = self.get_normalized_info_vals() + if vals: + self.write(vals) diff --git a/assets_management/models/asset_category.py b/assets_management/models/asset_category.py new file mode 100644 index 000000000000..0377bb5a8079 --- /dev/null +++ b/assets_management/models/asset_category.py @@ -0,0 +1,142 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class AssetCategory(models.Model): + _name = 'asset.category' + _description = "Asset Category" + _order = 'name' + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + @api.model + def get_default_type_ids(self): + mode_obj = self.env['asset.depreciation.mode'] + dom = [('company_id', '=', self.get_default_company_id().id)] + mode = mode_obj.search(dom + [('default', '=', True)], limit=1) + # Field ``mode_id`` is required for asset.category.depreciation.type; + # if no default mode is found, retry by getting the first one found. + if not mode: + mode = mode_obj.search(dom, limit=1) + + types = self.env['asset.depreciation.type'].search(dom) + + # Raise error if configuration has not been completed. + if not (mode and types): + raise UserError( + _("Before creating new categories, please complete the" + " assets' configuration for both depreciation types" + " and modes.") + ) + + return [ + (0, 0, {'base_coeff': 1, + 'depreciation_type_id': t.id, + 'mode_id': mode.id}) + for t in types + ] + + asset_account_id = fields.Many2one( + 'account.account', + required=True, + string="Asset Account", + ) + + comment = fields.Text( + string="Comment", + ) + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + string="Company" + ) + + depreciation_account_id = fields.Many2one( + 'account.account', + required=True, + string="Depreciation Account", + ) + + fund_account_id = fields.Many2one( + 'account.account', + required=True, + string="Fund Account", + ) + + gain_account_id = fields.Many2one( + 'account.account', + required=True, + string="Capital Gain Account", + ) + + journal_id = fields.Many2one( + 'account.journal', + required=True, + string="Journal" + ) + + loss_account_id = fields.Many2one( + 'account.account', + required=True, + string="Capital Loss Account", + ) + + name = fields.Char( + required=True, + string="Name", + ) + + print_by_default = fields.Boolean( + default=True, + help="Defines whether a category should be added by default when" + " printing assets' reports.", + string="Print By Default" + ) + + tag_ids = fields.Many2many( + 'asset.tag', + string="Tag", + ) + + type_ids = fields.One2many( + 'asset.category.depreciation.type', + 'category_id', + default=get_default_type_ids, + string="Depreciation Types", + ) + + @api.multi + def copy(self, default=None): + default = dict(default or []) + default.update({ + 'tag_ids': [(6, 0, self.tag_ids.ids)], + 'type_ids': [ + (0, 0, t.copy_data({'category_id': False})[0]) + for t in self.type_ids + ] + }) + return super().copy(default) + + @api.multi + def unlink(self): + if self.env['asset.asset'].sudo().search([ + ('category_id', 'in', self.ids) + ]): + raise UserError( + _("Cannot delete categories while they're still linked" + " to an asset.") + ) + return super().unlink() + + def get_depreciation_vals(self, amount_depreciable=0): + return [ + t.get_depreciation_vals(amount_depreciable) + for t in self.type_ids + ] diff --git a/assets_management/models/asset_category_depreciation_type.py b/assets_management/models/asset_category_depreciation_type.py new file mode 100644 index 000000000000..a95bbe69dc58 --- /dev/null +++ b/assets_management/models/asset_category_depreciation_type.py @@ -0,0 +1,61 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AssetCategoryDepreciationType(models.Model): + _name = 'asset.category.depreciation.type' + _description = "Asset Category - Depreciation Type" + + base_coeff = fields.Float( + default=1, + help="Coeff to compute depreciable amount from purchase amount", + string="Dep Base Coeff", + ) + + category_id = fields.Many2one( + 'asset.category', + ondelete='cascade', + readonly=True, + required=True, + string="Category" + ) + + company_id = fields.Many2one( + 'res.company', + readonly=True, + related='category_id.company_id', + string="Company" + ) + + depreciation_type_id = fields.Many2one( + 'asset.depreciation.type', + required=True, + string="Type", + ) + + mode_id = fields.Many2one( + 'asset.depreciation.mode', + required=True, + string="Dep Mode", + ) + + percentage = fields.Float( + string="Depreciation %") + + pro_rata_temporis = fields.Boolean( + string="Pro-rata Temporis" + ) + + def get_depreciation_vals(self, amount_depreciable=0): + self.ensure_one() + return { + 'amount_depreciable': amount_depreciable * self.base_coeff, + 'base_coeff': self.base_coeff, + 'mode_id': self.mode_id.id, + 'percentage': self.percentage, + 'pro_rata_temporis': self.pro_rata_temporis, + 'type_id': self.depreciation_type_id.id + } diff --git a/assets_management/models/asset_depreciation.py b/assets_management/models/asset_depreciation.py new file mode 100644 index 000000000000..0493edc5f85d --- /dev/null +++ b/assets_management/models/asset_depreciation.py @@ -0,0 +1,628 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools import float_compare, float_is_zero + + +class AssetDepreciation(models.Model): + _name = 'asset.depreciation' + _description = "Assets Depreciations" + + amount_depreciable = fields.Monetary( + string="Depreciable Amount" + ) + + amount_depreciable_updated = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Updated Amount", + ) + + amount_depreciated = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Depreciated Amount", + ) + + amount_gain = fields.Monetary( + compute='_compute_amounts', + string="Capital Gain", + store=True, + ) + + amount_historical = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Historical Amount", + ) + + amount_in = fields.Monetary( + compute='_compute_amounts', + store=True, + string="In Amount", + ) + + amount_loss = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Capital Loss", + ) + + amount_out = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Out Amount", + ) + + amount_residual = fields.Monetary( + compute='_compute_amounts', + store=True, + string="Residual Amount", + ) + + asset_id = fields.Many2one( + 'asset.asset', + ondelete='cascade', + readonly=True, + required=True, + string="Asset", + ) + + base_coeff = fields.Float( + default=1, + help="Coeff to compute amount depreciable from purchase amount", + string="Depreciable Base Coeff", + ) + + company_id = fields.Many2one( + 'res.company', + readonly=True, + related='asset_id.company_id', + string="Company" + ) + + currency_id = fields.Many2one( + 'res.currency', + readonly=True, + related='asset_id.currency_id', + string="Currency" + ) + + date_start = fields.Date( + string="Date Start" + ) + + dismiss_move_id = fields.Many2one( + 'account.move', + string="Dismiss Move" + ) + + first_dep_nr = fields.Integer( + default=1, + string="First Dep. Num", + ) + + force_all_dep_nr = fields.Boolean( + string="Force All Dep. Num" + ) + + force_first_dep_nr = fields.Boolean( + string="Force First Dep. Num" + ) + + last_depreciation_date = fields.Date( + compute='_compute_last_depreciation_date', + store=True, + string="Last Dep.", + ) + + line_ids = fields.One2many( + 'asset.depreciation.line', + 'depreciation_id', + string="Lines" + ) + + mode_id = fields.Many2one( + 'asset.depreciation.mode', + required=True, + string="Mode", + ) + + percentage = fields.Float( + string="Depreciation (%)" + ) + + pro_rata_temporis = fields.Boolean( + string="Pro-rata Temporis" + ) + + requires_account_move = fields.Boolean( + readonly=True, + related='type_id.requires_account_move', + string="Requires Account Move", + ) + + state = fields.Selection( + [('non_depreciated', "Non Depreciated"), + ('partially_depreciated', "Partially Depreciated"), + ('totally_depreciated', "Depreciated")], + compute='_compute_state', + default='non_depreciated', + store=True, + string="State" + ) + + type_id = fields.Many2one( + 'asset.depreciation.type', + string="Depreciation Type" + ) + + zero_depreciation_until = fields.Date( + string="Zero Depreciation Up To" + ) + + @api.model + def create(self, vals): + dep = super().create(vals) + dep.normalize_first_dep_nr() + if dep.line_ids: + num_lines = dep.line_ids.filtered('requires_depreciation_nr') + if num_lines: + num_lines.normalize_depreciation_nr() + return dep + + @api.multi + def write(self, vals): + res = super().write(vals) + need_norm = self.filtered(lambda d: d.need_normalize_first_dep_nr()) + if need_norm: + need_norm.normalize_first_dep_nr(force=True) + for dep in self: + num_lines = dep.line_ids.filtered('requires_depreciation_nr') + if num_lines and num_lines.need_normalize_depreciation_nr(): + num_lines.normalize_depreciation_nr(force=True) + return res + + @api.multi + def unlink(self): + if self.mapped('line_ids'): + raise ValidationError( + _("Cannot delete depreciations if there is any depreciation" + " line linked to it.") + ) + if any([m.state != 'draft' for m in self.mapped('dismiss_move_id')]): + deps = self.filtered( + lambda l: l.dismiss_move_id + and l.dismiss_move_id.state != 'draft' + ) + name_list = "\n".join([l[-1] for l in deps.name_get()]) + raise ValidationError( + _("Following lines are linked to posted account moves, and" + " cannot be deleted:\n{}").format(name_list) + ) + return super().unlink() + + @api.multi + def name_get(self): + return [(dep.id, dep.make_name()) for dep in self] + + @api.multi + @api.depends( + 'amount_depreciable', 'amount_depreciable_updated', 'amount_residual' + ) + def _compute_state(self): + for dep in self: + dep.state = dep.get_depreciation_state() + + @api.onchange('asset_id', 'base_coeff') + def onchange_base_coeff(self): + purchase_amount = self.asset_id.purchase_amount + self.amount_depreciable = self.base_coeff * purchase_amount + + @api.onchange('first_dep_nr') + def onchange_normalize_first_dep_nr(self): + if self.first_dep_nr <= 0: + self.first_dep_nr = 1 + + @api.onchange('force_all_dep_nr') + def onchange_force_all_dep_nr(self): + if self.force_all_dep_nr: + self.first_dep_nr = 1 + + @api.onchange('force_first_dep_nr') + def onchange_force_first_dep_nr(self): + if self.force_first_dep_nr and self.first_dep_nr <= 0: + self.first_dep_nr = 1 + + @api.onchange('force_all_dep_nr', 'force_first_dep_nr') + def onchange_force_dep_nrs(self): + if self.force_all_dep_nr and self.force_first_dep_nr: + self.force_all_dep_nr = False + self.force_first_dep_nr = False + title = _("Warning!") + msg = _( + "Fields `Force All Dep. Num` and `Force First Dep. Num`" + " cannot be both active." + ) + return {'warning': {'title': title, 'message': msg}} + if not self.force_all_dep_nr and self.force_first_dep_nr: + self.first_dep_nr = 1 + + @api.multi + @api.depends('amount_depreciable', + 'line_ids.amount', + 'line_ids.balance', + 'line_ids.move_type', + 'asset_id.sold') + def _compute_amounts(self): + for dep in self: + vals = dep.get_computed_amounts() + dep.update(vals) + + @api.multi + @api.depends('line_ids', 'line_ids.date', 'line_ids.move_type') + def _compute_last_depreciation_date(self): + """ + Update date upon deps with at least one depreciation line (excluding + partial dismissal); else set field to False + """ + for dep in self: + dep_lines = dep.line_ids.filtered( + lambda l: l.move_type == 'depreciated' + and not l.partial_dismissal + ) + if dep_lines: + dep.last_depreciation_date = max(dep_lines.mapped('date')) + else: + dep.last_depreciation_date = False + + def check_before_generate_depreciation_lines(self, dep_date): + # Check if self is a valid recordset + if not self: + raise ValidationError( + _("Cannot create any depreciation according to current" + " settings.") + ) + + lines = self.mapped('line_ids') + + # Check if any depreciation already has newer depreciation lines + # than the given date + newer_lines = lines.filtered( + lambda l: l.move_type == 'depreciated' + and not l.partial_dismissal + and l.date > dep_date + ) + if newer_lines: + asset_names = ', '.join([ + asset_name for asset_id, asset_name in + newer_lines.mapped('depreciation_id.asset_id').name_get() + ]) + raise ValidationError( + _("Cannot update the following assets which contain" + " newer depreciations for the chosen types:\n{}") + .format(asset_names) + ) + + posted_lines = lines.filtered( + lambda l: l.date == dep_date + and l.move_id + and l.move_id.state != 'draft' + ) + if posted_lines: + posted_names = ', '.join([ + asset_name for asset_id, asset_name in + posted_lines.mapped('depreciation_id.asset_id').name_get() + ]) + raise ValidationError( + _("Cannot update the following assets which contain" + " posted depreciation for the chosen date and types:\n{}") + .format(posted_names) + ) + + def generate_depreciation_lines(self, dep_date): + # Set new date within context if necessary + self.check_before_generate_depreciation_lines(dep_date) + + new_lines = self.env['asset.depreciation.line'] + for dep in self: + new_lines |= dep.generate_depreciation_lines_single(dep_date) + + return new_lines + + def generate_depreciation_lines_single(self, dep_date): + self.ensure_one() + + dep_nr = self.get_max_depreciation_nr() + 1 + dep = self.with_context(dep_nr=dep_nr, used_asset=self.asset_id.used) + dep_amount = dep.get_depreciation_amount(dep_date) + dep = dep.with_context(dep_amount=dep_amount) + + vals = dep.prepare_depreciation_line_vals(dep_date) + return self.env['asset.depreciation.line'].create(vals) + + def generate_dismiss_account_move(self): + self.ensure_one() + am_obj = self.env['account.move'] + + vals = self.get_dismiss_account_move_vals() + if 'line_ids' not in vals: + vals['line_ids'] = [] + + line_vals = self.get_dismiss_account_move_line_vals() + for v in line_vals: + vals['line_ids'].append((0, 0, v)) + + self.dismiss_move_id = am_obj.create(vals) + + def get_computed_amounts(self): + self.ensure_one() + vals = { + 'amount_{}'.format(k): abs(v) + for k, v in self.line_ids.get_balances_grouped().items() + if 'amount_{}'.format(k) in self._fields + } + + if self.asset_id.sold: + vals.update({ + 'amount_depreciable_updated': 0, + 'amount_residual': 0 + }) + else: + non_residual_types = self.line_ids.get_non_residual_move_types() + update_move_types = self.line_ids.get_update_move_types() + amt_dep = self.amount_depreciable + vals.update({ + 'amount_depreciable_updated': amt_dep + sum([ + l.balance for l in self.line_ids + if l.move_type in update_move_types + ]), + 'amount_residual': amt_dep + sum([ + l.balance for l in self.line_ids + if l.move_type not in non_residual_types + ]) + }) + + return vals + + def get_depreciable_amount(self, dep_date=None): + types = self.line_ids.get_update_move_types() + return self.amount_depreciable + sum([ + l.balance for l in self.line_ids + if l.move_type in types and (not dep_date or l.date <= dep_date) + ]) + + def get_depreciation_amount(self, dep_date): + self.ensure_one() + zero_dep_date = self.zero_depreciation_until + if zero_dep_date and dep_date <= zero_dep_date: + return 0 + + # Get depreciable amount, multiplier and digits + amount = self.get_depreciable_amount(dep_date) + multiplier = self.get_depreciation_amount_multiplier(dep_date) + digits = self.env['decimal.precision'].precision_get('Account') + dep_amount = round(amount * multiplier, digits) + + # If amount_residual < dep_amount: use amount_residual as dep_amount + if float_compare(self.amount_residual, dep_amount, digits) < 0: + dep_amount = self.amount_residual + + return dep_amount + + def get_depreciation_amount_multiplier(self, dep_date): + self.ensure_one() + + # Base multiplier + multiplier = self.percentage / 100 + + # Update multiplier from depreciation mode data + multiplier *= self.mode_id.get_depreciation_amount_multiplier() + + # Update multiplier from pro-rata temporis + date_start = self.date_start + if dep_date < date_start: + dt_start_str = fields.Date.from_string(date_start).strftime( + '%d-%m-%Y' + ) + raise ValidationError( + _("Depreciations cannot start before {}.").format(dt_start_str) + ) + + if self.pro_rata_temporis or self._context.get('force_prorata'): + fiscal_year_obj = self.env['account.fiscal.year'] + fy_start = fiscal_year_obj.get_fiscal_year_by_date( + date_start, company=self.company_id + ) + fy_dep = fiscal_year_obj.get_fiscal_year_by_date( + dep_date, company=self.company_id + ) + if fy_dep == fy_start: + # If current depreciation lies within the same fiscal year in + # which the asset was registered, compute multiplier as a + # difference from date_dep multiplier and start_date + # multiplier, plus 1/lapse to avoid "skipping" one day + fy_end = fields.Date.from_string(fy_dep.date_to) + fy_start = fields.Date.from_string(fy_dep.date_from) + lapse = (fy_end - fy_start).days + 1 + dep_multiplier = self.get_pro_rata_temporis_multiplier( + dep_date, 'dte' + ) + start_multiplier = self.get_pro_rata_temporis_multiplier( + self.date_start, 'dte' + ) + multiplier *= start_multiplier - dep_multiplier + 1 / lapse + else: + # Otherwise, simply compute multiplier with respect to how + # many days have passed since the beginning of the fiscal year + multiplier *= self.get_pro_rata_temporis_multiplier( + dep_date, 'std' + ) + + return multiplier + + def get_depreciation_state(self): + self.ensure_one() + digits = self.env['decimal.precision'].precision_get('Account') + depreciable = self.amount_depreciable + residual = self.amount_residual + updated = self.amount_depreciable_updated + if float_is_zero(depreciable, digits): + return 'non_depreciated' + elif float_is_zero(residual, digits): + return 'totally_depreciated' + elif float_compare(residual, updated, digits) < 0: + return 'partially_depreciated' + else: + return 'non_depreciated' + + def get_dismiss_account_move_line_vals(self): + self.ensure_one() + credit_line_vals = { + 'account_id': self.asset_id.category_id.asset_account_id.id, + 'credit': self.amount_depreciated, + 'debit': 0.0, + 'currency_id': self.currency_id.id, + 'name': _("Asset dismissal: ") + self.asset_id.make_name(), + } + debit_line_vals = { + 'account_id': self.asset_id.category_id.fund_account_id.id, + 'credit': 0.0, + 'debit': self.amount_depreciated, + 'currency_id': self.currency_id.id, + 'name': _("Asset dismissal: ") + self.asset_id.make_name(), + } + return [credit_line_vals, debit_line_vals] + + def get_dismiss_account_move_vals(self): + self.ensure_one() + return { + 'company_id': self.company_id.id, + 'date': self.asset_id.sale_date, + 'journal_id': self.asset_id.category_id.journal_id.id, + 'line_ids': [], + 'ref': _("Asset dismissal: ") + self.asset_id.make_name(), + } + + def get_max_depreciation_nr(self): + self.ensure_one() + num_lines = self.line_ids.filtered('requires_depreciation_nr') + nums = num_lines.mapped('depreciation_nr') + if not nums: + nums = [0] + return max(nums) + + def get_pro_rata_temporis_dates(self, date): + """ + Gets useful dates for pro rata temporis computations, according to + given date, by retrieving its fiscal year. + + :param date: given date for depreciation + :return: date objects triplet (dt_start, dt, dt_end) + - dt_start: fiscal year first day + - dt: given date + - dt_end: fiscal year last day + """ + if not date: + raise ValidationError( + _("Cannot compute pro rata temporis for unknown date.") + ) + + fiscal_year_obj = self.env['account.fiscal.year'] + fiscal_year = fiscal_year_obj.get_fiscal_year_by_date( + date, company=self.company_id + ) + if not fiscal_year: + date_str = fields.Date.from_string(date).strftime('%d/%m/%Y') + raise ValidationError( + _("No fiscal year defined for date {}") + date_str + ) + + return ( + fields.Date.from_string(fiscal_year.date_from), + fields.Date.from_string(date), + fields.Date.from_string(fiscal_year.date_to) + ) + + def get_pro_rata_temporis_multiplier(self, date=None, mode='std'): + """ + Computes and returns pro rata temporis multiplier according to given + depreciation, date, fiscal year and mode + :param date: given date as a fields.Date string + :param mode: string, defines how to compute multiplier. Valid values: + - 'std': start-to-date, computes multiplier using days from fiscal + year's first day to given date; + - 'dte': date-to-end, computes multiplier using days from given + date to fiscal year's last day + """ + self.ensure_one() + if not (self.pro_rata_temporis or self._context.get('force_prorata')): + return 1 + + dt_start, dt, dt_end = self.get_pro_rata_temporis_dates(date) + lapse = (dt_end - dt_start).days + 1 + if mode == 'std': + return ((dt - dt_start).days + 1) / lapse + elif mode == 'dte': + return ((dt_end - dt).days + 1) / lapse + elif mode: + raise NotImplementedError( + _("Cannot get pro rata temporis multiplier for mode `{}`") + .format(mode) + ) + raise NotImplementedError( + _("Cannot get pro rata temporis multiplier for unspecified mode") + ) + + def make_name(self): + self.ensure_one() + return " - ".join((self.asset_id.make_name(), self.type_id.name or "")) + + def need_normalize_first_dep_nr(self): + self.ensure_one() + + if self.force_all_dep_nr: + return False + + if self.force_first_dep_nr: + if self.first_dep_nr <= 0: + return True + + else: + if self.first_dep_nr != 1: + return True + + return False + + def normalize_first_dep_nr(self, force=False): + """ + Normalize first numbered line according to `first_dep_nr` value + :param force: if True, force normalization + """ + force = force or self._context.get('force_normalize_first_dep_nr') + for d in self: + if force or d.need_normalize_first_dep_nr(): + d.onchange_normalize_first_dep_nr() + + def post_generate_depreciation_lines(self, lines=None): + lines = lines or self.env['asset.depreciation.line'] + lines.filtered('requires_account_move').button_generate_account_move() + + def prepare_depreciation_line_vals(self, dep_date): + self.ensure_one() + if dep_date is None: + raise ValidationError( + _("Cannot create a depreciation line without a date") + ) + dep_amount = self._context.get('dep_amount') or 0.0 + dep_year = fields.Date.from_string(dep_date).year + return { + 'amount': dep_amount, + 'date': dep_date, + 'depreciation_id': self.id, + 'move_type': 'depreciated', + 'name': _("{} - Depreciation").format(dep_year) + } diff --git a/assets_management/models/asset_depreciation_line.py b/assets_management/models/asset_depreciation_line.py new file mode 100644 index 000000000000..f59439a9a8d8 --- /dev/null +++ b/assets_management/models/asset_depreciation_line.py @@ -0,0 +1,518 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AssetDepreciationLine(models.Model): + _name = 'asset.depreciation.line' + _description = "Assets Depreciations Lines" + _order = 'date asc, name asc' + + amount = fields.Monetary( + string="Amount", + ) + + asset_accounting_info_ids = fields.One2many( + 'asset.accounting.info', + 'dep_line_id', + string="Accounting Info" + ) + + asset_id = fields.Many2one( + 'asset.asset', + readonly=True, + related='depreciation_id.asset_id', + store=True, + string="Asset" + ) + + balance = fields.Monetary( + compute='_compute_balance', + store=True, + string="Balance", + ) + + base = fields.Float( + string="Base", + ) + + company_id = fields.Many2one( + 'res.company', + readonly=True, + related='depreciation_id.company_id', + ) + + currency_id = fields.Many2one( + 'res.currency', + readonly=True, + related='depreciation_id.currency_id', + ) + + date = fields.Date( + required=True, + string="Date", + ) + + depreciation_id = fields.Many2one( + 'asset.depreciation', + ondelete='cascade', + readonly=True, + required=True, + string="Asset depreciation", + ) + + depreciation_line_type_id = fields.Many2one( + 'asset.depreciation.line.type', + string="Depreciation Type" + ) + + depreciation_nr = fields.Integer( + string="Dep. Num", + ) + + depreciation_type_id = fields.Many2one( + 'asset.depreciation.type', + readonly=True, + related='depreciation_id.type_id', + store=True, + string="Asset depreciation type", + ) + + force_dep_nr = fields.Boolean( + readonly=True, + related='depreciation_id.force_all_dep_nr', + string="Force Dep. Num", + ) + + move_id = fields.Many2one( + 'account.move', + string="Move" + ) + + move_type = fields.Selection( + [('depreciated', 'Depreciation'), + ('historical', 'Historical'), + ('in', 'In'), + ('out', 'Out'), + ('loss', 'Capital Loss'), + ('gain', 'Capital Gain')], + string="Type", + required=True + ) + + name = fields.Char( + required=True, + string="Name", + ) + + partial_dismissal = fields.Boolean( + string="Partial Dismissal" + ) + + percentage = fields.Float( + string="%" + ) + + requires_account_move = fields.Boolean( + readonly=True, + related='depreciation_id.type_id.requires_account_move', + string="Required Account Move", + ) + + requires_depreciation_nr = fields.Boolean( + compute='_compute_requires_depreciation_nr', + search='_search_requires_depreciation_nr_lines', + string="Requires Dep Num" + ) + + # Non-default parameter: set which `move_types` require numeration + _numbered_move_types = ('depreciated', 'historical') + # Non-default parameter: set which `move_types` do not concur to + # asset.depreciation's `amount_residual` field compute + _non_residual_move_types = ('gain',) + # Non-default parameter: set which `move_types` get to update the + # depreciable amount + _update_move_types = ('in', 'out') + + @api.model + def create(self, vals): + line = super().create(vals) + if line.need_normalize_depreciation_nr(): + line.normalize_depreciation_nr(force=True) + return line + + @api.multi + def write(self, vals): + res = super().write(vals) + for line in self: + if line.need_normalize_depreciation_nr(): + line.normalize_depreciation_nr(force=True) + return res + + @api.multi + def unlink(self): + if self.mapped('asset_accounting_info_ids'): + lines = self.filtered('asset_accounting_info_ids') + name_list = "\n".join([l[-1] for l in lines.name_get()]) + raise ValidationError( + _("The lines you you are trying to delete are currently" + " linked to accounting info. Please remove them if" + " necessary before removing these lines:\n") + name_list + ) + if any([m.state != 'draft' for m in self.mapped('move_id')]): + lines = self.filtered( + lambda l: l.move_id and l.move_id.state != 'draft' + ) + name_list = "\n".join([l[-1] for l in lines.name_get()]) + raise ValidationError( + _("Following lines are linked to posted account moves, and" + " cannot be deleted:\n") + name_list + ) + self.mapped('move_id').unlink() + return super().unlink() + + @api.multi + def name_get(self): + return [(line.id, line.make_name()) for line in self] + + @api.constrains('company_id') + def check_company(self): + for dep_line in self: + comp = dep_line.get_linked_aa_info_records().mapped('company_id') + if len(comp) > 1 or (comp and comp != dep_line.company_id): + raise ValidationError( + _("`{}`: cannot change depreciation line's company once" + " it's already related to an asset.") + .format(dep_line.make_name()) + ) + + @api.constrains('depreciation_nr') + def check_depreciation_nr_coherence(self): + for dep in self.mapped('depreciation_id'): + # Check if any number is negative + num_lines = dep.line_ids.filtered('requires_depreciation_nr') + nums = num_lines.mapped('depreciation_nr') + if nums and min(nums) < 0: + raise ValidationError( + _("Depreciation number can't be a negative number.") + ) + + @api.multi + @api.depends('amount', 'move_type') + def _compute_balance(self): + for line in self: + if line.move_type in ['out', 'depreciated', 'historical', 'loss']: + line.balance = - line.amount + else: + line.balance = line.amount + + @api.multi + def _compute_requires_depreciation_nr(self): + for line in self: + line.requires_depreciation_nr = line.is_depreciation_nr_required() + + @api.multi + def _search_requires_depreciation_nr_lines(self, operator, value): + if operator not in ('=', '!='): + raise ValidationError( + _("Invalid search operator!") + ) + + if (operator == '=' and value) or (operator == '!=' and not value): + return [('move_type', 'in', self.get_numbered_move_types())] + else: + return [('move_type', 'not in', self.get_numbered_move_types())] + + @api.onchange('move_type') + def onchange_move_type(self): + if self.move_type not in ('in', 'out'): + self.depreciation_line_type_id = False + + def get_linked_aa_info_records(self): + self.ensure_one() + return self.asset_accounting_info_ids + + def get_balances_grouped(self): + """ Groups balances of line in `self` by line.move_type """ + balances_grouped = {} + for line in self: + if line.move_type not in balances_grouped: + balances_grouped[line.move_type] = 0 + balances_grouped[line.move_type] += line.balance + return balances_grouped + + def get_depreciation_nr_dict(self): + """ Returns dict {line: new number} """ + dep = self.mapped('depreciation_id') + dep.ensure_one() + lines = dep.line_ids.filtered('requires_depreciation_nr').sorted() + if not lines: + return {} + + first_num = 1 + if dep.force_first_dep_nr and dep.first_dep_nr > 0: + first_num = dep.first_dep_nr + + return { + line: nr + first_num + for nr, line in enumerate(lines) + } + + def get_non_residual_move_types(self): + """ + Returns list of `move_type` vals that do not concur to + asset.depreciation's `amount_residual` field compute + """ + return self._non_residual_move_types + + def get_numbered_move_types(self): + """ Returns list of `move_type` vals that require numeration """ + return self._numbered_move_types + + def get_update_move_types(self): + """ + Returns list of `move_type` that concur to update asset.depreciation's + `amount_depreciable_updated` field + """ + return self._update_move_types + + def is_depreciation_nr_required(self): + """ Defines if a line requires to be numbered """ + self.ensure_one() + return self.move_type in self.get_numbered_move_types() \ + and not self.partial_dismissal + + def make_name(self): + self.ensure_one() + return "{} ({})".format(self.name, self.depreciation_id.make_name()) + + def need_normalize_depreciation_nr(self): + """ Check if numbers need to be normalized """ + dep = self.mapped('depreciation_id') + dep.ensure_one() + + if dep.force_all_dep_nr: + return False + + lines = dep.line_ids.filtered('requires_depreciation_nr').sorted() + if not lines: + return False + + first_line = lines[0] + + if dep.force_first_dep_nr and dep.first_dep_nr: + if first_line.depreciation_nr != dep.first_dep_nr: + return True + + if not dep.force_first_dep_nr: + if first_line.depreciation_nr != 1: + return True + + nrs = tuple(lines.mapped('depreciation_nr') or [0]) + if min(nrs) <= 0: + return True + + expected_nrs = tuple([x for x in range(min(nrs), max(nrs) + 1)]) + if nrs != expected_nrs: + return True + + return False + + def normalize_depreciation_nr(self, force=False): + """ + Normalize depreciation numbers to be consecutive for depreciation + and historical lines within the same depreciation set; force to 0 + every non-depreciation line. + :param force: force normalization for every depreciations' lines + """ + for dep in self.mapped('depreciation_id'): + + # Avoid if user chooses to use custom numbers + if dep.force_all_dep_nr: + continue + + num_lines = dep.line_ids.filtered('requires_depreciation_nr') + if force or num_lines.need_normalize_depreciation_nr(): + nr_dict = num_lines.get_depreciation_nr_dict() + for num_line, nr in nr_dict.items(): + if num_line.depreciation_nr != nr: + num_line.depreciation_nr = nr + (dep.line_ids - num_lines).update({'depreciation_nr': 0}) + + ########################################################################## + # # + # ACCOUNT MOVE CREATING METHODS # + # # + ########################################################################## + + @api.multi + def button_generate_account_move(self): + self.generate_account_move() + + @api.multi + def button_regenerate_account_move(self): + self.button_remove_account_move() + self.generate_account_move() + + @api.multi + def button_remove_account_move(self): + self.mapped('move_id').unlink() + + def generate_account_move(self): + for line in self.filtered(lambda l: l.needs_account_move()): + line.generate_account_move_single() + + def generate_account_move_single(self): + self.ensure_one() + am_obj = self.env['account.move'] + + vals = self.get_account_move_vals() + if 'line_ids' not in vals: + vals['line_ids'] = [] + + line_vals = self.get_account_move_line_vals() + for v in line_vals: + vals['line_ids'].append((0, 0, v)) + + self.move_id = am_obj.create(vals) + + def get_account_move_vals(self): + self.ensure_one() + return { + 'company_id': self.company_id.id, + 'date': self.date, + 'journal_id': self.asset_id.category_id.journal_id.id, + 'line_ids': [], + 'ref': _("Asset: ") + self.asset_id.make_name(), + } + + def get_account_move_line_vals(self): + """ Switcher between methods """ + method = self.get_account_move_line_vals_methods().get(self.move_type) + if not method: + raise NotImplementedError( + _("Cannot create account move lines: no method is specified.") + ) + + return method() + + def get_account_move_line_vals_methods(self): + """ + Maps line `move_type` to its own method for generating move lines. + """ + return { + t: getattr(self, 'get_{}_account_move_line_vals'.format(t), False) + for t in dict(self._fields['move_type'].selection).keys() + } + + def get_depreciated_account_move_line_vals(self): + self.ensure_one() + + # Asset depreciation + if not self.partial_dismissal: + credit_account_id = self.asset_id.category_id.fund_account_id.id + debit_account_id = self.asset_id.category_id \ + .depreciation_account_id.id + + # Asset partial dismissal + else: + debit_account_id = self.asset_id.category_id.fund_account_id.id + credit_account_id = self.asset_id.category_id\ + .asset_account_id.id + + amt = abs(self.amount) + credit_line_vals = { + 'account_id': credit_account_id, + 'credit': amt, + 'debit': 0.0, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + debit_line_vals = { + 'account_id': debit_account_id, + 'credit': 0.0, + 'debit': amt, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + return [credit_line_vals, debit_line_vals] + + def get_gain_account_move_line_vals(self): + self.ensure_one() + credit_line_vals = { + 'account_id': self.asset_id.category_id.gain_account_id.id, + 'credit': self.amount, + 'debit': 0.0, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + debit_line_vals = { + 'account_id': self.asset_id.category_id.asset_account_id.id, + 'credit': 0.0, + 'debit': self.amount, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + return [credit_line_vals, debit_line_vals] + + def get_historical_account_move_line_vals(self): + raise NotImplementedError( + _("Cannot create account move lines for lines of type" + " `Historical`") + ) + + def get_in_account_move_line_vals(self): + raise NotImplementedError( + _("Cannot create account move lines for lines of type `In`") + ) + + def get_loss_account_move_line_vals(self): + self.ensure_one() + credit_line_vals = { + 'account_id': self.asset_id.category_id.asset_account_id.id, + 'credit': self.amount, + 'debit': 0.0, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + debit_line_vals = { + 'account_id': self.asset_id.category_id.loss_account_id.id, + 'credit': 0.0, + 'debit': self.amount, + 'currency_id': self.currency_id.id, + 'name': " - ".join((self.asset_id.make_name(), self.name)), + } + return [credit_line_vals, debit_line_vals] + + def get_out_account_move_line_vals(self): + raise NotImplementedError( + _("Cannot create account move lines for lines of type `Out`") + ) + + def needs_account_move(self): + self.ensure_one() + return self.requires_account_move and not self.move_id and self.amount + + def post_dismiss_asset(self): + dep = self.mapped('depreciation_id') + dep.ensure_one() + types = ('gain', 'loss') + gain_or_loss = self.filtered( + lambda l: l.needs_account_move() and l.move_type in types + ) + if gain_or_loss: + gain_or_loss.generate_account_move_single() + dep.generate_dismiss_account_move() + + def post_partial_dismiss_asset(self): + dep = self.mapped('depreciation_id') + dep.ensure_one() + types = ('depreciated', 'gain', 'loss') + to_create_move = self.filtered( + lambda l: l.needs_account_move() and l.move_type in types + ) + if to_create_move: + to_create_move.generate_account_move() diff --git a/assets_management/models/asset_depreciation_line_type.py b/assets_management/models/asset_depreciation_line_type.py new file mode 100644 index 000000000000..3d1ea579f8fe --- /dev/null +++ b/assets_management/models/asset_depreciation_line_type.py @@ -0,0 +1,66 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class DepLineType(models.Model): + _name = 'asset.depreciation.line.type' + _description = "Depreciation Line Type" + _table = 'asset_dep_line_type' + _order = 'name asc, code asc' + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + code = fields.Char( + string="Code" + ) + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + string="Company" + ) + + name = fields.Char( + required=True, + string="Name" + ) + + type = fields.Selection( + [('in', 'In'), + ('out', 'Out')], + string="Type", + ) + + @api.multi + def unlink(self): + for line_type in self: + if self.env['asset.depreciation.line'].search([ + ('depreciation_line_type_id', '=', line_type.id) + ]): + raise ValidationError( + _("Cannot remove type {}: there is some depreciation" + " line linked to it.".format(line_type.name)) + ) + + return super().unlink() + + @api.multi + def name_get(self): + return [(line_type.id, line_type.make_name()) for line_type in self] + + def make_name(self): + self.ensure_one() + name = "" + if self.code: + name += "[{}] ".format(self.code) + name += self.name + type_name = dict(self._fields['type'].selection).get(self.type) + if type_name: + name += " - " + type_name + return name.strip() diff --git a/assets_management/models/asset_depreciation_mode.py b/assets_management/models/asset_depreciation_mode.py new file mode 100644 index 000000000000..5e9a57e1e419 --- /dev/null +++ b/assets_management/models/asset_depreciation_mode.py @@ -0,0 +1,104 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class AssetDepreciationMode(models.Model): + _name = 'asset.depreciation.mode' + _description = "Asset Depreciation Mode" + _order = 'name' + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + string="Company" + ) + + default = fields.Boolean( + string="Default Mode" + ) + + line_ids = fields.One2many( + 'asset.depreciation.mode.line', + 'mode_id', + string="Lines" + ) + + name = fields.Char( + required=True, + string="Name", + ) + + used_asset_coeff = fields.Float( + default=1.0, + string="Used Asset Coeff.", + ) + + @api.multi + def copy(self, default=None): + default = dict(default or []) + default.update({ + 'default': False, + 'line_ids': [ + (0, 0, l.copy_data({'mode_id': False})[0]) + for l in self.line_ids + ] + }) + return super().copy(default) + + @api.multi + def unlink(self): + if self.env['asset.category.depreciation.type'].sudo().search([ + ('mode_id', 'in', self.ids) + ]): + raise UserError( + _("Cannot delete depreciation modes while they're still linked" + " to categories.") + ) + if self.env['asset.depreciation'].sudo().search([ + ('mode_id', 'in', self.ids) + ]): + raise UserError( + _("Cannot delete depreciation modes while they're still linked" + " to depreciations.") + ) + return super().unlink() + + @api.constrains('company_id', 'default') + def check_default_modes(self): + for company in self.mapped('company_id'): + domain = [ + ('company_id', '=', company.id), + ('default', '=', True) + ] + if self.search_count(domain) > 1: + raise ValidationError( + _("There can be no more than 1 default depreciation mode" + " for each company.") + ) + + def get_depreciation_amount_multiplier(self): + multiplier = 1 + if not self: + return multiplier + + self.ensure_one() + + # Update multiplier from used asset coefficient + used_asset = self._context.get('used_asset', False) + if self.used_asset_coeff and used_asset: + multiplier *= self.used_asset_coeff + + # Update multiplier from lines + lines = self.line_ids + if lines: + multiplier *= lines.get_depreciation_amount_multiplier() + + return multiplier diff --git a/assets_management/models/asset_depreciation_mode_line.py b/assets_management/models/asset_depreciation_mode_line.py new file mode 100644 index 000000000000..78a24fec1071 --- /dev/null +++ b/assets_management/models/asset_depreciation_mode_line.py @@ -0,0 +1,83 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class AssetDepreciationModeLine(models.Model): + _name = 'asset.depreciation.mode.line' + _description = "Asset Depreciation Mode Line" + _order = 'from_nr asc, to_nr asc' + + application = fields.Selection( + [('coefficient', 'Coefficient'), + ('percentage', 'Percentage')], + default='coefficient', + required=True, + string="Application by", + ) + + coefficient = fields.Float( + string="Coefficient", + ) + + company_id = fields.Many2one( + 'res.company', + readonly=True, + related='mode_id.company_id', + string="Company" + ) + + from_nr = fields.Integer( + required=True, + string="From Nr", + ) + + mode_id = fields.Many2one( + 'asset.depreciation.mode', + ondelete='cascade', + required=True, + readonly=True, + string="Mode", + ) + + percentage = fields.Float( + string="Percentage" + ) + + to_nr = fields.Integer( + string="To Nr", + ) + + @api.onchange('application') + def onchange_application(self): + if self.application: + if self.application == 'coefficient': + self.percentage = 0 + elif self.application == 'percentage': + self.coefficient = 0 + else: + self.coefficient = 0 + self.percentage = 0 + + def get_depreciation_amount_multiplier(self): + multiplier = 1 + nr = self._context.get('dep_nr') + if nr is None: + # Cannot compare to any line + return multiplier + + lines = self.filtered( + lambda l: l.from_nr <= nr and (not l.to_nr or l.to_nr >= nr) + ) + if not lines: + return multiplier + + for line in lines: + if line.application == 'coefficient': + multiplier *= line.coefficient + elif line.application == 'percentage': + multiplier *= line.percentage / 100 + + return multiplier diff --git a/assets_management/models/asset_depreciation_type.py b/assets_management/models/asset_depreciation_type.py new file mode 100644 index 000000000000..facd5167022e --- /dev/null +++ b/assets_management/models/asset_depreciation_type.py @@ -0,0 +1,49 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class AssetDepreciationType(models.Model): + _name = 'asset.depreciation.type' + _description = "Asset Depreciation Type" + _order = 'name' + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + string="Company" + ) + + name = fields.Char( + required=True, + string="Name" + ) + + print_by_default = fields.Boolean( + default=True, + help="Defines whether a category should be added by default when" + " printing assets' reports.", + string="Print By Default" + ) + + requires_account_move = fields.Boolean( + string="Requires Account Move" + ) + + @api.multi + def unlink(self): + if self.env['asset.category.depreciation.type'].sudo().search([ + ('depreciation_type_id', 'in', self.ids) + ]): + raise UserError( + _("Cannot delete depreciation types while they're still used" + " by categories.") + ) + return super().unlink() diff --git a/assets_management/models/asset_tag.py b/assets_management/models/asset_tag.py new file mode 100644 index 000000000000..9175a3fda9cc --- /dev/null +++ b/assets_management/models/asset_tag.py @@ -0,0 +1,25 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class AssetTag(models.Model): + _name = 'asset.tag' + _description = "Asset Tags" + + @api.model + def get_default_company_id(self): + return self.env.user.company_id + + company_id = fields.Many2one( + 'res.company', + default=get_default_company_id, + string="Company" + ) + + name = fields.Char( + string="Name", + required=True + ) diff --git a/assets_management/readme/CONTRIBUTORS.rst b/assets_management/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..55e226cd58d7 --- /dev/null +++ b/assets_management/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Alessandro Camilli +* Silvio Gregorini +* Stefano Pezzini diff --git a/assets_management/readme/DESCRIPTION.rst b/assets_management/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..7d5424d09a35 --- /dev/null +++ b/assets_management/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This modules allows account management of companies' assets. diff --git a/assets_management/readme/USAGE.rst b/assets_management/readme/USAGE.rst new file mode 100644 index 000000000000..c0c9c24e2e73 --- /dev/null +++ b/assets_management/readme/USAGE.rst @@ -0,0 +1,25 @@ +**English** + +You can create and manage assets from accounting section of Odoo. + +Configuration must be done from Invoicing -> Assets -> Assets Configuration, +where depreciation types, modes and assets categories can be found. + +Assets can both be created manually or via invoices and journal entries. +Depreciations can be generated by using the related wizard found in Assets -> +Generate Depreciations, or by triggering the same wizard from a single asset +form view. + + +**Italiano** + +È possibile creare e gestire cespiti dalla sezione contabilità di Odoo. + +La configurazione dei cespiti dev'essere fatta andando in Fatturazione -> +Cespiti -> Configurazione Cespiti, dove si trovano le categorie dei beni, i +tipi e le modalità di ammortamento. + +I cespiti possono essere creati manualmente o da fatture e registrazioni +contabili. Gli ammortamenti possono essere generati utilizzando l'apposito +wizard in Cespiti -> Genera Ammortamenti, o aprendo quello stesso wizard dalla +scheda del cespite diff --git a/assets_management/report/__init__.py b/assets_management/report/__init__.py new file mode 100644 index 000000000000..96d7545e5369 --- /dev/null +++ b/assets_management/report/__init__.py @@ -0,0 +1,8 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import asset_journal +from . import asset_journal_xlsx +from . import asset_previsional +from . import asset_previsional_xlsx diff --git a/assets_management/report/asset_journal.py b/assets_management/report/asset_journal.py new file mode 100644 index 000000000000..c616ba21d8ae --- /dev/null +++ b/assets_management/report/asset_journal.py @@ -0,0 +1,932 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from collections import OrderedDict + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools.pycompat import string_types +from odoo.tools.safe_eval import safe_eval + +from odoo.addons.mail.models.mail_template import format_amount + + +def format_date(rec, field_name, fmt): + """ Formats record's field value according to given format `fmt` """ + if not rec[field_name]: + return '' + return rec._fields[field_name].from_string(rec[field_name]).strftime(fmt) + + +class Report(models.TransientModel): + """ + This report has the following structure: + * Report (which is just a data container) + ** Category + *** Asset + **** Depreciation + ***** Depreciation Line by Year + Each class is set to be linked via a M2O to its parent class, and via + a O2M to its child class. + Each class is linked to Report via `report_id` field. + Asset and Depreciation Line by Year both have a relation to the section + Accounting Data which stores sale/purchase data. + """ + _name = 'report_asset_journal' + _inherit = 'account_financial_report_abstract' + + # Data fields + asset_ids = fields.Many2many( + 'asset.asset', + ) + + asset_order_fname = fields.Char() + + category_ids = fields.Many2many( + 'asset.category', + ) + + company_id = fields.Many2one( + 'res.company', + ) + + date = fields.Date() + + show_totals = fields.Boolean() + + show_category_totals = fields.Boolean() + + type_ids = fields.Many2many( + 'asset.depreciation.type', + ) + + # Report structure fields + report_category_ids = fields.One2many( + 'report_asset_journal_category', + 'report_id' + ) + + report_asset_ids = fields.One2many( + 'report_asset_journal_asset', + 'report_id' + ) + + report_depreciation_ids = fields.One2many( + 'report_asset_journal_depreciation', + 'report_id' + ) + + report_depreciation_line_year_ids = fields.One2many( + 'report_asset_journal_depreciation_line_year', + 'report_id' + ) + + report_total_ids = fields.One2many( + 'report_asset_journal_totals', + 'report_id' + ) + + # Fields to be printed + report_footer_year = fields.Char() + report_name = fields.Char() + + ############################ + # # + # REPORT RENDERING METHODS # + # # + ############################ + + @api.multi + def print_report(self, report_type=None): + """ + This method is called from the JS widget buttons 'Print' + and 'Export' in the HTML view. + Prints PDF and XLSX reports. + :param report_type: string that represents the report type + """ + self.ensure_one() + report_type = report_type or 'qweb-pdf' + if report_type in ('qweb-pdf', 'xlsx'): + res = self.do_print(report_type) + elif report_type == 'qweb-html': + res = self.view_report() + elif report_type: + raise ValidationError( + _("No report has been defined for type `{}`.") + .format(report_type) + ) + else: + raise ValidationError( + _("No report type has been declared for current print.") + ) + return res + + def do_print(self, report_type): + self.ensure_one() + if report_type == 'qweb-pdf': + xml_id = 'assets_management.report_asset_journal_pdf' + else: + xml_id = 'assets_management.report_asset_journal_xlsx' + report = self.env.ref(xml_id) + return report.report_action(self) + + @api.multi + def view_report(self): + """ Launches view for HTML report """ + self.ensure_one() + xmlid = 'assets_management.act_client_asset_journal_report' + [act] = self.env.ref(xmlid).read() + ctx = act.get('context', {}) + if isinstance(ctx, string_types): + ctx = safe_eval(ctx) + # Call update twice to force 'active_id(s)' values to be overridden + ctx.update(dict(self._context)) + ctx.update(active_id=self.id, active_ids=self.ids) + act['context'] = ctx + return act + + @api.model + def get_html(self, given_context=None): + """ Method needed from JavaScript widget to render HTML view """ + context = dict(self.env.context) + context.update(given_context or {}) + report = self or self.browse(context.get('active_id')) + xml_id = 'assets_management.template_asset_journal_report' + + result = {} + if report: + context['o'] = report + result['html'] = self.env.ref(xml_id).render(context) + return result + + ########################### + # # + # REPORT CREATION METHODS # + # # + ########################### + + def compute_data_for_report(self): + """ Compute data to be printed """ + self.set_report_name() + self.generate_structure() + self.generate_data() + + def generate_data(self): + self.report_category_ids.generate_data() + self.report_asset_ids.generate_data() + self.report_depreciation_ids.generate_data() + self.report_depreciation_line_year_ids.generate_data() + self.report_category_ids.generate_totals() + self.generate_totals() + + def generate_structure(self): + deps = self.get_depreciations() + dep_lines = deps.mapped('line_ids') + assets = deps.mapped('asset_id') + if self.date: + assets = assets.filtered( + lambda a: not a.purchase_date or a.purchase_date <= self.date + ) + dep_lines = dep_lines.filtered(lambda dl: dl.date <= self.date) + categories = assets.mapped('category_id') + + if not (categories and assets and deps and dep_lines): + raise ValidationError( + _("There is nothing to print according to current settings!") + ) + + dep_lines_grouped = OrderedDict() + fiscal_year = self.env['account.fiscal.year'] + for dep_line in dep_lines.sorted('date'): + dep = dep_line.depreciation_id + fyear = fiscal_year.get_fiscal_year_by_date( + dep_line.date, company=dep_line.company_id + ) + key = (dep, fyear) + if key not in dep_lines_grouped: + dep_lines_grouped[key] = self.env['asset.depreciation.line'] + dep_lines_grouped[key] += dep_line + + self.write({ + 'report_category_ids': [ + (0, 0, {'category_id': c.id, 'report_id': self.id}) + for c in categories.sorted('name') + ] + }) + for report_categ in self.report_category_ids: + report_categ.write({ + 'report_asset_ids': [ + (0, 0, {'asset_id': a.id, 'report_id': self.id}) + for a in self.sort_assets(assets) + if a.category_id == report_categ.category_id + ] + }) + for report_asset in self.report_asset_ids: + report_asset.write({ + 'report_depreciation_ids': [ + (0, 0, {'depreciation_id': d.id, 'report_id': self.id}) + for d in deps + if d.asset_id == report_asset.asset_id + ] + }) + for report_dep in self.report_depreciation_ids: + sequence = 0 + for (dep, fyear), lines in dep_lines_grouped.items(): + if dep == report_dep.depreciation_id: + sequence += 1 + report_dep.write({ + 'report_depreciation_year_line_ids': [ + (0, 0, {'dep_line_ids': [(6, 0, lines.ids)], + 'fiscal_year_id': fyear.id, + 'report_id': self.id, + 'sequence': sequence}) + ] + }) + + def generate_totals(self): + curr = self.company_id.currency_id + categ_totals = self.report_category_ids.mapped('report_total_ids') + fnames = self.env['report_asset_journal_totals']._total_fnames + totals_by_dep_type = { + t: {fname: 0 for fname in fnames} + for t in categ_totals.mapped('type_id') + } + for total in categ_totals: + total_curr = total.get_currency() + total_type = total.type_id + for fname in fnames: + totals_by_dep_type[total_type][fname] += \ + total_curr.compute(total[fname], curr) + self.write({ + 'report_total_ids': [ + (0, 0, dict( + v, + name=_("General Total"), + type_name=t.name_get()[0][-1], + type_id=t.id + )) + for t, v in totals_by_dep_type.items() + ] + }) + + def get_depreciations(self): + domain = [] + if self.asset_ids: + domain += [('asset_id', 'in', self.asset_ids.ids)] + if self.category_ids: + domain += [('asset_id.category_id', 'in', self.category_ids.ids)] + if self.company_id: + domain += [('company_id', '=', self.company_id.id)] + if self.date: + domain += [('date_start', '<=', self.date)] + if self.type_ids: + domain += [('type_id', 'in', self.type_ids.ids)] + return self.env['asset.depreciation'].search(domain) + + def set_report_name(self): + report_name = _("Assets Depreciations ") + if self.date: + report_name += _("to date {}").format( + format_date(self, 'date', '%d-%m-%Y') + ) + self.report_name = report_name.strip() + + def sort_assets(self, assets): + sortable_assets = assets.filtered(self.asset_order_fname) + sorted_assets = sortable_assets.sorted(self.asset_order_fname) \ + + (assets - sortable_assets).sorted() + return sorted_assets + + +class ReportCategory(models.TransientModel): + _name = 'report_asset_journal_category' + _inherit = 'account_financial_report_abstract' + + # Data fields + category_id = fields.Many2one( + 'asset.category', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + report_asset_ids = fields.One2many( + 'report_asset_journal_asset', + 'report_category_id' + ) + + report_total_ids = fields.One2many( + 'report_asset_journal_totals', + 'report_category_id' + ) + + # Fields to be printed + category_name = fields.Char() + + def generate_data(self): + for report_categ in self: + report_categ.write(report_categ.get_report_categ_data()) + + def get_report_categ_data(self): + self.ensure_one() + return {'category_name': self.category_id.name} + + def generate_totals(self): + for categ in self: + curr = categ.report_id.company_id.currency_id + report_date = categ.report_id.date + report_deps = categ.report_asset_ids\ + .mapped('report_depreciation_ids') + fnames = categ.env['report_asset_journal_totals']._total_fnames + totals_by_dep_type = { + t: {fname: 0 for fname in fnames} + for t in report_deps.mapped('depreciation_id.type_id') + } + for report_dep in report_deps.filtered( + 'report_depreciation_year_line_ids' + ): + dep_type = report_dep.depreciation_id.type_id + last_line = report_dep.report_depreciation_year_line_ids[-1] + line_curr = last_line.get_currency() + fy_start = last_line.fiscal_year_id.date_from + fy_end = last_line.fiscal_year_id.date_to + for fname in fnames: + if fname == 'amount_depreciation_fund_prev_year': + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + elif fname in ( + 'amount_in_total', + 'amount_out_total', + 'gain_loss_total' + ): + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + elif report_date < fy_start: + totals_by_dep_type[dep_type][fname] = 0 + elif fname == 'amount_depreciated': + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + else: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + categ.write({ + 'report_total_ids': [ + (0, 0, dict( + v, + name=categ.category_id.name_get()[0][-1], + type_name=t.name_get()[0][-1], + type_id=t.id + )) + for t, v in totals_by_dep_type.items() + ] + }) + + +class ReportAsset(models.TransientModel): + _name = 'report_asset_journal_asset' + _inherit = 'account_financial_report_abstract' + + # Data fields + asset_id = fields.Many2one( + 'asset.asset', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + report_category_id = fields.Many2one( + 'report_asset_journal_category' + ) + + report_depreciation_ids = fields.One2many( + 'report_asset_journal_depreciation', + 'report_asset_id' + ) + + report_purchase_doc_id = fields.Many2one( + 'report_asset_journal_accounting_doc', + ) + + report_sale_doc_id = fields.Many2one( + 'report_asset_journal_accounting_doc', + ) + + # Fields to be printed + asset_code = fields.Char() + asset_name = fields.Char() + asset_purchase_amount = fields.Float() + asset_state = fields.Char() + asset_used = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_asset in self: + report_asset.write(report_asset.get_report_asset_data()) + + def get_currency(self): + self.ensure_one() + return self.asset_id.currency_id + + def get_report_asset_data(self): + self.ensure_one() + asset = self.asset_id + states_dict = dict(asset._fields['state'].selection) + + vals = { + 'asset_code': asset.code or "/", + 'asset_name': asset.name, + 'asset_purchase_amount': asset.purchase_amount, + 'asset_state': states_dict.get(asset.state) or _("Unknown"), + 'asset_used': _("Used") if asset.used else _("New"), + } + + acc_doc = self.env['report_asset_journal_accounting_doc'] + purchase_vals = self.get_purchase_vals() + if purchase_vals: + vals.update({ + 'report_purchase_doc_id': acc_doc.create(purchase_vals).id, + }) + + sale_vals = self.get_sale_vals() + if sale_vals: + vals.update({ + 'report_sale_doc_id': acc_doc.create(sale_vals).id, + }) + + return vals + + def get_purchase_vals(self): + asset = self.asset_id + purchase_vals = { + 'partner_name': asset.supplier_id.name or "/", + 'partner_vat': asset.supplier_id.vat or "/", + } + + if asset.purchase_date: + purchase_vals['document_date'] = format_date( + asset, 'purchase_date', '%d-%m-%Y' + ) + + if asset.supplier_ref: + purchase_vals['partner_ref'] = asset.supplier_ref + elif asset.purchase_invoice_id.reference: + purchase_vals['partner_ref'] = asset.purchase_invoice_id.reference + elif asset.purchase_move_id.ref: + purchase_vals['partner_ref'] = asset.purchase_move_id.ref + else: + purchase_vals['partner_ref'] = "/" + + if asset.purchase_invoice_id: + purchase_vals.update({ + 'document_nr': asset.purchase_invoice_id.number or "/", + 'res_id': asset.purchase_invoice_id.id, + 'res_model': 'account.invoice', + }) + elif asset.purchase_move_id: + purchase_vals.update({ + 'document_nr': asset.purchase_move_id.name or "/", + 'res_id': asset.purchase_move_id.id, + 'res_model': 'account.move', + }) + else: + purchase_vals.update({ + 'document_nr': "/", + 'res_id': asset.id, + 'res_model': 'asset.asset', + }) + + return purchase_vals + + def get_sale_vals(self): + asset = self.asset_id + if not asset.sale_date or asset.sale_date > self.report_id.date: + return {} + + sale_vals = { + 'document_date': format_date(asset, 'sale_date', '%d-%m-%Y'), + 'partner_name': asset.customer_id.name, + 'partner_vat': asset.customer_id.vat or "/", + } + + if asset.sale_invoice_id: + sale_vals.update({ + 'document_nr': asset.sale_invoice_id.number or "/", + 'res_id': asset.sale_invoice_id.id, + 'res_model': 'account.invoice', + }) + elif asset.sale_move_id: + sale_vals.update({ + 'document_nr': asset.sale_move_id.name or "/", + 'res_id': asset.sale_move_id.id, + 'res_model': 'account.move', + }) + else: + sale_vals.update({ + 'document_nr': "/", + 'res_id': asset.id, + 'res_model': 'asset.asset', + }) + return sale_vals + + +class ReportDepreciation(models.TransientModel): + _name = 'report_asset_journal_depreciation' + _inherit = 'account_financial_report_abstract' + _order = 'type_name asc' + + # Data fields + depreciation_id = fields.Many2one( + 'asset.depreciation', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + report_asset_id = fields.Many2one( + 'report_asset_journal_asset' + ) + + report_depreciation_year_line_ids = fields.One2many( + 'report_asset_journal_depreciation_line_year', + 'report_depreciation_id' + ) + + # Fields to be printed + dep_amount_depreciable = fields.Float() + dep_date_start = fields.Char() + dep_percentage = fields.Float() + dep_pro_rata_temporis = fields.Char() + mode_name = fields.Char() + type_name = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_dep in self: + report_dep.write(report_dep.get_report_dep_data()) + + def get_currency(self): + self.ensure_one() + return self.depreciation_id.currency_id + + def get_report_dep_data(self): + self.ensure_one() + dep = self.depreciation_id + if dep.pro_rata_temporis: + dep_pro_rata_temporis = u"\u2612" # checked ballot box -> ☒ + else: + dep_pro_rata_temporis = u"\u2610" # empty ballot box -> ☐ + + return { + 'dep_amount_depreciable': dep.amount_depreciable, + 'dep_date_start': format_date(dep, 'date_start', '%d-%m-%Y'), + 'dep_percentage': dep.percentage, + 'dep_pro_rata_temporis': dep_pro_rata_temporis, + 'mode_name': dep.mode_id.name_get()[0][-1] if dep.mode_id else "", + 'type_name': dep.type_id.name_get()[0][-1] if dep.type_id else "" + } + + +class ReportDepreciationLineByYear(models.TransientModel): + _name = 'report_asset_journal_depreciation_line_year' + _inherit = 'account_financial_report_abstract' + _order = 'sequence asc' + + # Data fields + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + relation='report_journal_line_year_dep_line' + ) + + fiscal_year_id = fields.Many2one( + 'account.fiscal.year' + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + report_depreciation_id = fields.Many2one( + 'report_asset_journal_depreciation' + ) + + report_accounting_doc_ids = fields.Many2many( + 'report_asset_journal_accounting_doc', + relation='year_dep_line_accounting_doc_rel' + ) + + sequence = fields.Integer() + + # Fields to be printed + amount_depreciable = fields.Float() + amount_depreciable_updated = fields.Float() + amount_depreciated = fields.Float() + amount_depreciation_fund_curr_year = fields.Float() + amount_depreciation_fund_prev_year = fields.Float() + amount_gain = fields.Float() + amount_gain_total = fields.Float() + amount_historical = fields.Float() + amount_in = fields.Float() + amount_in_detail = fields.Char() + amount_in_total = fields.Float() + amount_loss = fields.Float() + amount_loss_total = fields.Float() + amount_out = fields.Float() + amount_out_detail = fields.Char() + amount_out_total = fields.Float() + amount_residual = fields.Float() + date_start = fields.Char() + gain_loss = fields.Float() # Needed for the .xls report + gain_loss_total = fields.Float() # Needed for the .xls report + has_amount_detail = fields.Boolean() + percentage = fields.Float() + year = fields.Char() + type_name = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_dep_line_year in self.sorted(): # Force sorting by _order + report_dep_line_year.write( + report_dep_line_year.get_report_dep_line_year_data() + ) + + def get_currency(self): + self.ensure_one() + return self.report_depreciation_id.depreciation_id.currency_id + + def get_report_dep_line_year_data(self): + self.ensure_one() + report_dep = self.report_depreciation_id + grouped_amounts = self.dep_line_ids.get_balances_grouped() + + amount_depreciable = report_dep.dep_amount_depreciable + amount_gain = grouped_amounts.get('gain') or 0.0 + amount_gain_total = amount_gain + amount_historical = abs(grouped_amounts.get('historical') or 0.0) + amount_in = abs(grouped_amounts.get('in') or 0.0) + amount_in_total = amount_in + amount_loss = grouped_amounts.get('loss') or 0.0 + amount_loss_total = amount_loss + amount_out = abs(grouped_amounts.get('out') or 0.0) + amount_out_total = amount_out + gain_loss = amount_gain + amount_loss + gain_loss_total = gain_loss + + amount_depreciated = sum([ + line.amount + for line in self.dep_line_ids.filtered( + lambda l: l.move_type == 'depreciated' + and not l.partial_dismissal + ) + ]) + amount_dismissal = sum([ + line.amount + for line in self.dep_line_ids.filtered( + lambda l: l.move_type == 'depreciated' + and l.partial_dismissal + ) + ]) + + prev_year_line = report_dep.report_depreciation_year_line_ids.filtered( + lambda l: l.sequence == self.sequence - 1 + ) + asset = self.report_depreciation_id.report_asset_id.asset_id + fy_start = self.fiscal_year_id.date_from + fy_end = self.fiscal_year_id.date_to + if asset.sold and asset.sale_date \ + and fy_start <= asset.sale_date <= fy_end: + amount_depreciable_upd = 0.0 + depreciation_fund_curr_year = 0.0 + amount_residual = 0.0 + if prev_year_line: + depreciation_fund_prev_year = prev_year_line\ + .amount_depreciation_fund_curr_year + amount_in_total += prev_year_line.amount_in_total + amount_out_total += prev_year_line.amount_out_total + else: + depreciation_fund_prev_year = 0.0 + else: + if prev_year_line: + depreciation_fund_prev_year = prev_year_line\ + .amount_depreciation_fund_curr_year + prev_year_resid = prev_year_line.amount_residual + amount_depreciable_upd = prev_year_line.\ + amount_depreciable_updated + amount_in - amount_out + amount_in_total += prev_year_line.amount_in_total + amount_out_total += prev_year_line.amount_out_total + else: + depreciation_fund_prev_year = 0.0 + prev_year_resid = amount_depreciable + amount_depreciable_upd = amount_depreciable + amount_in \ + - amount_out + + depreciation_fund_curr_year = depreciation_fund_prev_year \ + + amount_depreciated + amount_dismissal + amount_residual = prev_year_resid + amount_in - amount_out \ + - amount_depreciated - amount_dismissal + if prev_year_line: + amount_gain_total += prev_year_line.amount_gain_total + amount_loss_total += prev_year_line.amount_loss_total + gain_loss_total += prev_year_line.gain_loss_total + + type_mapping = {'in': {}, 'out': {}} + for dep_line in self.dep_line_ids.filtered( + lambda l: l.move_type in ('in', 'out') + and l.depreciation_line_type_id + ): + dep_type = dep_line.depreciation_line_type_id + if dep_type not in type_mapping[dep_line.move_type]: + type_mapping[dep_line.move_type][dep_type] = 0 + type_mapping[dep_line.move_type][dep_type] += dep_line.amount + + amount_in_detail = amount_out_detail = "" + has_amount_detail = False + if type_mapping['in']: + amount_in_detail = "; ".join([ + "{}: {}".format(dep_type.name, self.format_amount(amount)) + for dep_type, amount in sorted(list( + type_mapping['in'].items())) + ]) + has_amount_detail = True + if type_mapping['out']: + amount_out_detail = "; ".join([ + "{}: {}".format(dep_type.name, self.format_amount(amount)) + for dep_type, amount in sorted(list( + type_mapping['out'].items())) + ]) + has_amount_detail = True + + accounting_doc_vals = [] + for dep_line in self.dep_line_ids.filtered( + lambda l: l.move_type in ('in', 'out') + ): + for num, aa_info in enumerate(dep_line.asset_accounting_info_ids): + vals = {} + if aa_info.invoice_line_id: + inv = aa_info.invoice_line_id.invoice_id + vals = { + 'document_date': format_date( + dep_line, 'date', '%d-%m-%Y' + ), + 'document_nr': inv.number or "/", + 'partner_name': inv.partner_id.name or "/", + 'partner_ref': inv.reference or "/", + 'partner_vat': inv.partner_id.vat or "/", + 'res_id': inv.id, + 'res_model': 'account.invoice', + 'sequence': num + 1, + } + elif aa_info.move_id: + move = aa_info.move_id + vals = { + 'document_date': format_date( + dep_line, 'date', '%d-%m-%Y' + ), + 'document_nr': move.name or "/", + 'partner_name': move.partner_id.name or "/", + 'partner_ref': move.ref or "/", + 'partner_vat': move.partner_id.vat or "/", + 'res_id': move.id, + 'res_model': 'account.move', + 'sequence': num + 1, + } + if vals: + accounting_doc_vals.append((0, 0, vals)) + + start = fields.Date.from_string(self.fiscal_year_id.date_from).year + end = fields.Date.from_string(self.fiscal_year_id.date_to).year + if start == end: + year = str(start) + else: + year = "{} - {}".format(start, end) + + return { + 'amount_depreciable': amount_depreciable, + 'amount_depreciable_updated': amount_depreciable_upd, + 'amount_depreciated': amount_depreciated, + 'amount_depreciation_fund_curr_year': depreciation_fund_curr_year, + 'amount_depreciation_fund_prev_year': depreciation_fund_prev_year, + 'amount_gain': amount_gain, + 'amount_historical': amount_historical, + 'amount_in': amount_in, + 'amount_in_detail': amount_in_detail, + 'amount_in_total': amount_in_total, + 'amount_loss': amount_loss, + 'amount_out': amount_out, + 'amount_out_detail': amount_out_detail, + 'amount_out_total': amount_out_total, + 'amount_residual': amount_residual, + 'date_start': report_dep.dep_date_start, + 'gain_loss': gain_loss, + 'gain_loss_total': gain_loss_total, + 'has_amount_detail': has_amount_detail, + 'percentage': report_dep.dep_percentage, + 'report_accounting_doc_ids': accounting_doc_vals, + 'type_name': report_dep.type_name, + 'year': year, + } + + +class ReportAccountingDoc(models.TransientModel): + _name = 'report_asset_journal_accounting_doc' + _inherit = 'account_financial_report_abstract' + _order = 'sequence asc' + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + # Fields to be printed + document_date = fields.Char() + document_nr = fields.Char() + partner_name = fields.Char() + partner_ref = fields.Char() + partner_vat = fields.Char() + res_id = fields.Integer() + res_model = fields.Char() + sequence = fields.Integer() + + +class ReportTotals(models.TransientModel): + _name = 'report_asset_journal_totals' + _inherit = 'account_financial_report_abstract' + _total_fnames = [ + 'amount_depreciable_updated', + 'amount_depreciated', + 'amount_depreciation_fund_curr_year', + 'amount_depreciation_fund_prev_year', + 'amount_gain', + 'amount_in_total', + 'amount_loss', + 'amount_out_total', + 'amount_residual', + 'gain_loss_total', + ] + + # Data fields + type_id = fields.Many2one( + 'asset.depreciation.type', + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_journal', + ) + + report_category_id = fields.Many2one( + 'report_asset_journal_category' + ) + + # Fields to be printed + amount_depreciable_updated = fields.Float() + amount_depreciated = fields.Float() + amount_depreciation_fund_curr_year = fields.Float() + amount_depreciation_fund_prev_year = fields.Float() + amount_gain = fields.Float() + amount_in_total = fields.Float() + amount_loss = fields.Float() + amount_out_total = fields.Float() + amount_residual = fields.Float() + gain_loss = fields.Float() # Needed for the .xls report + gain_loss_total = fields.Float() # Needed for the .xls report + name = fields.Char() # Needed for the .xls report + type_name = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def get_currency(self): + self.ensure_one() + report = self.report_id or self.report_category_id.report_id + return report.company_id.currency_id diff --git a/assets_management/report/asset_journal_xlsx.py b/assets_management/report/asset_journal_xlsx.py new file mode 100644 index 000000000000..6479fa385d1a --- /dev/null +++ b/assets_management/report/asset_journal_xlsx.py @@ -0,0 +1,553 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from odoo import _, models + +_logger = logging.getLogger(__name__) + + +class AssetJournalXslx(models.AbstractModel): + _name = 'report.assets_management.report_asset_journal_xlsx' + _inherit = 'report.account_financial_report.abstract_report_xlsx' + + def __init__(self, pool, cr): + """ Adds new attributes """ + super().__init__(pool, cr) + + # Add report objects + self.workbook = None + self.data = None + self.report = None + + # These `_data`s here are made as dict of dicts, the key being the + # column number to be printed into, the second one the field datas for + # the print itself + self.category_data = None + self.asset_data = None + self.asset_accounting_doc_data = None + self.depreciation_data = None + self.depreciation_line_year_data = None + self.depreciation_line_amount_detail_data = None + self.depreciation_line_accounting_doc_data = None + self.totals_data = None + + # 1- Category formats + self.format_category_name = None + + # 2- Asset formats (purchase and sale docs will use the same format) + self.format_asset_header = None + self.format_asset_value = None + + # 3- Depreciations formats + self.format_depreciation_header = None + self.format_depreciation_value = None + + # 4- Depreciation yearly and amount details formats + self.format_depreciation_year_line_header = None + self.format_depreciation_year_line_value_center = None + self.format_depreciation_year_line_value_right = None + + # 5- Report title + self.format_title = None + + def generate_xlsx_report(self, workbook, data, objects): + """ Set wb, data and report attributes """ + self.workbook = workbook + self.data = data + self.report = objects + self.set_formats() + self.set_report_data() + super().generate_xlsx_report(workbook, data, objects) + + def set_formats(self): + """ Defines custom formats """ + + # 1- Category formats + self.format_category_name = self.workbook.add_format({ + 'align': 'center', + 'bg_color': '#337AB7', + 'bold': True, + 'font_color': '#FFFFFF', + 'font_size': 16, + }) + + # 2- Asset formats + self.format_asset_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_color': '#337AB7', + 'font_size': 14, + }) + self.format_asset_value = self.workbook.add_format({ + 'align': 'center', + 'font_color': '#337AB7', + 'font_size': 14, + }) + + # 3- Depreciations formats + self.format_depreciation_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_size': 12, + }) + self.format_depreciation_value = self.workbook.add_format({ + 'align': 'center', + 'font_size': 12, + }) + + # 4- Depreciation yearly and amount details formats + self.format_depreciation_year_line_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_size': 12, + }) + self.format_depreciation_year_line_value_center = self.workbook \ + .add_format({ + 'align': 'center', + 'font_size': 12, + }) + self.format_depreciation_year_line_value_right = self.workbook \ + .add_format({ + 'align': 'right', + 'font_size': 12, + }) + + # 5- Report title + self.format_title = self.workbook.add_format({ + 'align': 'center', + 'bg_color': '#337AB7', + 'bold': True, + 'font_color': 'white', + 'font_size': 20, + }) + + def set_report_data(self): + self.set_category_data() + self.set_asset_data() + self.set_asset_accounting_doc_data() + self.set_depreciation_data() + self.set_depreciation_line_year_data() + self.set_depreciation_line_amount_detail_data() + self.set_depreciation_line_accounting_doc_data() + self.set_totals_data() + + def set_category_data(self): + self.category_data = self.generate_category_data() + + def generate_category_data(self): + data = ( + {'title': _("Category"), + 'field': 'category_name', + 'tstyle': self.format_category_name, + 'vstyle': self.format_category_name}, + ) + return dict(enumerate(data)) + + def set_asset_data(self): + self.asset_data = self.generate_asset_data() + + def generate_asset_data(self): + data = ( + {'title': _("Asset"), + 'field': 'asset_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Code"), + 'field': 'asset_code', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Purchase Amount"), + 'field': 'asset_purchase_amount', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Purchased as New / Used"), + 'field': 'asset_used', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Status"), + 'field': 'asset_state', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return dict(enumerate(data)) + + def set_asset_accounting_doc_data(self): + self.asset_accounting_doc_data = \ + self.generate_asset_accounting_doc_data() + + def generate_asset_accounting_doc_data(self): + data = ( + {'title': _("Partner"), + 'field': 'partner_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("VAT"), + 'field': 'partner_vat', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Document Nr"), + 'field': 'document_nr', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Document Date"), + 'field': 'document_date', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Supplier Ref"), + 'field': 'partner_ref', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_data(self): + self.depreciation_data = self.generate_depreciation_data() + + def generate_depreciation_data(self): + data = ( + {'title': _("Depreciation Type"), + 'field': 'type_name', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Depreciation Mode"), + 'field': 'mode_name', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Depreciable Amount"), + 'field': 'dep_amount_depreciable', + 'type': 'amount', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Starting From"), + 'field': 'dep_date_start', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Dep. Percentage (%)"), + 'field': 'dep_percentage', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Pro Rata Temporis"), + 'field': 'dep_pro_rata_temporis', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_line_year_data(self): + self.depreciation_line_year_data = \ + self.generate_depreciation_line_year_data() + + def generate_depreciation_line_year_data(self): + data = ( + {'title': _("Year"), + 'field': 'year', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Amount"), + 'field': 'amount_depreciable_updated', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("In Amount"), + 'field': 'amount_in', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Out Amount"), + 'field': 'amount_out', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Prev. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_prev_year', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Depreciation"), + 'field': 'amount_depreciated', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Curr. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_curr_year', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Gain / Loss"), + 'field': 'gain_loss', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Residual"), + 'field': 'amount_residual', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_line_amount_detail_data(self): + self.depreciation_line_amount_detail_data = \ + self.generate_depreciation_line_amount_detail_data() + + def generate_depreciation_line_amount_detail_data(self): + data = ( + {'title': _("In Amount - Detail"), + 'field': 'amount_in_detail', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Out Amount - Detail"), + 'field': 'amount_out_detail', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + ) + return {n + 3: d for n, d in enumerate(data)} + + def set_depreciation_line_accounting_doc_data(self): + self.depreciation_line_accounting_doc_data = \ + self.generate_depreciation_line_accounting_doc_data() + + def generate_depreciation_line_accounting_doc_data(self): + data = ( + {'title': _("Partner"), + 'field': 'partner_name', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("VAT"), + 'field': 'partner_vat', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Document Nr"), + 'field': 'document_nr', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Document Date"), + 'field': 'document_date', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Supplier Ref"), + 'field': 'partner_ref', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + ) + return {n + 3: d for n, d in enumerate(data)} + + def set_totals_data(self): + self.totals_data = self.get_totals_data() + + def get_totals_data(self): + data = ( + {'title': _("Total"), + 'field': 'name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Type"), + 'field': 'type_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Amount"), + 'field': 'amount_depreciable_updated', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("In Amount"), + 'field': 'amount_in_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Out Amount"), + 'field': 'amount_out_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Prev. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_prev_year', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Depreciation"), + 'field': 'amount_depreciated', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Curr. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_curr_year', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Gain / Loss"), + 'field': 'gain_loss_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Residual"), + 'field': 'amount_residual', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return {n: d for n, d in enumerate(data)} + + def _set_column_width(self): + """ Override to force every column to width 25 at least """ + max_width = self.get_max_width_dict() + for col, width in max_width.items(): + self.sheet.set_column(col, col, max(width, 25)) + + def get_max_width_dict(self): + min_col = min([ + min(self.category_data.keys()), + min(self.asset_data.keys()), + min(self.asset_accounting_doc_data.keys()), + min(self.depreciation_data.keys()), + min(self.depreciation_line_year_data.keys()), + min(self.depreciation_line_amount_detail_data.keys()), + min(self.depreciation_line_accounting_doc_data.keys()), + min(self.totals_data.keys()), + ]) + max_col = max([ + max(self.category_data.keys()), + max(self.asset_data.keys()), + max(self.asset_accounting_doc_data.keys()), + max(self.depreciation_data.keys()), + max(self.depreciation_line_year_data.keys()), + max(self.depreciation_line_amount_detail_data.keys()), + max(self.depreciation_line_accounting_doc_data.keys()), + max(self.totals_data.keys()), + ]) + + return { + col: max([ + self.category_data.get(col, {}).get('width') or 0, + self.asset_data.get(col, {}).get('width') or 0, + self.asset_accounting_doc_data.get(col, {}).get('width') or 0, + self.depreciation_data.get(col, {}).get('width') or 0, + self.depreciation_line_year_data.get(col, {}) + .get('width') or 0, + self.depreciation_line_amount_detail_data.get(col, {}) + .get('width') or 0, + self.depreciation_line_accounting_doc_data.get(col, {}) + .get('width') or 0, + self.totals_data.get(col, {}).get('width') or 0, + ]) + for col in range(min_col, max_col + 1) + } + + def _get_report_name(self, report): + """ + * Overrides standard method * + Returns name for both sheet and report title + """ + return self._get_report_complete_name(report, report.report_name) + + def _write_report_title(self, title): + """ + * Overrides standard method * + Writes report title on current line using all defined columns width + """ + self.sheet.merge_range( + self.row_pos, 0, self.row_pos, 9, + title, self.format_title + ) + self.row_pos += 3 + + def _generate_report_content(self, workbook, report): + """ Creates actual xls report """ + for categ_section in report.report_category_ids: + self.write_all(self.category_data, categ_section) + + for asset_section in categ_section.report_asset_ids: + self.write_all(self.asset_data, asset_section) + + if asset_section.report_purchase_doc_id: + self.write_all( + self.asset_accounting_doc_data, + asset_section.report_purchase_doc_id + ) + + for dep_section in asset_section.report_depreciation_ids: + self.write_all(self.depreciation_data, dep_section) + + self.write_header(self.depreciation_line_year_data) + for year in dep_section.report_depreciation_year_line_ids: + self.write_value( + self.depreciation_line_year_data, year + ) + if year.has_amount_detail: + self.write_value( + self.depreciation_line_amount_detail_data, year + ) + for doc in year.report_accounting_doc_ids: + self.write_value( + self.depreciation_line_accounting_doc_data, doc + ) + + if asset_section.report_sale_doc_id: + self.write_all( + self.asset_accounting_doc_data, + asset_section.report_sale_doc_id + ) + self.row_pos += 1 + + if report.show_category_totals: + self.write_header(self.totals_data) + for total_section in categ_section.report_total_ids: + self.write_value(self.totals_data, total_section) + self.row_pos += 1 + + self.row_pos += 1 + + if report.show_totals: + self.write_header(self.totals_data) + for total_section in report.report_total_ids: + self.write_value(self.totals_data, total_section) + self.row_pos += 1 + + def write_all(self, data, obj): + self.write_header(data) + self.write_value(data, obj) + + def write_header(self, data): + pos = self.row_pos + for col, data in data.items(): + self.sheet.write(pos, col, data['title'], data['tstyle']) + self.row_pos += 1 + + def write_value(self, data, obj): + pos = self.row_pos + for col, data in data.items(): + value, style = getattr(obj, data['field']), data['vstyle'] + if data.get('type') == 'amount': + value = getattr(obj, 'format_amount')(value) + if value in (False, None): + value = '/' + self.sheet.write(pos, col, value, style) + self.row_pos += 1 + + ######################################################## + # # + # UNUSED METHODS, OVERRIDDEN FOR COMPATIBILITY REASONS # + # # + ######################################################## + + def _get_report_filters(self, report): + """ Override original method even if not used to avoid errors """ + return [] + + def _get_report_columns(self, report): + """ Override original method even if not used to avoid errors """ + return {} + + def _get_col_count_filter_name(self): + """ Override original method even if not used to avoid errors """ + pass + + def _get_col_count_filter_value(self): + """ Override original method even if not used to avoid errors """ + pass + + def _write_filters(self, filters): + """ Override original method even if not used to avoid errors """ + pass diff --git a/assets_management/report/asset_previsional.py b/assets_management/report/asset_previsional.py new file mode 100644 index 000000000000..fa25a817bc87 --- /dev/null +++ b/assets_management/report/asset_previsional.py @@ -0,0 +1,965 @@ +# Author(s): Silvio Gregorini (silviogregorini@openforce.it) +# Copyright 2019 Openforce Srls Unipersonale (www.openforce.it) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from collections import OrderedDict + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools.float_utils import float_is_zero +from odoo.tools.pycompat import string_types +from odoo.tools.safe_eval import safe_eval + +from odoo.addons.mail.models.mail_template import format_amount + + +def format_date(rec, field_name, fmt): + """ Formats record's field value according to given format `fmt` """ + if not rec[field_name]: + return '' + return rec._fields[field_name].from_string(rec[field_name]).strftime(fmt) + + +class Report(models.TransientModel): + """ + This report has the following structure: + * Report (which is just a data container) + ** Category + *** Asset + **** Depreciation + ***** Depreciation Line by Year + Each class is set to be linked via a M2O to its parent class, and via + a O2M to its child class. + Each class is linked to Report via `report_id` field. + Asset has a relation to the section Accounting Data which stores + sale/purchase data. + """ + _name = 'report_asset_previsional' + _inherit = 'account_financial_report_abstract' + + # Data fields + asset_ids = fields.Many2many( + 'asset.asset', + ) + + asset_order_fname = fields.Char() + + category_ids = fields.Many2many( + 'asset.category', + ) + + company_id = fields.Many2one( + 'res.company', + ) + + date = fields.Date() + + show_totals = fields.Boolean() + + show_category_totals = fields.Boolean() + + type_ids = fields.Many2many( + 'asset.depreciation.type', + ) + + # Report structure fields + previsional_line_ids = fields.Many2many( + 'asset.depreciation.line' + ) + + report_category_ids = fields.One2many( + 'report_asset_previsional_category', + 'report_id' + ) + + report_asset_ids = fields.One2many( + 'report_asset_previsional_asset', + 'report_id' + ) + + report_depreciation_ids = fields.One2many( + 'report_asset_previsional_depreciation', + 'report_id' + ) + + report_depreciation_line_year_ids = fields.One2many( + 'report_asset_previsional_depreciation_line_year', + 'report_id' + ) + + report_total_ids = fields.One2many( + 'report_asset_previsional_totals', + 'report_id' + ) + + # Fields to be printed + report_footer_year = fields.Char() + report_name = fields.Char() + + ############################ + # # + # REPORT RENDERING METHODS # + # # + ############################ + + @api.multi + def print_report(self, report_type=None): + """ + This method is called from the JS widget buttons 'Print' + and 'Export' in the HTML view. + Prints PDF and XLSX reports. + :param report_type: string that represents the report type + """ + self.ensure_one() + report_type = report_type or 'qweb-pdf' + if report_type in ('qweb-pdf', 'xlsx'): + res = self.do_print(report_type) + elif report_type == 'qweb-html': + res = self.view_report() + elif report_type: + raise ValidationError( + _("No report has been defined for type `{}`.") + .format(report_type) + ) + else: + raise ValidationError( + _("No report type has been declared for current print.") + ) + return res + + def do_print(self, report_type): + self.ensure_one() + if report_type == 'qweb-pdf': + xml_id = 'assets_management.report_asset_previsional_pdf' + else: + xml_id = 'assets_management.report_asset_previsional_xlsx' + report = self.env.ref(xml_id) + return report.report_action(self) + + @api.multi + def view_report(self): + """ Launches view for HTML report """ + self.ensure_one() + xmlid = 'assets_management.act_client_asset_previsional_report' + [act] = self.env.ref(xmlid).read() + ctx = act.get('context', {}) + if isinstance(ctx, string_types): + ctx = safe_eval(ctx) + # Call update twice to force 'active_id(s)' values to be overridden + ctx.update(dict(self._context)) + ctx.update(active_id=self.id, active_ids=self.ids) + act['context'] = ctx + return act + + @api.model + def get_html(self, given_context=None): + """ Method needed from JavaScript widget to render HTML view """ + context = dict(self.env.context) + context.update(given_context or {}) + report = self or self.browse(context.get('active_id')) + xml_id = 'assets_management.template_asset_previsional_report' + + result = {} + if report: + context['o'] = report + result['html'] = self.env.ref(xml_id).render(context) + return result + + ########################### + # # + # REPORT CREATION METHODS # + # # + ########################### + + def compute_data_for_report(self): + """ Compute data to be printed """ + self.set_report_name() + self.generate_structure() + self.generate_data() + + def generate_data(self): + self.report_category_ids.generate_data() + self.report_asset_ids.generate_data() + self.report_depreciation_ids.generate_data() + self.report_depreciation_line_year_ids.generate_previsional_lines() + self.report_depreciation_line_year_ids.generate_data() + self.previsional_line_ids.unlink() + self.report_depreciation_line_year_ids.clean_unused() + self.report_category_ids.generate_totals() + self.generate_totals() + + def generate_structure(self): + assets = self.get_assets() + categories = assets.mapped('category_id') + deps = assets.mapped('depreciation_ids') + if self.type_ids: + deps = deps.filtered(lambda d: d.type_id in self.type_ids) + if not (categories and assets and deps): + raise ValidationError( + _("There is nothing to print according to current settings!") + ) + + dep_lines = deps.mapped('line_ids') + if self.date: + dep_lines = dep_lines.filtered(lambda dl: dl.date <= self.date) + + fy_domain = [('company_id', '=', self.company_id.id)] + if self.date: + fy_domain += [('date_from', '<=', self.date)] + # Create an ordered dict where each key is a fiscal year, sorting + # them for starting date => every fiscal year must have its own + # depreciation lines or previsional ones + dep_line_obj = self.env['asset.depreciation.line'] + dep_lines_grouped = { + dep: OrderedDict({ + fy: dep_line_obj + for fy in self.env['account.fiscal.year'].search( + fy_domain, order='date_from asc' + ) + }) + for dep in deps + } + + fiscal_year = self.env['account.fiscal.year'] + for dep_line in dep_lines: + dep = dep_line.depreciation_id + fyear = fiscal_year.get_fiscal_year_by_date( + dep_line.date, company=dep_line.company_id + ) + dep_lines_grouped[dep][fyear] += dep_line + + self.write({ + 'report_category_ids': [ + (0, 0, {'category_id': c.id, 'report_id': self.id}) + for c in categories.sorted('name') + ] + }) + for report_categ in self.report_category_ids: + report_categ.write({ + 'report_asset_ids': [ + (0, 0, {'asset_id': a.id, 'report_id': self.id}) + for a in self.sort_assets(assets) + if a.category_id == report_categ.category_id + ] + }) + for report_asset in self.report_asset_ids: + report_asset.write({ + 'report_depreciation_ids': [ + (0, 0, {'depreciation_id': d.id, 'report_id': self.id}) + for d in deps + if d.asset_id == report_asset.asset_id + ] + }) + for report_dep in self.report_depreciation_ids: + sequence = 0 + for dep, lines_by_fyear in dep_lines_grouped.items(): + if dep == report_dep.depreciation_id: + for fyear, lines in lines_by_fyear.items(): + if fyear.date_to >= dep.date_start: + prev = not lines or not any( + l.move_type == 'depreciated' + and not l.partial_dismissal + for l in lines + ) + sequence += 1 + line_ids = lines.ids + report_dep.write({ + 'report_depreciation_year_line_ids': [ + (0, 0, {'dep_line_ids': [(6, 0, line_ids)], + 'fiscal_year_id': fyear.id, + 'needs_previsional': prev, + 'report_id': self.id, + 'sequence': sequence}) + ] + }) + + def generate_totals(self): + curr = self.company_id.currency_id + categ_totals = self.report_category_ids.mapped('report_total_ids') + fnames = self.env['report_asset_previsional_totals']._total_fnames + totals_by_dep_type = { + t: {fname: 0 for fname in fnames} + for t in categ_totals.mapped('type_id') + } + for total in categ_totals: + total_curr = total.get_currency() + total_type = total.type_id + for fname in fnames: + totals_by_dep_type[total_type][fname] += \ + total_curr.compute(total[fname], curr) + self.write({ + 'report_total_ids': [ + (0, 0, dict( + v, + name=_("General Total"), + type_name=t.name_get()[0][-1], + type_id=t.id + )) + for t, v in totals_by_dep_type.items() + ] + }) + + def get_assets(self): + domain = [] + if self.asset_ids: + domain += [('id', 'in', self.asset_ids.ids)] + if self.category_ids: + domain += [('category_id', 'in', self.category_ids.ids)] + if self.company_id: + domain += [('company_id', '=', self.company_id.id)] + if self.date: + domain += [('purchase_date', '<=', self.date)] + return self.env['asset.asset'].search(domain) + + def set_report_name(self): + report_name = _("Assets Previsional Depreciations ") + if self.date: + report_name += _("to date {}").format( + format_date(self, 'date', '%d-%m-%Y') + ) + self.report_name = report_name.strip() + + def sort_assets(self, assets): + # Divide assets in 'sortable' and 'unsortable' by filtering them upon + # the report's `asset_order_fname`. + # If the given + sortable_assets = assets.filtered(self.asset_order_fname) + unsortable_assets = assets - sortable_assets + sorted_assets = sortable_assets.sorted(self.asset_order_fname) \ + + unsortable_assets.sorted() + return sorted_assets + + +class ReportCategory(models.TransientModel): + _name = 'report_asset_previsional_category' + _inherit = 'account_financial_report_abstract' + + # Data fields + category_id = fields.Many2one( + 'asset.category', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + report_asset_ids = fields.One2many( + 'report_asset_previsional_asset', + 'report_category_id' + ) + + report_total_ids = fields.One2many( + 'report_asset_previsional_totals', + 'report_category_id' + ) + + # Fields to be printed + category_name = fields.Char() + + def generate_data(self): + for report_categ in self: + report_categ.write(report_categ.get_report_categ_data()) + + def get_report_categ_data(self): + self.ensure_one() + return {'category_name': self.category_id.name} + + def generate_totals(self): + for categ in self: + curr = categ.report_id.company_id.currency_id + report_date = categ.report_id.date + report_deps = categ.report_asset_ids\ + .mapped('report_depreciation_ids') + fnames = categ.env['report_asset_previsional_totals']._total_fnames + totals_by_dep_type = { + t: {fname: 0 for fname in fnames} + for t in report_deps.mapped('depreciation_id.type_id') + } + for report_dep in report_deps.filtered( + 'report_depreciation_year_line_ids' + ): + dep_type = report_dep.depreciation_id.type_id + last_line = report_dep.report_depreciation_year_line_ids[-1] + line_curr = last_line.get_currency() + fy_start = last_line.fiscal_year_id.date_from + fy_end = last_line.fiscal_year_id.date_to + for fname in fnames: + if fname == 'amount_depreciation_fund_prev_year': + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + elif fname in ( + 'amount_in_total', + 'amount_out_total', + 'gain_loss_total' + ): + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + elif report_date < fy_start: + totals_by_dep_type[dep_type][fname] = 0 + elif fname == 'amount_depreciated': + if fy_start <= report_date <= fy_end: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + else: + totals_by_dep_type[dep_type][fname] += \ + line_curr.compute(last_line[fname], curr) + categ.write({ + 'report_total_ids': [ + (0, 0, dict( + v, + name=categ.category_id.name_get()[0][-1], + type_name=t.name_get()[0][-1], + type_id=t.id + )) + for t, v in totals_by_dep_type.items() + ] + }) + + +class ReportAsset(models.TransientModel): + _name = 'report_asset_previsional_asset' + _inherit = 'account_financial_report_abstract' + + # Data fields + asset_id = fields.Many2one( + 'asset.asset', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + report_category_id = fields.Many2one( + 'report_asset_previsional_category' + ) + + report_depreciation_ids = fields.One2many( + 'report_asset_previsional_depreciation', + 'report_asset_id' + ) + + report_purchase_doc_id = fields.Many2one( + 'report_asset_previsional_accounting_doc', + ) + + report_sale_doc_id = fields.Many2one( + 'report_asset_previsional_accounting_doc', + ) + + # Fields to be printed + asset_code = fields.Char() + asset_name = fields.Char() + asset_purchase_amount = fields.Float() + asset_state = fields.Char() + asset_used = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_asset in self: + report_asset.write(report_asset.get_report_asset_data()) + + def get_currency(self): + self.ensure_one() + return self.asset_id.currency_id + + def get_report_asset_data(self): + self.ensure_one() + asset = self.asset_id + states_dict = dict(asset._fields['state'].selection) + + vals = { + 'asset_code': asset.code or "/", + 'asset_name': asset.name, + 'asset_purchase_amount': asset.purchase_amount, + 'asset_state': states_dict.get(asset.state) or _("Unknown"), + 'asset_used': _("Used") if asset.used else _("New"), + } + + acc_doc = self.env['report_asset_previsional_accounting_doc'] + purchase_vals = self.get_purchase_vals() + if purchase_vals: + vals.update({ + 'report_purchase_doc_id': acc_doc.create(purchase_vals).id, + }) + + sale_vals = self.get_sale_vals() + if sale_vals: + vals.update({ + 'report_sale_doc_id': acc_doc.create(sale_vals).id, + }) + + return vals + + def get_purchase_vals(self): + asset = self.asset_id + purchase_vals = { + 'partner_name': asset.supplier_id.name or "/", + 'partner_vat': asset.supplier_id.vat or "/", + } + + if asset.purchase_date: + purchase_vals['document_date'] = format_date( + asset, 'purchase_date', '%d-%m-%Y' + ) + + if asset.supplier_ref: + purchase_vals['partner_ref'] = asset.supplier_ref + elif asset.purchase_invoice_id.reference: + purchase_vals['partner_ref'] = asset.purchase_invoice_id.reference + elif asset.purchase_move_id.ref: + purchase_vals['partner_ref'] = asset.purchase_move_id.ref + else: + purchase_vals['partner_ref'] = "/" + + if asset.purchase_invoice_id: + purchase_vals.update({ + 'document_nr': asset.purchase_invoice_id.number or "/", + 'res_id': asset.purchase_invoice_id.id, + 'res_model': 'account.invoice', + }) + elif asset.purchase_move_id: + purchase_vals.update({ + 'document_nr': asset.purchase_move_id.name or "/", + 'res_id': asset.purchase_move_id.id, + 'res_model': 'account.move', + }) + else: + purchase_vals.update({ + 'document_nr': "/", + 'res_id': asset.id, + 'res_model': 'asset.asset', + }) + + return purchase_vals + + def get_sale_vals(self): + asset = self.asset_id + if not asset.sale_date or asset.sale_date > self.report_id.date: + return {} + + sale_vals = { + 'document_date': format_date(asset, 'sale_date', '%d-%m-%Y'), + 'partner_name': asset.customer_id.name, + 'partner_vat': asset.customer_id.vat or "/", + } + + if asset.sale_invoice_id: + sale_vals.update({ + 'document_nr': asset.sale_invoice_id.number or "/", + 'res_id': asset.sale_invoice_id.id, + 'res_model': 'account.invoice', + }) + elif asset.sale_move_id: + sale_vals.update({ + 'document_nr': asset.sale_move_id.name or "/", + 'res_id': asset.sale_move_id.id, + 'res_model': 'account.move', + }) + else: + sale_vals.update({ + 'document_nr': "/", + 'res_id': asset.id, + 'res_model': 'asset.asset', + }) + return sale_vals + + +class ReportDepreciation(models.TransientModel): + _name = 'report_asset_previsional_depreciation' + _inherit = 'account_financial_report_abstract' + _order = 'type_name asc' + + # Data fields + depreciation_id = fields.Many2one( + 'asset.depreciation', + ondelete='cascade', + required=True + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + report_asset_id = fields.Many2one( + 'report_asset_previsional_asset' + ) + + report_depreciation_year_line_ids = fields.One2many( + 'report_asset_previsional_depreciation_line_year', + 'report_depreciation_id' + ) + + # Fields to be printed + dep_amount_depreciable = fields.Float() + dep_date_start = fields.Char() + dep_percentage = fields.Float() + dep_pro_rata_temporis = fields.Char() + mode_name = fields.Char() + type_name = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_dep in self: + report_dep.write(report_dep.get_report_dep_data()) + + def get_currency(self): + self.ensure_one() + return self.depreciation_id.currency_id + + def get_report_dep_data(self): + self.ensure_one() + dep = self.depreciation_id + if dep.pro_rata_temporis: + dep_pro_rata_temporis = u"\u2612" # checked ballot box -> ☒ + else: + dep_pro_rata_temporis = u"\u2610" # empty ballot box -> ☐ + + return { + 'dep_amount_depreciable': dep.amount_depreciable, + 'dep_date_start': format_date(dep, 'date_start', '%d-%m-%Y'), + 'dep_percentage': dep.percentage, + 'dep_pro_rata_temporis': dep_pro_rata_temporis, + 'mode_name': dep.mode_id.name_get()[0][-1] if dep.mode_id else "", + 'type_name': dep.type_id.name_get()[0][-1] if dep.type_id else "" + } + + +class ReportDepreciationLineByYear(models.TransientModel): + _name = 'report_asset_previsional_depreciation_line_year' + _inherit = 'account_financial_report_abstract' + _order = 'sequence asc' + + # Data fields + dep_line_ids = fields.Many2many( + 'asset.depreciation.line', + relation='report_previsional_line_year_dep_line' + ) + + fiscal_year_id = fields.Many2one( + 'account.fiscal.year' + ) + + # Report structure fields + hidden = fields.Boolean() + + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + report_depreciation_id = fields.Many2one( + 'report_asset_previsional_depreciation' + ) + + sequence = fields.Integer() + + # Fields to be printed + amount_depreciable = fields.Float() + amount_depreciable_updated = fields.Float() + amount_depreciated = fields.Float() + amount_depreciation_fund_curr_year = fields.Float() + amount_depreciation_fund_prev_year = fields.Float() + amount_gain = fields.Float() + amount_gain_total = fields.Float() + amount_historical = fields.Float() + amount_in = fields.Float() + amount_in_detail = fields.Char() + amount_in_total = fields.Float() + amount_loss = fields.Float() + amount_loss_total = fields.Float() + amount_out = fields.Float() + amount_out_detail = fields.Char() + amount_out_total = fields.Float() + amount_residual = fields.Float() + date_start = fields.Char() + gain_loss = fields.Float() # Needed for the .xls report + gain_loss_total = fields.Float() # Needed for the .xls report + has_amount_detail = fields.Boolean() + needs_previsional = fields.Boolean() + percentage = fields.Float() + year = fields.Char() + type_name = fields.Char() + + def clean_unused(self): + self.filtered(lambda l: l.do_clean()).unlink() + + def do_clean(self): + self.ensure_one() + digits = self.env['decimal.precision'].precision_get('Account') + if not self.dep_line_ids \ + and float_is_zero(self.amount_residual, digits) \ + and self.sequence > 1: + previous_line = self.report_depreciation_id \ + .report_depreciation_year_line_ids.filtered( + lambda l: l.sequence == self.sequence - 1 + ) + if float_is_zero(previous_line.amount_residual, digits): + return True + return False + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def generate_data(self): + for report_dep_line_year in self.sorted(): # Force sorting by _order + report_dep_line_year.write( + report_dep_line_year.get_report_dep_line_year_data() + ) + + def get_currency(self): + self.ensure_one() + return self.report_depreciation_id.depreciation_id.currency_id + + def generate_previsional_lines(self): + lines_grouped = dict() + for line in self.filtered('needs_previsional'): + dep = line.report_depreciation_id.depreciation_id + if dep not in lines_grouped: + lines_grouped[dep] = line + else: + lines_grouped[dep] += line + + ctx = dict(force_prorata=True) + for lines in lines_grouped.values(): + lines = lines.sorted() + last_line = lines[-1] + for line in lines - last_line: + line.generate_previsional_line_single() + last_line.with_context(**ctx).generate_previsional_line_single() + + def generate_previsional_line_single(self): + self.ensure_one() + dep = self.report_depreciation_id.depreciation_id + to_date = min(self.fiscal_year_id.date_to, self.report_id.date) + previsional_lines = dep.generate_depreciation_lines(to_date) + self.dep_line_ids += previsional_lines + self.report_id.previsional_line_ids += previsional_lines + + def get_report_dep_line_year_data(self): + self.ensure_one() + report_dep = self.report_depreciation_id + grouped_amounts = self.dep_line_ids.get_balances_grouped() + + amount_depreciable = report_dep.dep_amount_depreciable + amount_gain = grouped_amounts.get('gain') or 0.0 + amount_gain_total = amount_gain + amount_historical = abs(grouped_amounts.get('historical') or 0.0) + amount_in = abs(grouped_amounts.get('in') or 0.0) + amount_in_total = amount_in + amount_loss = grouped_amounts.get('loss') or 0.0 + amount_loss_total = amount_loss + amount_out = abs(grouped_amounts.get('out') or 0.0) + amount_out_total = amount_out + gain_loss = amount_gain + amount_loss + gain_loss_total = gain_loss + + amount_depreciated = sum([ + line.amount + for line in self.dep_line_ids.filtered( + lambda l: l.move_type == 'depreciated' + and not l.partial_dismissal + ) + ]) + amount_dismissal = sum([ + line.amount + for line in self.dep_line_ids.filtered( + lambda l: l.move_type == 'depreciated' + and l.partial_dismissal + ) + ]) + + prev_year_line = report_dep.report_depreciation_year_line_ids.filtered( + lambda l: l.sequence == self.sequence - 1 + ) + asset = self.report_depreciation_id.report_asset_id.asset_id + fy_start = self.fiscal_year_id.date_from + fy_end = self.fiscal_year_id.date_to + if asset.sold and asset.sale_date \ + and fy_start <= asset.sale_date <= fy_end: + amount_depreciable_upd = 0.0 + depreciation_fund_curr_year = 0.0 + amount_residual = 0.0 + if prev_year_line: + depreciation_fund_prev_year = prev_year_line\ + .amount_depreciation_fund_curr_year + amount_in_total += prev_year_line.amount_in_total + amount_out_total += prev_year_line.amount_out_total + else: + depreciation_fund_prev_year = 0.0 + else: + if prev_year_line: + depreciation_fund_prev_year = prev_year_line\ + .amount_depreciation_fund_curr_year + prev_year_resid = prev_year_line.amount_residual + amount_depreciable_upd = prev_year_line.\ + amount_depreciable_updated + amount_in - amount_out + amount_in_total += prev_year_line.amount_in_total + amount_out_total += prev_year_line.amount_out_total + else: + depreciation_fund_prev_year = 0.0 + prev_year_resid = amount_depreciable + amount_depreciable_upd = amount_depreciable + amount_in \ + - amount_out + + depreciation_fund_curr_year = depreciation_fund_prev_year \ + + amount_depreciated + amount_dismissal + amount_residual = prev_year_resid + amount_in - amount_out \ + - amount_depreciated - amount_dismissal + if prev_year_line: + amount_gain_total += prev_year_line.amount_gain_total + amount_loss_total += prev_year_line.amount_loss_total + gain_loss_total += prev_year_line.gain_loss_total + + type_mapping = {'in': {}, 'out': {}} + for dep_line in self.dep_line_ids.filtered( + lambda l: l.move_type in ('in', 'out') + and l.depreciation_line_type_id + ): + dep_type = dep_line.depreciation_line_type_id + if dep_type not in type_mapping[dep_line.move_type]: + type_mapping[dep_line.move_type][dep_type] = 0 + type_mapping[dep_line.move_type][dep_type] += dep_line.amount + + amount_in_detail = amount_out_detail = "" + has_amount_detail = False + if type_mapping['in']: + amount_in_detail = "; ".join([ + "{}: {}".format(dep_type.name, self.format_amount(amount)) + for dep_type, amount in sorted(list( + type_mapping['in'].items())) + ]) + has_amount_detail = True + if type_mapping['out']: + amount_out_detail = "; ".join([ + "{}: {}".format(dep_type.name, self.format_amount(amount)) + for dep_type, amount in sorted(list( + type_mapping['out'].items())) + ]) + has_amount_detail = True + + start = fields.Date.from_string(self.fiscal_year_id.date_from).year + end = fields.Date.from_string(self.fiscal_year_id.date_to).year + if start == end: + year = str(start) + else: + year = "{} - {}".format(start, end) + + return { + 'amount_depreciable': amount_depreciable, + 'amount_depreciable_updated': amount_depreciable_upd, + 'amount_depreciated': amount_depreciated, + 'amount_depreciation_fund_curr_year': depreciation_fund_curr_year, + 'amount_depreciation_fund_prev_year': depreciation_fund_prev_year, + 'amount_gain': amount_gain, + 'amount_historical': amount_historical, + 'amount_in': amount_in, + 'amount_in_detail': amount_in_detail, + 'amount_in_total': amount_in_total, + 'amount_loss': amount_loss, + 'amount_out': amount_out, + 'amount_out_detail': amount_out_detail, + 'amount_out_total': amount_out_total, + 'amount_residual': amount_residual, + 'date_start': report_dep.dep_date_start, + 'gain_loss': gain_loss, + 'gain_loss_total': gain_loss_total, + 'has_amount_detail': has_amount_detail, + 'percentage': report_dep.dep_percentage, + 'type_name': report_dep.type_name, + 'year': year, + } + + +class ReportAccountingDoc(models.TransientModel): + _name = 'report_asset_previsional_accounting_doc' + _inherit = 'account_financial_report_abstract' + _order = 'sequence asc' + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + # Fields to be printed + document_date = fields.Char() + document_nr = fields.Char() + partner_name = fields.Char() + partner_ref = fields.Char() + partner_vat = fields.Char() + res_id = fields.Integer() + res_model = fields.Char() + sequence = fields.Integer() + + +class ReportTotals(models.TransientModel): + _name = 'report_asset_previsional_totals' + _inherit = 'account_financial_report_abstract' + _total_fnames = [ + 'amount_depreciable_updated', + 'amount_depreciated', + 'amount_depreciation_fund_curr_year', + 'amount_depreciation_fund_prev_year', + 'amount_gain', + 'amount_in_total', + 'amount_loss', + 'amount_out_total', + 'amount_residual', + 'gain_loss_total', + ] + + # Data fields + type_id = fields.Many2one( + 'asset.depreciation.type', + ) + + # Report structure fields + report_id = fields.Many2one( + 'report_asset_previsional', + ) + + report_category_id = fields.Many2one( + 'report_asset_previsional_category' + ) + + # Fields to be printed + amount_depreciable_updated = fields.Float() + amount_depreciated = fields.Float() + amount_depreciation_fund_curr_year = fields.Float() + amount_depreciation_fund_prev_year = fields.Float() + amount_gain = fields.Float() + amount_in_total = fields.Float() + amount_loss = fields.Float() + amount_out_total = fields.Float() + amount_residual = fields.Float() + gain_loss = fields.Float() # Needed for the .xls report + gain_loss_total = fields.Float() # Needed for the .xls report + name = fields.Char() # Needed for the .xls report + type_name = fields.Char() + + def format_amount(self, amount, currency=None): + self.ensure_one() + currency = currency or self.get_currency() + return format_amount(self.env, amount, currency) + + def get_currency(self): + self.ensure_one() + report = self.report_id or self.report_category_id.report_id + return report.company_id.currency_id diff --git a/assets_management/report/asset_previsional_xlsx.py b/assets_management/report/asset_previsional_xlsx.py new file mode 100644 index 000000000000..8310de281fd0 --- /dev/null +++ b/assets_management/report/asset_previsional_xlsx.py @@ -0,0 +1,514 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from odoo import _, models + +_logger = logging.getLogger(__name__) + + +class AssetJournalXslx(models.AbstractModel): + _name = 'report.assets_management.report_asset_previsional_xlsx' + _inherit = 'report.account_financial_report.abstract_report_xlsx' + + def __init__(self, pool, cr): + """ Adds new attributes """ + super().__init__(pool, cr) + + # Add report objects + self.workbook = None + self.data = None + self.report = None + + # These `_data`s here are made as dict of dicts, the key being the + # column number to be printed into, the second one the field datas for + # the print itself + self.category_data = None + self.asset_data = None + self.asset_accounting_doc_data = None + self.depreciation_data = None + self.depreciation_line_year_data = None + self.depreciation_line_amount_detail_data = None + self.totals_data = None + + # 1- Category formats + self.format_category_name = None + + # 2- Asset formats (purchase and sale docs will use the same format) + self.format_asset_header = None + self.format_asset_value = None + + # 3- Depreciations formats + self.format_depreciation_header = None + self.format_depreciation_value = None + + # 4- Depreciation yearly and amount details formats + self.format_depreciation_year_line_header = None + self.format_depreciation_year_line_value_center = None + self.format_depreciation_year_line_value_right = None + + # 5- Report title + self.format_title = None + + def generate_xlsx_report(self, workbook, data, objects): + """ Set wb, data and report attributes """ + self.workbook = workbook + self.data = data + self.report = objects + self.set_formats() + self.set_report_data() + super().generate_xlsx_report(workbook, data, objects) + + def set_formats(self): + """ Defines custom formats """ + + # 1- Category formats + self.format_category_name = self.workbook.add_format({ + 'align': 'center', + 'bg_color': '#337AB7', + 'bold': True, + 'font_color': '#FFFFFF', + 'font_size': 16, + }) + + # 2- Asset formats + self.format_asset_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_color': '#337AB7', + 'font_size': 14, + }) + self.format_asset_value = self.workbook.add_format({ + 'align': 'center', + 'font_color': '#337AB7', + 'font_size': 14, + }) + + # 3- Depreciations formats + self.format_depreciation_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_size': 12, + }) + self.format_depreciation_value = self.workbook.add_format({ + 'align': 'center', + 'font_size': 12, + }) + + # 4- Depreciation yearly and amount details formats + self.format_depreciation_year_line_header = self.workbook.add_format({ + 'align': 'center', + 'bold': True, + 'font_size': 12, + }) + self.format_depreciation_year_line_value_center = self.workbook \ + .add_format({ + 'align': 'center', + 'font_size': 12, + }) + self.format_depreciation_year_line_value_right = self.workbook \ + .add_format({ + 'align': 'right', + 'font_size': 12, + }) + + # 5- Report title + self.format_title = self.workbook.add_format({ + 'align': 'center', + 'bg_color': '#337AB7', + 'bold': True, + 'font_color': 'white', + 'font_size': 20, + }) + + def set_report_data(self): + self.set_category_data() + self.set_asset_data() + self.set_asset_accounting_doc_data() + self.set_depreciation_data() + self.set_depreciation_line_year_data() + self.set_depreciation_line_amount_detail_data() + self.set_totals_data() + + def set_category_data(self): + self.category_data = self.generate_category_data() + + def generate_category_data(self): + data = ( + {'title': _("Category"), + 'field': 'category_name', + 'tstyle': self.format_category_name, + 'vstyle': self.format_category_name}, + ) + return dict(enumerate(data)) + + def set_asset_data(self): + self.asset_data = self.generate_asset_data() + + def generate_asset_data(self): + data = ( + {'title': _("Asset"), + 'field': 'asset_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Code"), + 'field': 'asset_code', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Purchase Amount"), + 'field': 'asset_purchase_amount', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Purchased as New / Used"), + 'field': 'asset_used', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Status"), + 'field': 'asset_state', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return dict(enumerate(data)) + + def set_asset_accounting_doc_data(self): + self.asset_accounting_doc_data = \ + self.generate_asset_accounting_doc_data() + + def generate_asset_accounting_doc_data(self): + data = ( + {'title': _("Partner"), + 'field': 'partner_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("VAT"), + 'field': 'partner_vat', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Document Nr"), + 'field': 'document_nr', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Document Date"), + 'field': 'document_date', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Supplier Ref"), + 'field': 'partner_ref', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_data(self): + self.depreciation_data = self.generate_depreciation_data() + + def generate_depreciation_data(self): + data = ( + {'title': _("Depreciation Type"), + 'field': 'type_name', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Depreciation Mode"), + 'field': 'mode_name', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Depreciable Amount"), + 'field': 'dep_amount_depreciable', + 'type': 'amount', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Starting From"), + 'field': 'dep_date_start', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Dep. Percentage (%)"), + 'field': 'dep_percentage', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + {'title': _("Pro Rata Temporis"), + 'field': 'dep_pro_rata_temporis', + 'tstyle': self.format_depreciation_header, + 'vstyle': self.format_depreciation_value}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_line_year_data(self): + self.depreciation_line_year_data = \ + self.generate_depreciation_line_year_data() + + def generate_depreciation_line_year_data(self): + data = ( + {'title': _("Year"), + 'field': 'year', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Amount"), + 'field': 'amount_depreciable_updated', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("In Amount"), + 'field': 'amount_in', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Out Amount"), + 'field': 'amount_out', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Prev. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_prev_year', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Depreciation"), + 'field': 'amount_depreciated', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Curr. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_curr_year', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Gain / Loss"), + 'field': 'gain_loss', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + {'title': _("Residual"), + 'field': 'amount_residual', + 'type': 'amount', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_right}, + ) + return {n + 1: d for n, d in enumerate(data)} + + def set_depreciation_line_amount_detail_data(self): + self.depreciation_line_amount_detail_data = \ + self.generate_depreciation_line_amount_detail_data() + + def generate_depreciation_line_amount_detail_data(self): + data = ( + {'title': _("In Amount - Detail"), + 'field': 'amount_in_detail', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + {'title': _("Out Amount - Detail"), + 'field': 'amount_out_detail', + 'tstyle': self.format_depreciation_year_line_header, + 'vstyle': self.format_depreciation_year_line_value_center}, + ) + return {n + 3: d for n, d in enumerate(data)} + + def set_totals_data(self): + self.totals_data = self.get_totals_data() + + def get_totals_data(self): + data = ( + {'title': _("Total"), + 'field': 'name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Type"), + 'field': 'type_name', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Amount"), + 'field': 'amount_depreciable_updated', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("In Amount"), + 'field': 'amount_in_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Out Amount"), + 'field': 'amount_out_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Prev. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_prev_year', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Depreciation"), + 'field': 'amount_depreciated', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Curr. Year Dep. Fund"), + 'field': 'amount_depreciation_fund_curr_year', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Gain / Loss"), + 'field': 'gain_loss_total', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + {'title': _("Residual"), + 'field': 'amount_residual', + 'type': 'amount', + 'tstyle': self.format_asset_header, + 'vstyle': self.format_asset_value}, + ) + return {n: d for n, d in enumerate(data)} + + def _set_column_width(self): + """ Override to force every column to width 25 at least """ + max_width = self.get_max_width_dict() + for col, width in max_width.items(): + self.sheet.set_column(col, col, max(width, 25)) + + def get_max_width_dict(self): + min_col = min([ + min(self.category_data.keys()), + min(self.asset_data.keys()), + min(self.asset_accounting_doc_data.keys()), + min(self.depreciation_data.keys()), + min(self.depreciation_line_year_data.keys()), + min(self.depreciation_line_amount_detail_data.keys()), + min(self.totals_data.keys()), + ]) + max_col = max([ + max(self.category_data.keys()), + max(self.asset_data.keys()), + max(self.asset_accounting_doc_data.keys()), + max(self.depreciation_data.keys()), + max(self.depreciation_line_year_data.keys()), + max(self.depreciation_line_amount_detail_data.keys()), + max(self.totals_data.keys()), + ]) + + return { + col: max([ + self.category_data.get(col, {}).get('width') or 0, + self.asset_data.get(col, {}).get('width') or 0, + self.asset_accounting_doc_data.get(col, {}).get('width') or 0, + self.depreciation_data.get(col, {}).get('width') or 0, + self.depreciation_line_year_data.get(col, {}) + .get('width') or 0, + self.depreciation_line_amount_detail_data.get(col, {}) + .get('width') or 0, + self.totals_data.get(col, {}).get('width') or 0, + ]) + for col in range(min_col, max_col + 1) + } + + def _get_report_name(self, report): + """ + * Overrides standard method * + Returns name for both sheet and report title + """ + return self._get_report_complete_name(report, report.report_name) + + def _write_report_title(self, title): + """ + * Overrides standard method * + Writes report title on current line using all defined columns width + """ + self.sheet.merge_range( + self.row_pos, 0, self.row_pos, 9, + title, self.format_title + ) + self.row_pos += 3 + + def _generate_report_content(self, workbook, report): + """ Creates actual xls report """ + for categ_section in report.report_category_ids: + self.write_all(self.category_data, categ_section) + + for asset_section in categ_section.report_asset_ids: + self.write_all(self.asset_data, asset_section) + + if asset_section.report_purchase_doc_id: + self.write_all( + self.asset_accounting_doc_data, + asset_section.report_purchase_doc_id + ) + + for dep_section in asset_section.report_depreciation_ids: + self.write_all(self.depreciation_data, dep_section) + + self.write_header(self.depreciation_line_year_data) + for year in dep_section.report_depreciation_year_line_ids: + self.write_value( + self.depreciation_line_year_data, year + ) + if year.has_amount_detail: + self.write_value( + self.depreciation_line_amount_detail_data, year + ) + + if asset_section.report_sale_doc_id: + self.write_all( + self.asset_accounting_doc_data, + asset_section.report_sale_doc_id + ) + self.row_pos += 1 + + if report.show_category_totals: + self.write_header(self.totals_data) + for total_section in categ_section.report_total_ids: + self.write_value(self.totals_data, total_section) + self.row_pos += 1 + + self.row_pos += 1 + + if report.show_totals: + self.write_header(self.totals_data) + for total_section in report.report_total_ids: + self.write_value(self.totals_data, total_section) + self.row_pos += 1 + + def write_all(self, data, obj): + self.write_header(data) + self.write_value(data, obj) + + def write_header(self, data): + pos = self.row_pos + for col, data in data.items(): + self.sheet.write(pos, col, data['title'], data['tstyle']) + self.row_pos += 1 + + def write_value(self, data, obj): + pos = self.row_pos + for col, data in data.items(): + value, style = getattr(obj, data['field']), data['vstyle'] + if data.get('type') == 'amount': + value = getattr(obj, 'format_amount')(value) + if value in (False, None): + value = '/' + self.sheet.write(pos, col, value, style) + self.row_pos += 1 + + ######################################################## + # # + # UNUSED METHODS, OVERRIDDEN FOR COMPATIBILITY REASONS # + # # + ######################################################## + + def _get_report_filters(self, report): + """ Override original method even if not used to avoid errors """ + return [] + + def _get_report_columns(self, report): + """ Override original method even if not used to avoid errors """ + return {} + + def _get_col_count_filter_name(self): + """ Override original method even if not used to avoid errors """ + pass + + def _get_col_count_filter_value(self): + """ Override original method even if not used to avoid errors """ + pass + + def _write_filters(self, filters): + """ Override original method even if not used to avoid errors """ + pass diff --git a/assets_management/report/layout.xml b/assets_management/report/layout.xml new file mode 100644 index 000000000000..3ac4ad1edaec --- /dev/null +++ b/assets_management/report/layout.xml @@ -0,0 +1,58 @@ + + + + + + diff --git a/assets_management/report/paperformat.xml b/assets_management/report/paperformat.xml new file mode 100644 index 000000000000..ce269e90242b --- /dev/null +++ b/assets_management/report/paperformat.xml @@ -0,0 +1,34 @@ + + + + + Assets Journal Report A4 Landscape + A4 + 0 + 0 + Landscape + 40 + 15 + 5 + 5 + + 35 + 90 + + + + Assets Previsional Report A4 Landscape + A4 + 0 + 0 + Landscape + 40 + 15 + 5 + 5 + + 35 + 90 + + + diff --git a/assets_management/report/reports.xml b/assets_management/report/reports.xml new file mode 100644 index 000000000000..79536817ef70 --- /dev/null +++ b/assets_management/report/reports.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + diff --git a/assets_management/report/templates/asset_journal.xml b/assets_management/report/templates/asset_journal.xml new file mode 100644 index 000000000000..a44401270441 --- /dev/null +++ b/assets_management/report/templates/asset_journal.xml @@ -0,0 +1,798 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets_management/report/templates/asset_previsional.xml b/assets_management/report/templates/asset_previsional.xml new file mode 100644 index 000000000000..f4461302f3da --- /dev/null +++ b/assets_management/report/templates/asset_previsional.xml @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets_management/security/ir.model.access.csv b/assets_management/security/ir.model.access.csv new file mode 100755 index 000000000000..24186943fb63 --- /dev/null +++ b/assets_management/security/ir.model.access.csv @@ -0,0 +1,12 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +asset_user,asset_user,model_asset_asset,base.group_user,1,1,1,1 +asset_accounting_info_user,asset_accounting_info_user,model_asset_accounting_info,base.group_user,1,1,1,1 +asset_category_user,asset_category_user,model_asset_category,base.group_user,1,1,1,1 +asset_category_depreciation_type_user,asset_category_depreciation_type_user,model_asset_category_depreciation_type,base.group_user,1,1,1,1 +asset_depreciation_user,asset_depreciation_user,model_asset_depreciation,base.group_user,1,1,1,1 +asset_depreciation_line_user,asset_depreciation_line_user,model_asset_depreciation_line,base.group_user,1,1,1,1 +asset_depreciation_line_type_user,asset_depreciation_line_type_user,model_asset_depreciation_line_type,base.group_user,1,1,1,1 +asset_depreciation_mode_user,asset_depreciation_mode_user,model_asset_depreciation_mode,base.group_user,1,1,1,1 +asset_depreciation_mode_line_user,asset_depreciation_mode_line_user,model_asset_depreciation_mode_line,base.group_user,1,1,1,1 +asset_depreciation_type_user,asset_depreciation_type_user,model_asset_depreciation_type,base.group_user,1,1,1,1 +asset_tag_user,asset_tag_user,model_asset_tag,base.group_user,1,1,1,1 diff --git a/assets_management/security/res_groups.xml b/assets_management/security/res_groups.xml new file mode 100644 index 000000000000..c85bb123135f --- /dev/null +++ b/assets_management/security/res_groups.xml @@ -0,0 +1,14 @@ + + + + + Asset Users + + + + + + + + + diff --git a/assets_management/security/rules.xml b/assets_management/security/rules.xml new file mode 100644 index 000000000000..1a7fcf6160a4 --- /dev/null +++ b/assets_management/security/rules.xml @@ -0,0 +1,105 @@ + + + + + + Asset multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset accounting info multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset category multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset category dep type multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation line multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation line type multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation mode multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation mode line multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset depreciation type multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + Asset tag multi company rule + + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + diff --git a/assets_management/static/description/icon.png b/assets_management/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..781b33858e61384e3243e3cdbb334d81b4c1643b GIT binary patch literal 10456 zcmaia19V;6+V+lZHde#Nb{aHJ)7WY3>|kfdjnUX@Y}-a-v$1U(f6uw+YTSGOZ;dh6 z)cZUy)_m8P3*QwLBvB9v5CH%HinNrt((hXFj{*<-`y7FBS@yeva8!~M1(c5w9sKSf z*hy(R0su%@e-sEnN-9180F7>;q5;y7m*X=6+AtXy0}V}>Tx{%qO9KD`E_}b6HYOkg zG8Y?bTSq<@L5e>m_~Wa40Ap%6kOBO?=VFgE2= z694oU{C7`~!W;y$<6~xac6MfRW@iFAm@%{R^71mXuraf-G5(fdbab@^8MrXoI#T|P z;(ox0L&V*UX#1ZJ^U}W-JobtaB{SMs!-+=!H0$G^;59NQ% z{Au?;V)EN%f!|8x<@v--94x>l#-AL3Hh%`j&cMOZpV zz}Cn_T3qNi6O)C7F`uZI7z-Px1TQDoCoWc23C@q)?3|ytMI|J7M7hK`*hK}H{{#AO z@&Ak27--~VV`2;Xi`n>}%pdQ>obhR{9t3KcWAk z^lx+0|1(OW{}=7QK>wYVPt3u@00eYU0RpXsKK_w(WQyiM5YW*aXh$X{Mna`}i{F7Z_#-WZSOu8>W9%<^0p>q)=3jE?ZwdP6=p%S2=rNDsh7Q3jLd_7^Z zsiPJ5C=Ky9{57`-*41t(kw2<`v-JemEvc>MB_u$r)ZWbMR%qeCBV-DQM>#`MiAXsB zPqzei-(E(WXqsAM0gEqQL<543yCcuL+-nb`z;9PSc!R3Od)|?Eju&1x(IKZp8^sIr zr8EqYQhcG_cx=FmFui2okUg)iE>Z0p(#Q?tEv=s7eNPx4FQe&C7bc-Wg;^DS#}0E{ z1Bsp)55dui{#^q!ifqDedLPTmS;9EzBr)p`Z^yn`S_gFBIWRUA3Q3Gtwaj>*l)>c< zC|3#>r{@=;tkg0b!j~xA!pBP#$qWP}LL&cS*$jl1tEAd$jc1>vgio$f!LCwX+&O53KsimA$~GvEC!#pd zRZ|uhzNZb?ePiiLoKqe5l=MwY7#dNyoEq<)-MZD809%Nf#RHcIN{Wl6*fcC$d&?S^ zkq}x`*gY^=AbYu#JN?egLaGV9Io7+#b(Y@EP>A9x4jYMH!xj5=g1lx~q9i`Xd{v|W z=&H7PcCc9N+EMW1^3tKMI9EJXtw3p)9exkHQ?7`R-D&sj3-)Vpc3~oY6h~m+kNg9X zO-t{e8RE}Uxo4qX8gGb3Wd)YwNy%u~AuiS87=y#fCc48-_>mD4(ptnzh7nt(;yEOG z%A9v7*|CE?Mf?UP9r=F-);`GhcCN_h-Zo$_FrDDCuN!stuq*5I&LeYqL2ND@sF z0_EKNWiq#2pBEbY&vDgo(DLEL6mNqB{!(8$|M{I3+bd&N9CPq73pP3EoycZ_^d=Oi zWJ>rjojBV-G6iM|qGTivl#%%?se=zUepac>T&NV2^}-Ec3=uOPQSUR@55ab{3h zv~Qmebh(vfcoQS~f_CaE0qwpQY|d_~3#nj^$uV;*>iB_>$r?K2&fkv(<~wQd0DsIE zaX?JKUg{2ZVQHO(cE()3^iv1tEm?Kw)DQa8Z5>@HGQI?xk4en>%ACNP1%fdWub3v1 zm(DRtZL3Y2hJdnMU|IH4U{r(>;j8=Oko&I(RfamLd1{ajCSOQw(?&fXN;tGQb#rMW z3po}bmd?CUeo9U(9T4ji$bpdgoF)D!206vM*2{Fv9WC!qoQ!HzFxL8=;rT9UL}h;y zZ64K0$L6F)u@N9xX4TfZ(iWp@ujU(n`6k2ZAtv=w)1ytQ^)T8Dk%UO%nub_a&hAkkdM?eu7LA$2~K9nGeQHu2+ZEGy3&M~|j{b>aToesTwRO@wtZ}Xj%%1Idh51W(% z0N7)qu?TND!eEIk6)d6Pwn(2ibUuzWG|{6PUNl3uad0DMCMTC40ol@&Odq!q7gKbY zV#_praJC?VU_xhgHL3IkUQp?~6k&INb1UQTn+$8fefL-0uj=&HI=S0TPzm#tWGg~B z7T$&lr$!;kwXnZ{l@9goqha}@^xV&UXxE1Ia~YZuHBg(%p*zC_2K+x%Bo?-Uw+;H9 z8SCUp`=LF2Gq-NhRW}0M8G1@D6uYEo_%bsXVUrV7=ld2^T?CpzTD_#K7c>4pUA$#XO!lM4GH$Gws(OQW5)uWCn0vQ;BXclGo1I+8LTUC{w!*gO#*7#z#Y*W+(N$pO-218f4+&vn9 z8x@6NFYj^;wQxD{55K3~I&`d4bu>TNg(WbBe@{qQ<3Vwusxm>NZLe2Ss#W=Yiua1~ zpyHyMs}O38!xS>LuM3Z7J;$DAF9R^+RMs_d=(YWRj|?|4YyUAq&#PZ+svoYN?DGY< z?6rEWN+5lJ#xJf1T?uwfp$iH`b^8Oz{b06}R-9UO7n|(n7A!WHT&tZa8Ru>k=WWeTbEb^;g=Bo&DL?aBl?MitSnl%t z;4+*gN;(BPjb6}BrEuGBu+`AXIdHozlevE}>XRiJOwlrbsD;p?p^G%`V?saNP zsoG>*ieR)|?AQz?v;xY&ROdltj49L*ncHP)NZ$^#CWdANc0b}IybIMD1E@~F%A!Hr zvSM9$CiO9CYS(2J(KIWfhAX@(kTQgd8^4pC?lNsvG`<+d&t7Ny)3pC-L=0r<|$ph92Z9IyOM zsd>xr=q4-!!!8>hu|wQcIj@aIQ4{)*7&NY=@vTbGos@| zN(TJFg~H1P_m61%L=cA^M8|s$+h&`B()*;K6_}{lxTv3*o8%*MEDZDNRqNGCWIp|H zczDN|(brYJb1xC!TnI4y5Tp+CMkUiK^Qjp7d5NNJ;*PdL z(_iz^L#Vz3u~9L#Rg$*8n_J%D+#!Euly3=p;3w_%kMmWn6x8i;wZIV#m$LF!o=LkX zbO)%Z$!s#hv^aeE+}@epIdT~AfJ)CIA6H&$?$|px9dMa7U}=HA971S!U{p4&mpwDl zPwFgtNtJg!9<^(_U?siVN}%vQH4#Ou{?j(?_a4&09hyZ$uHH#%e-PocYU=G2Bf!EroYs)_oo^Xtu7OpoaxCO^ zc!R*Ozx)sx6@+WR>fE*+iVzI>p}cD1={1o z^@FCv2cmTOU46VOT~DOE0xE60%5=RM5g$lkZ; z3sb+OV`HLsp$_mF#i&T~WnOKfD?mR+qr!)PZTjM|TW`Q zUl>}vVwO1(0=6PD`wyc&;Wbc1o7jES}Omtp z<+;!-_R%z;G5Glar>CH;^CW34V|8M*zue$WQbA_yWGV8@evo!nrg2VmrF%Y8SM9}E z5F45g=IplaJeP7dNf`yPe^-6>>ww`4CLTK|;OV0Hp^fmhd|4uSd#WtQ>A+C8gF{KaBk44nUL zmOD~__B-plf~g~s-gOfuotkM``3>~72YEk@Lyfn9*L`6N_b^zwjbwD(YPPIGv|_N+e_U41l)|Er%JBHIXS8CkgTNGb58pnzF0zvTnGO zZ(dqX^h*C65ZCh+whP(E7oP&5CK+ekVljDGWlaR`tMAFIZpp*F&I&9`n{6JHC;svec z0mJiGncdIga`Y6n$m!^N-SWWP?xV!Q4`+}o((hCJSvvI8+w2~`?C6kLxH`>Pnk>&G zD;uD{$*@AglsaYD1U>SiV4YUp?V)6Qn$LXJXj+lHUS`VG>s(FUQ1`7$DC^OGvH+aE zK&TCQ5U-wfeEzjGS%3Xv!K{>##`TN!ofIbcG>k`r@)KNT_&rV@%#%RdxVo0xjggWC zRMAL!R%6M}9jF-99mOtml3k(Uh9liB&n)y`P}5KP9Ht(V!Lr#eL8!vDXIm&I^A6aT zXgh;GOJ2qYbuY|Jo{&EjggX(+tmhWLQo|}#I?J`D5f2^g#m3OM5065Je< zkC0jnq@Vg(T%wUw`i)VknfND`tdli1JlI@H0~b`3S*-^#&kuR)kq$5pw+GAuz~#sc z?U@G2MQ+v!YFHW3Y%|zd8h4_RR8hIUZpRf~-`Lb#CiitX8TROJ)^W85`SooMX7y#r z<-uv|O_(Bd=~PO7EC;lsu28e$8&Z!-1o}*_{4%v>GPtmnWi12UBeARz`TEKf~v7vZy!|~+r{At zm`Bt8HTb5Z%ZWyVJye^9gf|qgdbjRpl-B~&`b;dCU(!(-^Sy%M6Rj}t>IiJK`jxW? zu9HPa&7w$lSg+aqF=AJ2Ak>oD#gS#roaDiTM&O!_|IV)Mo%!mIsT_IVC234GCQyb6 z?9;i6Ee7yZP{d~R5XA#Vfxa_6H(dlc$t<0LMDWr~Hl%-z9YJNMpFMi;GI=!r6X|IE zflMLfg@zS}JW`QLbkY{CA;A{U5h*TV6Q3FNATDA2nJJ=NkSXGrRa$5A<#eSDA0hSaOxQDEff&BR#~mAN3=GaIoOhoRfggq~gv*w%5lUk{&J~Sv z1z@UjyU?NDW->3|H^T!xR(IQA55cW3uZxFGk<(Iqu{pM8&}169m(|nuwI_lSclx_O z2}WOHU!~WyRk~}jbzUc2uyqjZjo3cse=)#QYRKx8UWJrXuQrCc4if=?yfSy0aG7CC zlAg|`0fBz9JzI;sP|uyU=_kv8eQbXW#{YgUq1mX?c5OyUi)$vKbU%`V1Q{f&K%Hx= zeT}8=y~$j49(4rkISNMD+?zlZLZamxF*xqTrYn(g3viH@E74E7q(s5<$T-p<7(Qs6 zFJF=nFvVG%+kvP^ThTx3jL%(slSZ^%M?}AHxud6nZ6+SW7AcGfmUu#N8XsRlM)KmK zL92`3hEjhU8?>?ELlxg-Q9c$tmG*M&R3unw5mOo>#fiORqu82WP+se)_$?n1pP=qA|Kyj4<=H@$N^JI7ZWaxZ)1X!WG;!rEWzQHLqG z?vG||VEU>^GCXENfO~^Uc~_A0so@~G<21*Je6V#q%-x@MR6bGrW(3y7Rgz$S{SJ@E z?b^GOt2m@4M7X#t{Vi_W>0*-|Hu6vigPG*>N}F3PH0p&wk!e7?O#|`Ik2RG%if*AH z?{O8dH0M8e9jDF#(^J1lq*J-YV^-x%FY~L@x9KFK*xgW#;Ts+omzuxf&NYC)mr*S> z5)7#y-_{q*sf@p&%7D)or1SQwYAAe&XQ!u-xD0#p>nd)D!Byq=eqKQ^?U;)X<;kO- zmJHV7!|+iw{VT9AQ8OgIeOB?#P8Q8jO@7}b%SW*BcrK47H{^&F{If_qdM>TJtPH2- z8im8cJ8v^)n0~woYSNDy(FCxErs)DK4&qJi*7ED#lzBY1^;*~L1?7llJFMy!p6sB0 zLAJSAakZXZKSEK%v59XZFZt+5LNoI7DL9{!j?Q_fEr)?ZnB+?e?Fk80)K8#=ziY@8 zRw$g^d_8N<1~2&bznA;D#Cl|z{0&w(nJ671c`L-hp+nAs{Um^koV zBHI=eb)h6|q&n(0N=$6nhwz02A`FLH319xN804t@w&(#fnC9C;IkTwAGM;EBrcEuD zL~pCJl_|(+Iey3D?rC3lkDH4n>T<6-k&^S?#o0OIb~iyPRwo$bZuTa&kodlxLyWRi zZw&d;3{{T^QEHT~^;&9oxwgWDD|~gCrfv%*h(2FDs`~EkeGFyJyB~Jml}6!CI=0AR z>t7)^?NaI86%(?#{@^vEHvWWwF|h6fpMJA$51vDChh`^adE9;1o07MJranW=GfBER z4+deD;rnVP;LsbIR#2oP-Wr&ajo45kNp|Tnb4ybzY$FM-2A-6D$|o(t)6y0sDr60Z zJJ+jc4!he_IzQ5M$@3Mg2S2pxs(6{MkO-SSxs5@9-hn$p*B5jX=PuJaP%85qFNha#(J_lUd~MkQB(<-xCKMnsGs@u~{|QyiIQI#@wiO zlodPpCld&K%}F$j;BFK827j${Ft9BJjICtGocw)f34kbtCzF zW%dp*juh;KM#8@XrDQ>H{{WoHkl}0ASg-QsN@v11`uajn=Jd$?ltc6FH$V%yZ4E{; zM)3ZL@Q?#V>eO=rqiFWPv$}@F?kixMg^1c9TP(q<45wbEG38HDo5x3WSYUFiR_0xVe}4oO-DV<$|m}57`gr+=`{d zu}lYrBHP@&CUQ@{xu@6g#q+Hru%k-hO&^l|K)z{+{F{ZuByZ0%vqhKLU_MgP@JG{U zAmFDm3Y;65f`5p?G24vB??I(jfRAP*RxfbD2$^s1#`9aMSiBr0ua08eF+KCCQcT6y0oY-&g-ZLuu{<{7p5YSAFtdEKsd!Bt z=|h*Z9@$tEDqW9U8c%@d$aQj}ooZ_tTy?u8bahZycKh7u-tL7Dk59@}Bt~9VAA)f8=oNmjnB8Hmqe2sc1g>D``oAl}@Z*)6v5x0%y3d zy=F`;S3;~{t=^amme#hOWD705`mvI2F)-L{@%J}`1bHL7ls)2ScZ_D4K>}`@Idu#= zxVVSPw+4FLr_q$XJ)6wO{>1UlA32L`rI6=>xL^F@XN7YgLXse^evy9ABcdEUM>c*) zrWwosIuKx=A0&i-dz4~w)u5b=Fx|n03|E|xUG7|&(?VRQAKFVm%<7)=o*?P-p8h$- zx`_sgaF{^ed=PV|tZxZMKVgyw3Rl3lPav6s(Ps()^ah`oZ{|;6Yt=FB7VB4nhf)tP z>MdS^m?4_aTE}|kI`&KzW0&^nnucmT0l(*5-Uu#xAI zIuGlIQY#MmH()nG26h${L?NDh_nV4<+(KrXHWo97Ss=7;Z<5T1B!}OMBzC zwLRamOZz^%Z!|@?@@L-xt($hR5ZulbW+sk17PExDA8I3W)bvx4IKyg1--fhHF$X2X zz$WA94ZyCm@lsP*5%jWlK&YdV&^o&gr9C*N>!f;x7x6=jHPFhExNSw@>9komwD;ri zS4K_g1jn}GLa&Jzh=vd8MjhXU=C05Mc;EE+>I@NG%DaoOP@H5x1gkS(cp;C!E|Z?F(LW;1+jje@hOD&bN%j>u0>vqMr3tH zG$9)JvFJQmN$dH%#PpDmpj zr4{C%$(7Bmbn zBoDWTmQXuf#oo5}91+Y~XP4TIcyL#TPh?bb$kr9z)lQIy zKm`nKh<09W<$WY;kDzEgSu3(MJx8^edj8^4yWQ*d;BXXIiknPVWl>Rz7?LY&!9kz# z2Q9xoue|H#1^mY`6c8fz2FvrE7=#`xeZz&29i$w}N;0CZ&Av63!lMo}>{4o6qy0(9 z1B%L5Yu8>>&=`aHgiT_+*Ix8pNxBCyF&oyDP&CcMQr)bhUcSfvfDDRuLQ&lJwumM) zMS|{(E?_$bvgdmon-|Q}4A?YQCT0bg#T)e@|7tXXg^xt0;Y|HPgK{!r_sRz|EqbNI zyp8$SJ%SBTg+w4Q@&PQB8`})7r-212m7sr?2hCJQ(E5V;kCqSJK+=7DWXK)jY_O)Q z1hBdLO}nHJovqK!3=VEDC-Gb~WL{HQ=^A1*hN?>@y`IDZWdIvg{eg%Cj~8Tz(Ubp^ zbf`%xS6;nJfwH_a*P5?5}bR!<}wO?JTS|W?i>}w?5 z3eyOv9qLv*6AL0D zLXAX)Y`=&Xb3-eCQ*E3|B9QCB?P95}KBIc|+*k&R#n^Wu>>)KpG4HH5O%#&hh#EC) zY$2=r($N~@x^`Hu8t^FvVnN0p;JD7Tjw;6TprUwo$8S~<-YRt2#qT}z;iL+qkZg#$ zB%|e~){jEq+IA|^%fC0|yr`$_5V4X&#)8S98*+{r1k*mK_bsc~<9Mb9Y00G8mKMhu zeYwdy&tkNs0cCw`Ib>T8;qaKF@{H`?#G0Dq(PbyLm@Ub8+sXRUu$Df$X^7}4kC@!> zP%Ymt)5Q?zja6doE2ZK+$_3Z$J7|VzdTq8^;Z`4@`tk81k5Y14zsF$INt}=zhVwdj z-Ci#HJ|(|$BUt6!_6PMWV5*T?I3hTeXN@E1{igFqPhbs;@nd#=-MN|qD`Xdv^2ubG zVroT1#v|wb(fKZ!UUlzLM<|QV(E5r0c}NRL-Pz&}BrVyd^o_Jz5 z1cBRDF0bh^itVLlCgHMm{kL^}kh2Rqqy2CIcshhsbtHveX3niDFV1JpSS19EF5V;c zbLvHZ5n3|`fyGDM`wxDn&-k%pEUi(xut7|EQEd=yV1S#C_+6h0a$q?+nyp83Xo8yq)dy?@mJU>nyy2%?DHD4XcSj$r{He z0ZRrQM3Ked#NV4n&~(0hV;98vsJ^Z`kHa&jcVmxqUS?=%(}yCDg3|zA_abr$yu@9f z9QTP_;)z6O!`tPs)-w_N7yPI4j?RJcuYeVrT+TQU*Q*)n%lbT^XUHW5 z+uk+U8o^s3>L~rwwbpury)kZ|Uy;FeIX#1=z%%HV`J$Rn@~tO?kTJDy`!SaaB+#D= zVsmPZ8i`}o=@Xf9T{R;{*X+Hj`4kdPF>;RvFI^5+IcwzjR=)_ZkUEJWsQkWXLmyx) z$5%;h2ThQ({qX)C)B8Lpi~sP$fX{=SacBVVWBV4`p-b(+O8P3&;EZIgn%d{>kh`Qa zyGgOdAqu%JM4B3bLkTHiN)oCLlS+6CYWW~G4FsAM8eVzLNHE-+iHYRo?cx664Nql@ z*7=o38oaS@(z~;f3)kaXcyzlAKWD8Zq4A0L(66LdPGrNu7R-PAstAylP!KN{{p$Pw E0Mo5$t^fc4 literal 0 HcmV?d00001 diff --git a/assets_management/static/src/css/report.css b/assets_management/static/src/css/report.css new file mode 100644 index 000000000000..cd27582a10ae --- /dev/null +++ b/assets_management/static/src/css/report.css @@ -0,0 +1,103 @@ +.act_as_table { + display: table !important; + background-color: white; +} +.act_as_row { + display: table-row !important; + page-break-inside: avoid; +} +.act_as_cell { + display: table-cell !important; + page-break-inside: avoid; +} +.act_as_thead { + display: table-header-group !important; +} +.act_as_tbody { + display: table-row-group !important; +} +.list_table, .data_table, .totals_table{ + width: 100% !important; +} +.act_as_row.labels { + background-color:#F0F0F0 !important; +} +.list_table, .data_table, .totals_table, .list_table .act_as_row { + border-left:0px; + border-right:0px; + text-align:center; + font-size:10px; + padding-right:3px; + padding-left:3px; + padding-top:2px; + padding-bottom:2px; + border-collapse:collapse; +} +.totals_table { + font-weight: bold; + text-align: center; +} +.list_table .act_as_row.labels, .list_table .act_as_row.initial_balance, .list_table .act_as_row.lines { + border-color:grey !important; + border-bottom:1px solid lightGrey !important; +} +.data_table .act_as_cell{ + border: 1px solid lightGrey; + text-align: center; +} +.data_table .act_as_cell, .list_table .act_as_cell, .totals_table .act_as_cell { + word-wrap: break-word; +} +.data_table .act_as_row.labels, .totals_table .act_as_row.labels { + font-weight: bold; +} +.initial_balance .act_as_cell { + font-style:italic; +} +.account_title { + font-size:11px; + font-weight:bold; +} +.account_title.labels { + background-color:#F0F0F0 !important; +} +.act_as_cell.amount { + word-wrap:normal; + text-align:right; +} +.act_as_cell.left { + text-align:left; +} +.act_as_cell.right { + text-align:right; +} +.list_table .act_as_cell{ +/* border-right:1px solid lightGrey; uncomment to active column lines */ +} +.list_table .act_as_cell.first_column { + padding-left: 0px; +/* border-left:1px solid lightGrey; uncomment to active column lines */ +} +.overflow_ellipsis { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.custom_footer { + font-size:7px !important; +} +.page_break { + page-break-inside: avoid; +} + +.button_row { + padding-bottom: 10px; +} + +.o_account_financial_reports_page { + padding-top: 10px; + width: 90%; + margin-right: auto; + margin-left: auto; + font-family: Helvetica, Arial; +} diff --git a/assets_management/views/account_invoice.xml b/assets_management/views/account_invoice.xml new file mode 100644 index 000000000000..bfdf01ef6dc9 --- /dev/null +++ b/assets_management/views/account_invoice.xml @@ -0,0 +1,134 @@ + + + + + invoice.form.inherit + account.invoice + + + + +