Search code examples
pythonodooodoo-14

Odoo Custom filter function


I already tried everything and searched everywhere for an answer but I wasn't successful.

I want to implement a custom function to retrieve filtered values for a Many2one selection list. Usually you would use a domain for that but the domain-options given are not sufficient to achieve my goal.

What function do I have to override to modify the selection list for a given Many2one field?

Thank you, Lars

UPDATE:

Thank you for your answers. I used name_search to analyze the generated WHERE clause. Here what I want to achieve and my findings so far:

programs = fields.Many2many(
        comodel_name='hr.program',
        relation='hr_process_onboarding_wizard_programs')
program_department = fields.Many2one(
        comodel_name='hr.department',
        domain="[('programs', 'in', programs)]")

Field programs is represented as a many2many_checkboxes widget. When I select 2 values, the following domain-filter is being passed to name_search: ['programs', 'in', [1, 2]]

This will generate the following SQL-Query (excerpt of the interesting part): (SELECT "hr_department_id" FROM "hr_programs_departments" WHERE "hr_program_id" IN (1,2))

The result list is of course the UNION of programs [1,2] but I would expect the INTERSECTION of programs [1,2].

Afaik there is no domain filter to get the intersection.

UPDATE 2:

After thinking about the given filter operators I would expect = to do exactly what I want but operator = is generating the same WHERE clause as for in.


Solution

  • This is my quick-hack solution using name_search in class HrDepartment.
    I added a attribute context="{'intersect': True}" to the field in the corresponding view to be failsafe in other contexts.
    The domain is still in place and being used in must_contain_programs.

    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        is_intersect_context = self._context.get('intersect')
        must_contain_programs = args[0][2]
        if(is_intersect_context and len(must_contain_programs) > 1):
            all_departments = self.env['hr.department'].search([])
            filtered_departments = []
            for department in all_departments:
                if all(program_id in department.programs.ids for program_id in must_contain_programs):
                    filtered_departments.append(department)
            if len(filtered_departments) > 0:
                intersect_res = []
                for filtered_department in filtered_departments:
                    intersect_res.append((filtered_department.id, filtered_department.name))
                intersect_res.sort(key=lambda tuple: tuple[0])
                if name != '':
                    res = list(filter(lambda tuple: name.upper() in tuple[1].upper(), intersect_res))
                else:
                    res = intersect_res
        else:
            res = super(HrDepartment, self).name_search(name, args, operator, limit)
        return res