# Copyright 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited from odoo import api, fields, models REASON_DUPLICATE = 1 REASON_DEFAULT = 2 REASON_DEFAULT_FALSE = 3 REASON_UNKNOWN_MODEL = 4 class CleanupPurgeLineProperty(models.TransientModel): _inherit = "cleanup.purge.line" _name = "cleanup.purge.line.property" _description = "Purge properties" wizard_id = fields.Many2one( "cleanup.purge.wizard.property", "Purge Wizard", readonly=True ) property_id = fields.Many2one("ir.property") reason = fields.Selection( [ (REASON_DUPLICATE, "Duplicated property"), (REASON_DEFAULT, "Same value as default"), (REASON_DEFAULT_FALSE, "Empty default property"), (REASON_UNKNOWN_MODEL, "Unknown model"), ] ) @api.multi def purge(self): """Delete properties""" self.write({"purged": True}) return self.mapped("property_id").unlink() class CleanupPurgeWizardProperty(models.TransientModel): _inherit = "cleanup.purge.wizard" _name = "cleanup.purge.wizard.property" _description = "Purge properties" @api.model def find(self): """ Search property records which are duplicated or the same as the default """ result = [] default_properties = self.env["ir.property"].search( [ ("res_id", "=", False), ] ) handled_field_ids = [] for prop in default_properties: value = None try: value = prop.get_by_record() except KeyError: result.append( { "name": "%s@%s: %s" % ( prop.name, prop.res_id, value, ), "property_id": prop.id, "reason": REASON_UNKNOWN_MODEL, } ) continue if not value: result.append( { "name": "%s@%s: %s" % ( prop.name, prop.res_id, value, ), "property_id": prop.id, "reason": REASON_DEFAULT_FALSE, } ) continue if prop.fields_id.id in handled_field_ids: continue domain = [ ("id", "!=", prop.id), ("fields_id", "=", prop.fields_id.id), # =? explicitly tests for None or False, not falsyness ("value_float", "=?", prop.value_float or False), ("value_integer", "=?", prop.value_integer or False), ("value_text", "=?", prop.value_text or False), ("value_binary", "=?", prop.value_binary or False), ("value_reference", "=?", prop.value_reference or False), ("value_datetime", "=?", prop.value_datetime or False), ] if prop.company_id: domain.append(("company_id", "=", prop.company_id.id)) else: domain.extend( [ "|", ("company_id", "=", False), ( "company_id", "in", self.env["res.company"] .search( [ ( "id", "not in", default_properties.filtered( lambda x: x.company_id and x.fields_id == prop.fields_id ).ids, ) ] ) .ids, ), ] ) for redundant_property in self.env["ir.property"].search(domain): result.append( { "name": "%s@%s: %s" % (prop.name, redundant_property.res_id, prop.get_by_record()), "property_id": redundant_property.id, "reason": REASON_DEFAULT, } ) handled_field_ids.append(prop.fields_id.id) self.env.cr.execute( """ with grouped_properties(ids, cnt) as ( select array_agg(id), count(*) from ir_property group by res_id, company_id, fields_id ) select ids from grouped_properties where cnt > 1 """ ) for (ids,) in self.env.cr.fetchall(): # odoo uses the first property found by search for prop in self.env["ir.property"].search([("id", "in", ids)])[1:]: result.append( { "name": "%s@%s: %s" % (prop.name, prop.res_id, prop.get_by_record()), "property_id": prop.id, "reason": REASON_DUPLICATE, } ) return result purge_line_ids = fields.One2many( "cleanup.purge.line.property", "wizard_id", "Properties to purge" )