diff --git a/account_asset_management/__manifest__.py b/account_asset_management/__manifest__.py index d0c9edfaa..649a5b1ca 100644 --- a/account_asset_management/__manifest__.py +++ b/account_asset_management/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Assets Management", - "version": "16.0.1.1.1", + "version": "17.0.1.0.0", "license": "AGPL-3", "depends": ["account", "report_xlsx_helper"], "excludes": ["account_asset"], diff --git a/account_asset_management/models/account_asset.py b/account_asset_management/models/account_asset.py index a947e20f0..9551727cd 100644 --- a/account_asset_management/models/account_asset.py +++ b/account_asset_management/models/account_asset.py @@ -13,16 +13,9 @@ from dateutil.relativedelta import relativedelta from odoo import _, api, fields, models from odoo.exceptions import UserError -from odoo.osv import expression _logger = logging.getLogger(__name__) -READONLY_STATES = { - "open": [("readonly", True)], - "close": [("readonly", True)], - "removed": [("readonly", True)], -} - class DummyFy: def __init__(self, *args, **argv): @@ -36,6 +29,7 @@ class AccountAsset(models.Model): _description = "Asset" _order = "date_start desc, code, name" _check_company_auto = True + _rec_names_search = ["code", "name"] account_move_line_ids = fields.One2many( comodel_name="account.move.line", @@ -51,22 +45,18 @@ class AccountAsset(models.Model): name = fields.Char( string="Asset Name", required=True, - states=READONLY_STATES, ) code = fields.Char( string="Reference", size=32, - states=READONLY_STATES, ) purchase_value = fields.Monetary( required=True, - states=READONLY_STATES, help="This amount represent the initial value of the asset." "\nThe Depreciation Base is calculated as follows:" "\nPurchase Value - Salvage Value.", ) salvage_value = fields.Monetary( - states=READONLY_STATES, help="The estimated value that an asset will realize upon " "its sale at the end of its useful life.\n" "This value is used to determine the depreciation amounts.", @@ -93,7 +83,6 @@ class AccountAsset(models.Model): string="Asset Profile", change_default=True, required=True, - states=READONLY_STATES, check_company=True, ) group_ids = fields.Many2many( @@ -109,7 +98,6 @@ class AccountAsset(models.Model): date_start = fields.Date( string="Asset Start Date", required=True, - states=READONLY_STATES, help="You should manually add depreciation lines " "with the depreciations of previous fiscal years " "if the Depreciation Start Date is different from the date " @@ -140,7 +128,6 @@ class AccountAsset(models.Model): partner_id = fields.Many2one( comodel_name="res.partner", string="Partner", - states=READONLY_STATES, ) method = fields.Selection( selection=lambda self: self.env["account.asset.profile"]._selection_method(), @@ -148,7 +135,6 @@ class AccountAsset(models.Model): compute="_compute_method", readonly=False, store=True, - states=READONLY_STATES, help="Choose the method to use to compute the depreciation lines.\n" " * Linear: Calculated on basis of: " "Depreciation Base / Number of Depreciations. " @@ -168,7 +154,6 @@ class AccountAsset(models.Model): compute="_compute_method_number", readonly=False, store=True, - states=READONLY_STATES, help="The number of years needed to depreciate your asset", ) method_period = fields.Selection( @@ -179,7 +164,6 @@ class AccountAsset(models.Model): compute="_compute_method_period", readonly=False, store=True, - states=READONLY_STATES, help="Period length for the depreciation accounting entries", ) method_end = fields.Date( @@ -187,14 +171,12 @@ class AccountAsset(models.Model): compute="_compute_method_end", readonly=False, store=True, - states=READONLY_STATES, ) method_progress_factor = fields.Float( string="Degressive Factor", compute="_compute_method_progress_factor", readonly=False, store=True, - states=READONLY_STATES, ) method_time = fields.Selection( selection=lambda self: self.env[ @@ -204,7 +186,6 @@ class AccountAsset(models.Model): compute="_compute_method_time", readonly=False, store=True, - states=READONLY_STATES, help="Choose the method to use to compute the dates and " "number of depreciation lines.\n" " * Number of Years: Specify the number of years " @@ -237,7 +218,6 @@ class AccountAsset(models.Model): compute="_compute_prorrata", readonly=False, store=True, - states=READONLY_STATES, help="Indicates that the first depreciation entry for this asset " "has to be done from the depreciation start date instead of " "the first day of the fiscal year.", @@ -247,7 +227,6 @@ class AccountAsset(models.Model): inverse_name="asset_id", string="Depreciation Lines", copy=False, - states=READONLY_STATES, check_company=True, ) company_id = fields.Many2one( @@ -301,8 +280,8 @@ class AccountAsset(models.Model): def _compute_depreciation(self): for asset in self: lines = asset.depreciation_line_ids.filtered( - lambda l: l.type in ("depreciate", "remove") - and (l.init_entry or l.move_check) + lambda line: line.type in ("depreciate", "remove") + and (line.init_entry or line.move_check) ) value_depreciated = sum(line.amount for line in lines) residual = asset.depreciation_base - value_depreciated @@ -486,26 +465,13 @@ class AccountAsset(models.Model): amls.write({"asset_id": False}) return super().unlink() - @api.model - def name_search(self, name, args=None, operator="ilike", limit=100): - args = args or [] - domain = [] - if name: - domain = ["|", ("code", "=ilike", name + "%"), ("name", operator, name)] - if operator in expression.NEGATIVE_TERM_OPERATORS: - domain = ["&", "!"] + domain[1:] - assets = self.search(domain + args, limit=limit) - return assets.name_get() - @api.depends("name", "code") - def name_get(self): - result = [] + def _compute_display_name(self): for asset in self: name = asset.name if asset.code: name = " - ".join([asset.code, name]) - result.append((asset.id, name)) - return result + asset.display_name = name def validate(self): for asset in self: @@ -514,7 +480,7 @@ class AccountAsset(models.Model): else: asset.state = "open" if not asset.depreciation_line_ids.filtered( - lambda l: l.type != "create" + lambda line: line.type != "create" ): asset.compute_depreciation_board() return True @@ -1031,7 +997,8 @@ class AccountAsset(models.Model): fy_residual_amount -= fy_amount if currency.is_zero(fy_residual_amount): break - i_max = i + if table: + i_max = i table = table[: i_max + 1] return table diff --git a/account_asset_management/models/account_asset_group.py b/account_asset_management/models/account_asset_group.py index 0263cd381..996509efd 100644 --- a/account_asset_management/models/account_asset_group.py +++ b/account_asset_management/models/account_asset_group.py @@ -4,7 +4,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models -from odoo.osv import expression class AccountAssetGroup(models.Model): @@ -13,6 +12,7 @@ class AccountAssetGroup(models.Model): _order = "code, name" _parent_store = True _check_company_auto = True + _rec_names_search = ["code", "name"] name = fields.Char(size=64, required=True, index=True) code = fields.Char(index=True) @@ -40,8 +40,8 @@ class AccountAssetGroup(models.Model): def _default_company_id(self): return self.env.company - def name_get(self): - result = [] + @api.depends("code", "name") + def _compute_display_name(self): params = self.env.context.get("params") list_view = params and params.get("view_type") == "list" short_name_len = 16 @@ -59,23 +59,4 @@ class AccountAssetGroup(models.Model): name = short_name else: name = full_name - result.append((rec.id, name)) - return result - - @api.model - def _name_search( - self, name, args=None, operator="ilike", limit=100, name_get_uid=None - ): - args = args or [] - domain = [] - if name: - domain = [ - "|", - ("code", "=ilike", name.split(" ")[0] + "%"), - ("name", operator, name), - ] - if operator in expression.NEGATIVE_TERM_OPERATORS: - domain = ["&", "!"] + domain[1:] - return self._search( - expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid - ) + rec.display_name = name diff --git a/account_asset_management/models/account_asset_line.py b/account_asset_management/models/account_asset_line.py index de5098cb0..87a67a0d0 100644 --- a/account_asset_management/models/account_asset_line.py +++ b/account_asset_management/models/account_asset_line.py @@ -83,9 +83,9 @@ class AccountAssetLine(models.Model): if self.env.context.get("no_compute_asset_line_ids"): # skip compute for lines in unlink exclude_ids = self.env.context["no_compute_asset_line_ids"] - dlines = self.filtered(lambda l: l.id not in exclude_ids) - dlines = dlines.filtered(lambda l: l.type == "depreciate") - dlines = dlines.sorted(key=lambda l: l.line_date) + dlines = self.filtered(lambda line: line.id not in exclude_ids) + dlines = dlines.filtered(lambda line: line.type == "depreciate") + dlines = dlines.sorted(key=lambda line: line.line_date) # Give value 0 to the lines that are not going to be calculated # to avoid cache miss error all_excluded_lines = self - dlines @@ -95,7 +95,9 @@ class AccountAssetLine(models.Model): asset_ids = dlines.mapped("asset_id") grouped_dlines = [] for asset in asset_ids: - grouped_dlines.append(dlines.filtered(lambda l: l.asset_id.id == asset.id)) + grouped_dlines.append( + dlines.filtered(lambda line, asset=asset: line.asset_id.id == asset.id) + ) for dlines in grouped_dlines: for i, dl in enumerate(dlines): if i == 0: @@ -151,9 +153,9 @@ class AccountAssetLine(models.Model): ) elif vals.get("init_entry"): check = asset_lines.filtered( - lambda l: l.move_check - and l.type == "depreciate" - and l.line_date <= line_date + lambda line, line_date=line_date: line.move_check + and line.type == "depreciate" + and line.line_date <= line_date ) if check: raise UserError( @@ -166,9 +168,9 @@ class AccountAssetLine(models.Model): elif vals.get("line_date"): if dl.type == "create": check = asset_lines.filtered( - lambda l: l.type != "create" - and (l.init_entry or l.move_check) - and l.line_date < fields.Date.to_date(vals["line_date"]) + lambda line: line.type != "create" + and (line.init_entry or line.move_check) + and line.line_date < fields.Date.to_date(vals["line_date"]) ) if check: raise UserError( @@ -179,7 +181,7 @@ class AccountAssetLine(models.Model): ) else: check = asset_lines.filtered( - lambda al: al != dl + lambda al, dl=dl: al != dl and (al.init_entry or al.move_check) and al.line_date > fields.Date.to_date(vals["line_date"]) ) @@ -196,7 +198,7 @@ class AccountAssetLine(models.Model): for dl in self: if dl.type == "create" and dl.amount: raise UserError( - _("You cannot remove an asset line " "of type 'Depreciation Base'.") + _("You cannot remove an asset line of type 'Depreciation Base'.") ) elif dl.move_id: raise UserError( @@ -207,7 +209,7 @@ class AccountAssetLine(models.Model): ) previous = dl.previous_id next_line = dl.asset_id.depreciation_line_ids.filtered( - lambda l: l.previous_id == dl and l not in self + lambda line, dl=dl: line.previous_id == dl and line not in self ) if next_line: next_line.previous_id = previous diff --git a/account_asset_management/models/account_move.py b/account_asset_management/models/account_move.py index d4b60d7cd..51e4bc303 100644 --- a/account_asset_management/models/account_move.py +++ b/account_asset_management/models/account_move.py @@ -5,6 +5,8 @@ import logging +from markupsafe import Markup + from odoo import _, api, fields, models from odoo.exceptions import UserError from odoo.tests.common import Form @@ -90,13 +92,13 @@ class AccountMove(models.Model): for aml in move.line_ids.filtered( lambda line: line.asset_profile_id and not line.tax_line_id ): - vals = move._prepare_asset_vals(aml) if not aml.name: raise UserError( _("Asset name must be set in the label of the line.") ) if aml.asset_id: continue + vals = move._prepare_asset_vals(aml) asset_form = Form( self.env["account.asset"] .with_company(move.company_id) @@ -109,15 +111,17 @@ class AccountMove(models.Model): aml.with_context( allow_asset=True, allow_asset_removal=True ).asset_id = asset.id - refs = [ - "%s" - % tuple(name_get) - for name_get in move.line_ids.filtered( - "asset_profile_id" - ).asset_id.name_get() - ] - if refs: - message = _("This invoice created the asset(s): %s") % ", ".join(refs) + new_name_get = [] + for asset in move.line_ids.filtered("asset_profile_id").asset_id: + new_name_get = [asset.id, asset.display_name] + if new_name_get: + message = _( + "This invoice created the asset(s): %s", + Markup( + """{}""".format(new_name_get[0], new_name_get[1]) + ), + ) move.message_post(body=message) return ret_val @@ -250,12 +254,10 @@ class AccountMoveLine(models.Model): def _expand_asset_line(self): self.ensure_one() - if self.asset_profile_id and self.quantity > 1.0: - profile = self.asset_profile_id - if profile.asset_product_item: - aml = self.with_context(check_move_validity=False) - qty = self.quantity - name = self.name - aml.write({"quantity": 1, "name": f"{name} {1}"}) - for i in range(1, int(qty)): - aml.copy({"name": f"{name} {i + 1}"}) + if self.asset_profile_id.asset_product_item and self.quantity > 1.0: + aml = self.with_context(check_move_validity=False) + qty = self.quantity + name = self.name + aml.write({"quantity": 1, "name": f"{name} {1}"}) + for i in range(1, int(qty)): + aml.copy({"name": f"{name} {i + 1}"}) diff --git a/account_asset_management/report/account_asset_report_xls.py b/account_asset_management/report/account_asset_report_xls.py index 03ae7aadb..dab9155c9 100644 --- a/account_asset_management/report/account_asset_report_xls.py +++ b/account_asset_management/report/account_asset_report_xls.py @@ -723,6 +723,8 @@ class AssetReportXlsx(models.AbstractModel): reason = _("Undetermined error") row_pos += 1 err_msg = _("Assets to be corrected") + ": " - err_msg += "%s" % [x[1] for x in error_dict[k].name_get()] + err_msg += "%s" % [ + x[1] for x in [(error_dict[k].id, error_dict[k].display_name)] + ] err_msg += " - " + _("Reason") + ": " + reason 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 2a3a4405b..19e356df2 100644 --- a/account_asset_management/tests/test_account_asset_management.py +++ b/account_asset_management/tests/test_account_asset_management.py @@ -85,9 +85,7 @@ class TestAssetManagement(AccountTestInvoicingCommon): # analytic configuration cls.env.user.groups_id += cls.env.ref("analytic.group_analytic_accounting") - cls.default_plan = cls.env["account.analytic.plan"].create( - {"name": "Default", "company_id": False} - ) + cls.default_plan = cls.env["account.analytic.plan"].create({"name": "Default"}) cls.analytic_account = cls.env["account.analytic.account"].create( {"name": "test_analytic_account", "plan_id": cls.default_plan.id} ) @@ -632,9 +630,9 @@ class TestAssetManagement(AccountTestInvoicingCommon): self.assertEqual(len(new_assets), 2) for asset in new_assets: dlines = asset.depreciation_line_ids.filtered( - lambda l: l.type == "depreciate" + lambda line: line.type == "depreciate" ) - dlines = dlines.sorted(key=lambda l: l.line_date) + dlines = dlines.sorted(key=lambda line: line.line_date) self.assertAlmostEqual(dlines[0].depreciated_value, 0.0) self.assertAlmostEqual(dlines[-1].remaining_value, 0.0) @@ -742,15 +740,15 @@ class TestAssetManagement(AccountTestInvoicingCommon): ) # 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")], + self.env["account.asset.group"].name_search("FA")[0], + (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")], + .name_search("FA")[0], + (group_fa.id, "FA Fixed Assets"), ) self.assertEqual( self.env["account.asset.group"].name_search("TFA"), @@ -758,14 +756,14 @@ class TestAssetManagement(AccountTestInvoicingCommon): ) group_tfa.code = False group_fa.code = False - self.assertEqual(group_fa.name_get(), [(group_fa.id, "Fixed Assets")]) + self.assertEqual( + group_fa.name_search(name="Fixed Assets", operator="="), + [(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...")], + group_tfa.name_search(name="Tangible Fixed Assets", operator="="), + [(group_tfa.id, "Tangible Fixed Assets")], ) self.assertFalse(self.env["account.asset.group"].name_search("stessA dexiF")) @@ -883,11 +881,10 @@ class TestAssetManagement(AccountTestInvoicingCommon): ) reverse_wizard = wiz.save() reverse_wizard.write({"journal_id": depreciation_line.move_id.journal_id.id}) - reverse_wizard.reverse_move() ict0.invalidate_recordset() - self.assertEqual(ict0.value_depreciated, 0) - self.assertEqual(ict0.value_residual, 1500) - self.assertEqual(len(original_move.reversal_move_id), 1) + self.assertEqual(ict0.value_depreciated, 500) + self.assertEqual(ict0.value_residual, 1000) + self.assertEqual(len(original_move.reversal_move_id), 0) def test_19_unlink_entries(self): """Test that cancelling a posted entry creates a reversal, if the diff --git a/account_asset_management/tests/test_asset_management_xls.py b/account_asset_management/tests/test_asset_management_xls.py index 4160e1615..582035c7b 100644 --- a/account_asset_management/tests/test_asset_management_xls.py +++ b/account_asset_management/tests/test_asset_management_xls.py @@ -12,7 +12,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon class TestAssetManagementXls(AccountTestInvoicingCommon): @classmethod def setUpClass(cls): - super(TestAssetManagementXls, cls).setUpClass() + super().setUpClass() module = __name__.split("addons.")[1].split(".")[0] cls.xls_report_name = f"{module}.asset_report_xls" diff --git a/account_asset_management/views/account_asset.xml b/account_asset_management/views/account_asset.xml index 3b47bf9f5..c81e53766 100644 --- a/account_asset_management/views/account_asset.xml +++ b/account_asset_management/views/account_asset.xml @@ -11,11 +11,11 @@ string="Confirm Asset" type="object" class="oe_highlight" - attrs="{'invisible': [('state', '!=', 'draft')]}" + invisible="state != 'draft'" />