def name_search(self, name, args=None, operator='ilike', limit=100):
        res = super(ResPartner, self).name_search(name,
                                                  args,
                                                  operator=operator,
                                                  limit=limit)
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or ' WHERE '

            # search on the name of the contacts and of its company or search by phone also
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(where=where_str,
                               operator=operator,
                               email=unaccent('email'),
                               display_name=unaccent('display_name'),
                               reference=unaccent('ref'),
                               percent=unaccent('%s'))

            where_clause_params += [search_name] * 4
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = map(lambda x: x[0], self.env.cr.fetchall())

            if partner_ids:
                return self.browse(partner_ids).name_get()
            if not partner_ids:
                partner_ids = self.search([
                    '|', ('phone', operator, name), '|',
                    ('mobile', operator, name), '|',
                    ('mobile1', operator, name), '|',
                    ('mobile2', operator, name), ('whatsapp', operator, name)
                ])
                return partner_ids.name_get()
            else:
                return []
        return res
Beispiel #2
0
    def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
        self = self.with_user(name_get_uid or self.env.uid)
        # as the implementation is in SQL, we force the recompute of fields if necessary
        self.recompute(['display_name'])
        self.flush()
        if args is None:
            args = []
        order_by_rank = self.env.context.get('res_partner_search_mode') 
        if (name or order_by_rank) and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql()
            from_str = from_clause if from_clause else 'res_partner'
            where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            fields = self._get_name_search_order_by_fields()

            query = """SELECT res_partner.id
                         FROM {from_str}
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent}
                           OR {vat} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {fields} {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(from_str=from_str,
                               fields=fields,
                               where=where_str,
                               operator=operator,
                               email=unaccent('res_partner.email'),
                               display_name=unaccent('res_partner.display_name'),
                               reference=unaccent('res_partner.ref'),
                               percent=unaccent('%s'),
                               vat=unaccent('res_partner.vat'),)

            where_clause_params += [search_name]*3  # for email / display_name, reference
            where_clause_params += [re.sub('[^a-zA-Z0-9]+', '', search_name) or None]  # for vat
            where_clause_params += [search_name]  # for order by
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return models.lazy_name_get(self.browse(partner_ids))
            else:
                return []
        return super(Partner, self)._name_search(name, args, operator=operator, limit=limit, name_get_uid=name_get_uid)
Beispiel #3
0
    def name_search(self, name, args=None, operator='ilike', limit=100):
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            from_str = from_clause if from_clause else 'res_partner'
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT res_partner.id
                         FROM {from_str}
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent}
                           OR {vat} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(
                from_str=from_str,
                where=where_str,
                operator=operator,
                email=unaccent('res_partner.email'),
                display_name=unaccent('res_partner.display_name'),
                reference=unaccent('res_partner.ref'),
                percent=unaccent('%s'),
                vat=unaccent('res_partner.vat'),
            )

            where_clause_params += [search_name] * 5
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []
        return super(Partner, self).name_search(name,
                                                args,
                                                operator=operator,
                                                limit=limit)
Beispiel #4
0
    def name_search(self, name, args=None, operator="ilike", limit=100):
        if args is None:
            args = []
        if name and operator in ("=", "ilike", "=ilike", "like", "=like"):
            self.check_access_rights("read")
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, "read")
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or " WHERE "

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ("ilike", "like"):
                search_name = "%%%s%%" % name
            if operator in ("=ilike", "=like"):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
              FROM res_partner
              {where} (
                {company_registry} {operator} {percent}
                OR {display_name} {operator} {percent}
                OR {reference} {operator} {percent}
                OR {company_registry} {operator} {percent}
              )
              -- don't panic, trust postgres bitmap
              ORDER BY {display_name} {operator} {percent} desc,
                      {display_name}
            """.format(
                where=where_str,
                operator=operator,
                email=unaccent("email"),
                display_name=unaccent("display_name"),
                reference=unaccent("ref"),
                company_registry=unaccent("company_registry"),
                percent=unaccent("%s"),
            )

            where_clause_params += [search_name] * 5
            if limit:
                query += " limit %s"
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = map(lambda x: x[0], self.env.cr.fetchall())

            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []
        return super(ResPartner, self).name_search(name,
                                                   args,
                                                   operator=operator,
                                                   limit=limit)
