From 9352bd825cef9d39fc1974e7d5b666e27dbea47d Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Wed, 3 Feb 2021 20:22:01 +0100 Subject: [PATCH] [FIX] account_asset_management: don't set class attributes in reporting Also, actually generate report in test plus other tests to make it to the codecov target --- .../report/account_asset_report_xls.py | 178 ++++++++++-------- .../tests/test_account_asset_management.py | 43 +++++ .../tests/test_asset_management_xls.py | 59 +++++- 3 files changed, 197 insertions(+), 83 deletions(-) diff --git a/account_asset_management/report/account_asset_report_xls.py b/account_asset_management/report/account_asset_report_xls.py index 37ef06cb..2de634d3 100644 --- a/account_asset_management/report/account_asset_report_xls.py +++ b/account_asset_management/report/account_asset_report_xls.py @@ -7,6 +7,11 @@ from odoo import _, models from odoo.exceptions import UserError from odoo.tools.translate import translate +from odoo.addons.report_xlsx_helper.report.report_xlsx_format import ( + FORMATS, + XLS_HEADERS, +) + _logger = logging.getLogger(__name__) @@ -24,7 +29,7 @@ class AssetReportXlsx(models.AbstractModel): return val def _get_ws_params(self, wb, data, wiz): - self._grouped_assets = self._get_assets(wiz) + self._get_assets(wiz, data) s1 = self._get_acquisition_ws_params(wb, data, wiz) s2 = self._get_active_ws_params(wb, data, wiz) s3 = self._get_removal_ws_params(wb, data, wiz) @@ -64,7 +69,7 @@ class AssetReportXlsx(models.AbstractModel): "header": {"type": "string", "value": self._("Asset Start Date")}, "asset": { "value": self._render("asset.date_start"), - "format": self.format_tcell_date_left, + "format": FORMATS["format_tcell_date_left"], }, "width": 20, }, @@ -72,7 +77,7 @@ class AssetReportXlsx(models.AbstractModel): "header": {"type": "string", "value": self._("Asset Removal Date")}, "asset": { "value": self._render("asset.date_remove"), - "format": self.format_tcell_date_left, + "format": FORMATS["format_tcell_date_left"], }, "width": 20, }, @@ -80,22 +85,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Depreciation Base"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "number", - "value": self._render("group._depreciation_base"), - "format": self.format_theader_blue_amount_right, + "value": self._render('group_entry["_depreciation_base"]'), + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "number", "value": self._render("asset.depreciation_base"), - "format": self.format_tcell_amount_right, + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("asset_total_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -103,22 +108,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Salvage Value"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "number", - "value": self._render("group._salvage_value"), - "format": self.format_theader_blue_amount_right, + "value": self._render('group_entry["_salvage_value"]'), + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "number", "value": self._render("asset.salvage_value"), - "format": self.format_tcell_amount_right, + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("salvage_total_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -126,22 +131,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Period Start Value"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "number", - "value": self._render("group._period_start_value"), - "format": self.format_theader_blue_amount_right, + "value": self._render('group_entry["_period_start_value"]'), + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "number", - "value": self._render("asset._period_start_value"), - "format": self.format_tcell_amount_right, + "value": self._render('asset_entry["_period_start_value"]'), + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("period_start_total_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -149,22 +154,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Period Depreciation"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "formula", "value": self._render("period_diff_formula"), - "format": self.format_theader_blue_amount_right, + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "formula", "value": self._render("period_diff_formula"), - "format": self.format_tcell_amount_right, + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("period_diff_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -172,22 +177,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Period End Value"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "number", - "value": self._render("group._period_end_value"), - "format": self.format_theader_blue_amount_right, + "value": self._render('group_entry["_period_end_value"]'), + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "number", - "value": self._render("asset._period_end_value"), - "format": self.format_tcell_amount_right, + "value": self._render('asset_entry["_period_end_value"]'), + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("period_end_total_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -195,22 +200,22 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Tot. Depreciation"), - "format": self.format_theader_yellow_right, + "format": FORMATS["format_theader_yellow_right"], }, "asset_group": { "type": "formula", "value": self._render("total_depr_formula"), - "format": self.format_theader_blue_amount_right, + "format": FORMATS["format_theader_blue_amount_right"], }, "asset": { "type": "formula", "value": self._render("total_depr_formula"), - "format": self.format_tcell_amount_right, + "format": FORMATS["format_tcell_amount_right"], }, "totals": { "type": "formula", "value": self._render("total_depr_formula"), - "format": self.format_theader_yellow_amount_right, + "format": FORMATS["format_theader_yellow_amount_right"], }, "width": 18, }, @@ -218,12 +223,12 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Comput. Method"), - "format": self.format_theader_yellow_center, + "format": FORMATS["format_theader_yellow_center"], }, "asset": { "type": "string", "value": self._render("asset.method or ''"), - "format": self.format_tcell_center, + "format": FORMATS["format_tcell_center"], }, "width": 20, }, @@ -231,12 +236,12 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Number of Years"), - "format": self.format_theader_yellow_center, + "format": FORMATS["format_theader_yellow_center"], }, "asset": { "type": "number", "value": self._render("asset.method_number"), - "format": self.format_tcell_integer_center, + "format": FORMATS["format_tcell_integer_center"], }, "width": 20, }, @@ -244,12 +249,12 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Prorata Temporis"), - "format": self.format_theader_yellow_center, + "format": FORMATS["format_theader_yellow_center"], }, "asset": { "type": "boolean", "value": self._render("asset.prorata"), - "format": self.format_tcell_center, + "format": FORMATS["format_tcell_center"], }, "width": 20, }, @@ -257,12 +262,12 @@ class AssetReportXlsx(models.AbstractModel): "header": { "type": "string", "value": self._("Status"), - "format": self.format_theader_yellow_center, + "format": FORMATS["format_theader_yellow_center"], }, "asset": { "type": "string", "value": self._render("asset.state"), - "format": self.format_tcell_center, + "format": FORMATS["format_tcell_center"], }, "width": 8, }, @@ -359,10 +364,10 @@ class AssetReportXlsx(models.AbstractModel): else: suffix = _("Removed Assets") no_entries = _("No") + " " + suffix - ws.write_string(row_pos, 0, no_entries, self.format_left_bold) - - def _get_assets(self, wiz): + ws.write_string(row_pos, 0, no_entries, FORMATS["format_left_bold"]) + def _get_assets(self, wiz, data): + """ Add the selected assets, both grouped and ungrouped, to `data` """ dom = [ ("date_start", "<=", wiz.date_to), "|", @@ -394,10 +399,15 @@ class AssetReportXlsx(models.AbstractModel): if not wiz.draft: dom.append(("state", "!=", "draft")) - self._assets = self.env["account.asset"].search(dom) + assets = self.env["account.asset"].search(dom) grouped_assets = {} - self._group_assets(self._assets, parent_group, grouped_assets) - return grouped_assets + self._group_assets(assets, parent_group, grouped_assets) + data.update( + { + "assets": assets, + "grouped_assets": grouped_assets, + } + ) @staticmethod def acquisition_filter(wiz, asset): @@ -452,13 +462,17 @@ class AssetReportXlsx(models.AbstractModel): return asset_entries = [] - group._depreciation_base = 0.0 - group._salvage_value = 0.0 - group._period_start_value = 0.0 - group._period_end_value = 0.0 + group_entry = { + "_depreciation_base": 0.0, + "_salvage_value": 0.0, + "_period_start_value": 0.0, + "_period_end_value": 0.0, + "group": group, + } for asset in assets: - group._depreciation_base += asset.depreciation_base - group._salvage_value += asset.salvage_value + asset_entry = {"asset": asset} + group_entry["_depreciation_base"] += asset.depreciation_base + group_entry["_salvage_value"] += asset.salvage_value dls_all = asset.depreciation_line_ids.filtered( lambda r: r.type == "depreciate" ) @@ -471,25 +485,29 @@ class AssetReportXlsx(models.AbstractModel): value_depreciated = dls[-1].depreciated_value + dls[-1].amount else: value_depreciated = 0.0 - asset._period_start_value = asset.depreciation_base - value_depreciated - group._period_start_value += asset._period_start_value + asset_entry["_period_start_value"] = ( + asset.depreciation_base - value_depreciated + ) + group_entry["_period_start_value"] += asset_entry["_period_start_value"] # period_end_value dls = dls_all.filtered(lambda r: r.line_date <= wiz.date_to) if dls: value_depreciated = dls[-1].depreciated_value + dls[-1].amount else: value_depreciated = 0.0 - asset._period_end_value = asset.depreciation_base - value_depreciated - group._period_end_value += asset._period_end_value + asset_entry["_period_end_value"] = ( + asset.depreciation_base - value_depreciated + ) + group_entry["_period_end_value"] += asset_entry["_period_end_value"] - asset_entries.append({"asset": asset}) + asset_entries.append(asset_entry) todos = [] for g in group.child_ids: if _has_assets(g, group_val[g]): todos.append(g) - entries.append({"group": group}) + entries.append(group_entry) entries.extend(asset_entries) for todo in todos: self._create_report_entries( @@ -501,8 +519,8 @@ class AssetReportXlsx(models.AbstractModel): ws.set_portrait() ws.fit_to_pages(1, 0) - ws.set_header(self.xls_headers["standard"]) - ws.set_footer(self.xls_footers["standard"]) + ws.set_header(XLS_HEADERS["xls_headers"]["standard"]) + ws.set_footer(XLS_HEADERS["xls_footers"]["standard"]) wl = ws_params["wanted_list"] if "account" not in wl: @@ -523,7 +541,7 @@ class AssetReportXlsx(models.AbstractModel): filter = getattr(self, "{}_filter".format(report)) return filter(wiz, asset) - assets = self._assets.filtered(asset_filter) + assets = data["assets"].filtered(asset_filter) if not assets: return self._empty_report(ws, row_pos, ws_params, data, wiz) @@ -533,7 +551,7 @@ class AssetReportXlsx(models.AbstractModel): row_pos, ws_params, col_specs_section="header", - default_format=self.format_theader_yellow_left, + default_format=FORMATS["format_theader_yellow_left"], ) ws.freeze_panes(row_pos, 0) @@ -550,7 +568,7 @@ class AssetReportXlsx(models.AbstractModel): entries = [] root = wiz.asset_group_id - root_val = self._grouped_assets[root] + root_val = data["grouped_assets"][root] error_dict = { "no_table": self.env["account.asset"], "dups": self.env["account.asset"], @@ -560,16 +578,18 @@ class AssetReportXlsx(models.AbstractModel): # traverse entries in reverse order to calc totals for i, entry in enumerate(reversed(entries)): - group = entry.get("group") if "group" in entry: - parent = group.parent_id - for e in reversed(entries[: -i - 1]): - g = e.get("group") - if g == parent: - g._depreciation_base += group._depreciation_base - g._salvage_value += group._salvage_value - g._period_start_value += group._period_start_value - g._period_end_value += group._period_end_value + parent = entry["group"].parent_id + for parent_entry in reversed(entries[: -i - 1]): + if "group" in parent_entry and parent_entry["group"] == parent: + parent_entry["_depreciation_base"] += entry[ + "_depreciation_base" + ] + parent_entry["_salvage_value"] += entry["_salvage_value"] + parent_entry["_period_start_value"] += entry[ + "_period_start_value" + ] + parent_entry["_period_end_value"] += entry["_period_end_value"] continue processed = [] @@ -599,10 +619,11 @@ class AssetReportXlsx(models.AbstractModel): col_specs_section="asset_group", render_space={ "group": entry["group"], + "group_entry": entry, "period_diff_formula": period_diff_formula, "total_depr_formula": total_depr_formula, }, - default_format=self.format_theader_blue_left, + default_format=FORMATS["format_theader_blue_left"], ) else: @@ -618,11 +639,12 @@ class AssetReportXlsx(models.AbstractModel): ws_params, col_specs_section="asset", render_space={ - "asset": asset, + "asset": entry["asset"], + "asset_entry": entry, "period_diff_formula": period_diff_formula, "total_depr_formula": total_depr_formula, }, - default_format=self.format_tcell_left, + default_format=FORMATS["format_tcell_left"], ) asset_total_formula = depreciation_base_pos and self._rowcol_to_cell( @@ -666,7 +688,7 @@ class AssetReportXlsx(models.AbstractModel): "period_diff_formula": period_diff_formula, "total_depr_formula": total_depr_formula, }, - default_format=self.format_theader_yellow_left, + default_format=FORMATS["format_theader_yellow_left"], ) for k in error_dict: @@ -681,4 +703,4 @@ class AssetReportXlsx(models.AbstractModel): err_msg = _("Assets to be corrected") + ": " err_msg += "%s" % [x[1] for x in error_dict[k].name_get()] err_msg += " - " + _("Reason") + ": " + reason - ws.write_string(row_pos, 0, err_msg, self.format_left_bold) + ws.write_string(row_pos, 0, err_msg, FORMATS["format_left_bold"]) diff --git a/account_asset_management/tests/test_account_asset_management.py b/account_asset_management/tests/test_account_asset_management.py index 255e52fd..9cdc11a8 100644 --- a/account_asset_management/tests/test_account_asset_management.py +++ b/account_asset_management/tests/test_account_asset_management.py @@ -623,3 +623,46 @@ class TestAssetManagement(AccountTestInvoicingCommon): # In the last month of the fiscal year we compensate for the small # deviations if that is necessary. self.assertAlmostEqual(asset.depreciation_line_ids[12].amount, 166.63, places=2) + + def test_15_account_asset_group(self): + """Group's name_get behaves differently depending on code and context""" + group_fa = self.env["account.asset.group"].create( + { + "name": "Fixed Assets", + "code": "FA", + } + ) + group_tfa = self.env["account.asset.group"].create( + { + "name": "Tangible Fixed Assets", + "code": "TFA", + } + ) + # Groups are displayed by code (if any) plus name + self.assertEqual( + self.env["account.asset.group"]._name_search("FA"), + [(group_fa.id, "FA Fixed Assets")], + ) + # Groups with code are shown by code in list views + self.assertEqual( + self.env["account.asset.group"] + .with_context(params={"view_type": "list"}) + ._name_search("FA"), + [(group_fa.id, "FA")], + ) + self.assertEqual( + self.env["account.asset.group"]._name_search("TFA"), + [(group_tfa.id, "TFA Tangible Fixed Assets")], + ) + group_tfa.code = False + group_fa.code = False + self.assertEqual(group_fa.name_get(), [(group_fa.id, "Fixed Assets")]) + # Groups without code are shown by truncated name in lists + self.assertEqual( + group_tfa.name_get(), [(group_tfa.id, "Tangible Fixed Assets")] + ) + self.assertEqual( + group_tfa.with_context(params={"view_type": "list"}).name_get(), + [(group_tfa.id, "Tangible Fixed A...")], + ) + self.assertFalse(self.env["account.asset.group"]._name_search("stessA dexiF")) diff --git a/account_asset_management/tests/test_asset_management_xls.py b/account_asset_management/tests/test_asset_management_xls.py index 3119203e..0b604ff3 100644 --- a/account_asset_management/tests/test_asset_management_xls.py +++ b/account_asset_management/tests/test_asset_management_xls.py @@ -1,11 +1,13 @@ # Copyright 2009-2019 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import time from odoo import fields -from odoo.tests.common import SavepointCase + +from odoo.addons.account.tests.common import AccountTestInvoicingCommon -class TestAssetManagementXls(SavepointCase): +class TestAssetManagementXls(AccountTestInvoicingCommon): @classmethod def setUpClass(cls): super(TestAssetManagementXls, cls).setUpClass() @@ -14,11 +16,54 @@ class TestAssetManagementXls(SavepointCase): cls.xls_report_name = "{}.asset_report_xls".format(module) cls.wiz_model = cls.env["wiz.account.asset.report"] cls.company = cls.env.ref("base.main_company") - asset_group_id = cls.wiz_model._default_asset_group_id() + # Ensure we have something to report on + group_fa = cls.env["account.asset.group"].create( + { + "name": "Fixed Assets", + "code": "FA", + } + ) + group_tfa = cls.env["account.asset.group"].create( + { + "name": "Tangible Fixed Assets", + "code": "TFA", + "parent_id": group_fa.id, + } + ) + ict3Y = cls.env["account.asset.profile"].create( + { + "account_expense_depreciation_id": cls.company_data[ + "default_account_expense" + ].id, + "account_asset_id": cls.company_data["default_account_assets"].id, + "account_depreciation_id": cls.company_data[ + "default_account_assets" + ].id, + "group_ids": [(6, 0, group_tfa.ids)], + "journal_id": cls.company_data["default_journal_purchase"].id, + "name": "Hardware - 3 Years", + "method_time": "year", + "method_number": 3, + "method_period": "year", + } + ) + cls.env["account.asset"].create( + { + "state": "draft", + "method_time": "year", + "method_number": 3, + "method_period": "year", + "name": "Laptop", + "code": "PI00101", + "purchase_value": 1500.0, + "profile_id": ict3Y.id, + "date_start": time.strftime("%Y-01-01"), + } + ).validate() fy_dates = cls.company.compute_fiscalyear_dates(fields.date.today()) wiz_vals = { - "asset_group_id": asset_group_id, + "asset_group_id": group_fa.id, "date_from": fy_dates["date_from"], "date_to": fy_dates["date_to"], } @@ -26,7 +71,7 @@ class TestAssetManagementXls(SavepointCase): cls.report_action = cls.xls_report.xls_export() def test_01_action_xls(self): - """ Check report XLS action """ + """ Check report XLS action and generate report """ self.assertGreaterEqual( self.report_action.items(), { @@ -35,3 +80,7 @@ class TestAssetManagementXls(SavepointCase): "report_name": self.xls_report_name, }.items(), ) + model = self.env["report.%s" % self.report_action["report_name"]].with_context( + active_model=self.xls_report._name, **self.report_action["context"] + ) + model.create_xlsx_report(self.xls_report.ids, data=self.report_action["data"])