Beispiel #5
0
    def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
        self = self.sudo(name_get_uid or self.env.uid)
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql()
            from_str = from_clause if from_clause else 'res_partner'
            where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT res_partner.id
                         FROM {from_str}
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent}
                           OR {vat} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(from_str=from_str,
                               where=where_str,
                               operator=operator,
                               email=unaccent('res_partner.email'),
                               display_name=unaccent('res_partner.display_name'),
                               reference=unaccent('res_partner.ref'),
                               percent=unaccent('%s'),
                               vat=unaccent('res_partner.vat'),)

            where_clause_params += [search_name]*3  # for email / display_name, reference
            where_clause_params += [re.sub('[^a-zA-Z0-9]+', '', search_name) or None]  # for vat
            where_clause_params += [search_name]  # for order by
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return models.lazy_name_get(self.browse(partner_ids))
            else:
                return []
        return super(Partner, self)._name_search(name, args, operator=operator, limit=limit, name_get_uid=name_get_uid)
Beispiel #6
0
    def name_search(self, name, args=None, operator='ilike', limit=100):
        result = super(ResPartner, self).name_search(name,
                                                     args=None,
                                                     operator='ilike',
                                                     limit=100)
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({phone} {operator} {percent}
                           OR {mobile} {operator} {percent})
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(
                where=where_str,
                operator=operator,
                phone=unaccent('phone'),
                display_name=unaccent('display_name'),
                mobile=unaccent('mobile'),
                percent=unaccent('%s'),
            )

            where_clause_params += [search_name] * 3
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]
            if partner_ids:
                result += self.browse(partner_ids).name_get()
        return result
Beispiel #7
0
    def name_search(self, name, args=None, operator='ilike', limit=100):
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql()
            where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent}
                           OR {vat} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(where=where_str,
                               operator=operator,
                               email=unaccent('email'),
                               display_name=unaccent('display_name'),
                               reference=unaccent('ref'),
                               percent=unaccent('%s'),
                               vat=unaccent('vat'),)

            where_clause_params += [search_name]*5
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []
        return super(Partner, self).name_search(name, args, operator=operator, limit=limit)
Beispiel #8
0
    def name_search(self, name, args=None, operator='ilike', limit=100):
        res = super(ResPartner, self).name_search(name, args, operator, limit)
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            where_query = self._where_calc(args)
            from_clause, where_clause, where_clause_params = where_query.get_sql()
            where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({fal_shortname} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(where=where_str,
                               operator=operator,
                               fal_shortname=unaccent('fal_shortname'),
                               display_name=unaccent('display_name'),
                               percent=unaccent('%s'),)

            where_clause_params += [search_name]*2
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]
            super_partner_ids = []
            for partner_id in res:
                if partner_id[0] not in partner_ids:
                    partner_ids.append(partner_id[0])
            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []
        return super(ResPartner, self).name_search(name, args, operator=operator, limit=limit)
Beispiel #9
0
    def _get_invoice_matching_query(self, st_lines_with_partner, excluded_ids):
        ''' Returns the query applying the current invoice_matching reconciliation
        model to the provided statement lines.

        :param st_lines_with_partner: A list of tuples (statement_line, partner),
                                      associating each statement line to treate with
                                      the corresponding partner, given by the partner map
        :param excluded_ids:    Account.move.lines to exclude.
        :return:                (query, params)
        '''
        self.ensure_one()
        if self.rule_type != 'invoice_matching':
            raise UserError(_('Programmation Error: Can\'t call _get_invoice_matching_query() for different rules than \'invoice_matching\''))

        unaccent = get_unaccent_wrapper(self._cr)

        # N.B: 'communication_flag' is there to distinguish invoice matching through the number/reference
        # (higher priority) from invoice matching using the partner (lower priority).
        query = r'''
        SELECT
            st_line.id                          AS id,
            aml.id                              AS aml_id,
            aml.currency_id                     AS aml_currency_id,
            aml.date_maturity                   AS aml_date_maturity,
            aml.amount_residual                 AS aml_amount_residual,
            aml.amount_residual_currency        AS aml_amount_residual_currency,
            ''' + self._get_select_communication_flag() + r''' AS communication_flag,
            ''' + self._get_select_payment_reference_flag() + r''' AS payment_reference_flag
        FROM account_bank_statement_line st_line
        JOIN account_move st_line_move          ON st_line_move.id = st_line.move_id
        JOIN res_company company                ON company.id = st_line_move.company_id
        , account_move_line aml
        LEFT JOIN account_move move             ON move.id = aml.move_id AND move.state = 'posted'
        LEFT JOIN account_account account       ON account.id = aml.account_id
        LEFT JOIN res_partner aml_partner       ON aml.partner_id = aml_partner.id
        LEFT JOIN account_payment payment       ON payment.move_id = move.id
        WHERE
            aml.company_id = st_line_move.company_id
            AND move.state = 'posted'
            AND account.reconcile IS TRUE
            AND aml.reconciled IS FALSE
        '''

        # Add conditions to handle each of the statement lines we want to match
        st_lines_queries = []
        for st_line, partner in st_lines_with_partner:
            # In case we don't have any partner for this line, we try assigning one with the rule mapping
            if st_line.amount > 0:
                st_line_subquery = r"aml.balance > 0"
            else:
                st_line_subquery = r"aml.balance < 0"

            if self.match_same_currency:
                st_line_subquery += r" AND COALESCE(aml.currency_id, company.currency_id) = %s" % (st_line.foreign_currency_id.id or st_line.move_id.currency_id.id)

            if partner:
                st_line_subquery += r" AND aml.partner_id = %s" % partner.id
            else:
                st_line_subquery += r"""
                    AND
                    (
                        substring(REGEXP_REPLACE(st_line.payment_ref, '[^0-9\s]', '', 'g'), '\S(?:.*\S)*') != ''
                        AND
                        (
                            (""" + self._get_select_communication_flag() + """)
                            OR
                            (""" + self._get_select_payment_reference_flag() + """)
                        )
                    )
                    OR
                    (
                        /* We also match statement lines without partners with amls
                        whose partner's name's parts (splitting on space) are all present
                        within the payment_ref, in any order, with any characters between them. */

                        aml_partner.name IS NOT NULL
                        AND """ + unaccent("st_line.payment_ref") + r""" ~* ('^' || (
                            SELECT string_agg(concat('(?=.*\m', chunk[1], '\M)'), '')
                              FROM regexp_matches(""" + unaccent("aml_partner.name") + r""", '\w{3,}', 'g') AS chunk
                        ))
                    )
                """

            st_lines_queries.append(r"st_line.id = %s AND (%s)" % (st_line.id, st_line_subquery))

        query += r" AND (%s) " % " OR ".join(st_lines_queries)

        params = {}

        # If this reconciliation model defines a past_months_limit, we add a condition
        # to the query to only search on move lines that are younger than this limit.
        if self.past_months_limit:
            date_limit = fields.Date.context_today(self) - relativedelta(months=self.past_months_limit)
            query += "AND aml.date >= %(aml_date_limit)s"
            params['aml_date_limit'] = date_limit

        # Filter out excluded account.move.line.
        if excluded_ids:
            query += 'AND aml.id NOT IN %(excluded_aml_ids)s'
            params['excluded_aml_ids'] = tuple(excluded_ids)

        if self.matching_order == 'new_first':
            query += ' ORDER BY aml_date_maturity DESC, aml_id DESC'
        else:
            query += ' ORDER BY aml_date_maturity ASC, aml_id ASC'

        return query, params
Beispiel #10
0
    def name_search(self, name, args=None, operator="ilike", limit=100):

        if name and operator in ("=", "ilike", "=ilike", "like", "=like"):
            self.check_access_rights("read")

            # Cetmix force search by email
            email = False
            if args:
                for arg in args:
                    if arg[0] == "email":
                        email = arg
                        args.remove(arg)
                        break
            if email:
                email_args = self._tweak_args([("email", operator, email)])
            else:
                email_args = self._tweak_args([("email", operator, name)])

            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, "read")
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            from_str = from_clause if from_clause else "res_partner"
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or " WHERE "

            # Compose email query args
            where_query_email = self.with_context(
                active_test=False)._where_calc(email_args)
            (
                from_clause_email,
                where_clause_email,
                where_clause_params_email,
            ) = where_query_email.get_sql()

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ("ilike", "like"):
                search_name = "%%%s%%" % name
            if operator in ("=ilike", "=like"):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT res_partner.id
                                     FROM {from_str}
                                  {where} ({display_name} {operator} {percent}
                                       OR {reference} {operator} {percent}
                                       OR {vat} {operator} {percent}
                                       OR {email_addresses})
                                       -- don't panic, trust postgres bitmap
                                 ORDER BY {display_name} {operator} {percent} desc,
                                          {display_name}
                                """.format(
                from_str=from_str,
                where=where_str,
                operator=operator,
                email_addresses=where_clause_email,
                display_name=unaccent("res_partner.display_name"),
                reference=unaccent("res_partner.ref"),
                percent=unaccent("%s"),
                vat=unaccent("res_partner.vat"),
            )

            where_clause_params += [search_name] * 3
            where_clause_params += where_clause_params_email  # partner ids
            where_clause_params.append(search_name)  # The last one for sort
            if limit:
                query += " limit %s"
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []

        return super(Partner, self).name_search(name=name,
                                                args=args,
                                                operator=operator,
                                                limit=limit)
Beispiel #11
0
    def find_duplicates(self, batch_commits=False):
        """
        Search for duplicate records and create the data_merge.group along with its data_merge.record

        :param bool batch_commits: If set, will automatically commit every X records
        """

        # YTI CLEAN: Use add_join from the Query object maybe ?
        def field_join(field_id, table, res_model_name, env):
            join, join_data = '', ()

            # Related non-stored field
            if rule.field_id.related and not rule.field_id.store:
                IrField = self.env['ir.model.fields']._get(
                    res_model_name,
                    field_id.related.split('.')[0])
                rel_table = IrField.relation.replace('.', '_')
                join_data = (rel_table, IrField.relation_field, table,
                             env[IrField.relation]._rec_name)
            # Many2one
            elif rule.field_id.relation:
                rel_table = field_id.relation.replace('.', '_')
                join_data = (table, field_id.name, rel_table,
                             env[field_id.relation]._rec_name)

            if join_data:
                rel_where = '%s."%s" = %s.id' % (join_data[0], join_data[1],
                                                 join_data[2])
                join = """JOIN %s ON %s""" % (rel_table, rel_where)
                field_name = '%s."%s"' % (join_data[2], join_data[3])
            else:
                field_name = '%s."%s"' % (table, field_id.name)

            return (field_name, join)

        unaccent = get_unaccent_wrapper(self.env.cr)
        self.flush()
        for dm_model in self:
            t1 = timeit.default_timer()
            ids = []
            for rule in dm_model.rule_ids:
                table = self.env[dm_model.res_model_name]._table

                field_name, join = field_join(rule.field_id, table,
                                              dm_model.res_model_name,
                                              self.env)

                if rule.match_mode == 'accent':
                    field_name = unaccent(field_name)

                domain = ast.literal_eval(dm_model.domain or '[]')
                tables, where_clause, where_clause_params = self.env[
                    dm_model.res_model_name]._where_calc(domain).get_sql()
                where_clause = where_clause and ('AND %s' % where_clause) or ''

                group_by = ''
                if 'company_id' in self.env[
                        dm_model.
                        res_model_name]._fields and not dm_model.mix_by_company:
                    group_by = ', %s.company_id' % table

                # Get all the rows matching the rule defined
                # (e.g. exact match of the name) having at least 2 records
                # Each row contains the matched value and an array of matching records:
                #   | value matched | {array of record IDs matching the field}
                query = """
                    SELECT
                        %(field)s as group_field_name,
                        array_agg(
                            %(model_table)s.id order by %(model_table)s.id asc
                        )
                    FROM %(tables)s
                        %(join)s
                        WHERE length(%(field)s) > 0 %(where_clause)s
                    GROUP BY group_field_name %(group_by)s
                        HAVING COUNT(%(field)s) > 1""" % {
                    'field': field_name,
                    'model_table': table,
                    'tables': tables,
                    'join': join,
                    'where_clause': where_clause,
                    'group_by': group_by,
                }

                try:
                    self._cr.execute(query, where_clause_params)
                except ProgrammingError:
                    # YTI TODO: Explain why this is valid to suppose that the extentions
                    # are missing
                    raise UserError(
                        'Missing required PostgreSQL extension: unaccent')

                rows = self._cr.fetchall()
                ids = ids + [row[1] for row in rows]

            # Fetches the IDs of all the records who already matched (and are not merged),
            # as well as the discarded ones.
            # This prevents creating twice the same groups.
            self._cr.execute(
                """
                SELECT
                    ARRAY_AGG(res_id ORDER BY res_id ASC)
                FROM data_merge_record
                WHERE model_id = %s
                GROUP BY group_id""", [dm_model.id])
            done_groups_res_ids = [set(x[0]) for x in self._cr.fetchall()]

            _logger.info('Query identification done after %s' %
                         str(timeit.default_timer() - t1))
            t1 = timeit.default_timer()
            if ast.literal_eval(self.env['ir.config_parameter'].get_param(
                    'data_merge.merge_lists', 'True')):
                merge_list = merge_common_lists
            else:
                merge_list = lambda x: x
            groups_to_create = [set(r) for r in merge_list(ids) if len(r) > 1]
            _logger.info('Merging lists done after %s' %
                         str(timeit.default_timer() - t1))
            t1 = timeit.default_timer()
            _logger.info('Record creation started at %s', str(t1))
            groups_created = 0
            groups_to_create_count = len(groups_to_create)
            for group_to_create in groups_to_create:
                groups_created += 1
                if groups_created % 100 == 0:
                    _logger.info('Created groups %s / %s' %
                                 (groups_created, groups_to_create_count))

                # Check if the IDs of the group to create is already part of an existing group
                # e.g.
                #   The group with records A B C already exists:
                #       1/ If group_to_create equals A B, do not create a new group
                #       2/ If group_to_create equals A D, create the new group (A D is not a subset of A B C)
                if any(group_to_create <= x for x in done_groups_res_ids):
                    continue

                group = self.env['data_merge.group'].with_context(
                    prefetch_fields=False).create({'model_id': dm_model.id})
                d = [{
                    'group_id': group.id,
                    'res_id': rec
                } for rec in group_to_create]
                self.env['data_merge.record'].with_context(
                    prefetch_fields=False).create(d)

                if groups_created % 1000 == 0 and batch_commits:
                    self.env.cr.commit()

                group._elect_master_record()

                if dm_model.create_threshold > 0 and group.similarity * 100 <= dm_model.create_threshold:
                    group.unlink()
                    continue

                if dm_model.merge_mode == 'automatic':
                    if group.similarity * 100 >= dm_model.merge_threshold:
                        group.merge_records()
                        group.unlink()

            _logger.info('Record creation done after %s' %
                         str(timeit.default_timer() - t1))
Beispiel #12
0
    def _name_search(self,
                     name,
                     args=None,
                     operator='ilike',
                     limit=100,
                     name_get_uid=None):
        self = self.sudo(name_get_uid or self.env.uid)
        if args is None:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
            self.check_access_rights('read')
            where_query = self._where_calc(args)
            self._apply_ir_rules(where_query, 'read')
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(self.env.cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent}
                           OR {vat} {operator} {percent}
                           OR {phone} {operator} {percent}
                           OR {mobile} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(
                where=where_str,
                operator=operator,
                email=unaccent('email'),
                display_name=unaccent('display_name'),
                reference=unaccent('ref'),
                percent=unaccent('%s'),
                vat=unaccent('vat'),
                phone=unaccent('phone'),
                mobile=unaccent('mobile'),
            )

            where_clause_params += [
                search_name
            ] * 3  # for email / display_name, reference
            where_clause_params += [re.sub('[^a-zA-Z0-9]+', '',
                                           search_name)]  # for vat
            where_clause_params += [
                re.sub("^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\'s\'./0-9]*$", '',
                       search_name)
            ] * 2  # for phone / mobile
            where_clause_params += [search_name]  # for order by
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            self.env.cr.execute(query, where_clause_params)
            partner_ids = [row[0] for row in self.env.cr.fetchall()]

            if partner_ids:
                return self.browse(partner_ids).name_get()
            else:
                return []
        return super(Partner, self)._name_search(name,
                                                 args,
                                                 operator=operator,
                                                 limit=limit,
                                                 name_get_uid=name_get_uid)