def get_move_lines_for_reconciliation(self, partner_id=None, excluded_ids=None, str=False, offset=0, limit=None, additional_domain=None, overlook_partner=False): """ Return account.move.line records which can be used for bank statement reconciliation. :param partner_id: :param excluded_ids: :param str: :param offset: :param limit: :param additional_domain: :param overlook_partner: """ _logger.debug('PAsa por aquí') if partner_id is None: partner_id = self.partner_id.id # Blue lines = payment on bank account not assigned to a statement yet reconciliation_aml_accounts = [ self.journal_id.default_credit_account_id.id, self.journal_id.default_debit_account_id.id ] #domain_reconciliation = ['&', '&', ('statement_line_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)] domain_reconciliation = [ '&', ('statement_line_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts) ] # Black lines = unreconciled & (not linked to a payment or open balance created by statement domain_matching = [('reconciled', '=', False)] if partner_id or overlook_partner: domain_matching = expression.AND([ domain_matching, [('account_id.internal_type', 'in', ['payable', 'receivable'])] ]) else: # TODO : find out what use case this permits (match a check payment, registered on a journal whose account type is other instead of liquidity) domain_matching = expression.AND( [domain_matching, [('account_id.reconcile', '=', True)]]) # Let's add what applies to both domain = expression.OR([domain_reconciliation, domain_matching]) if partner_id and not overlook_partner: domain = expression.AND( [domain, [('partner_id', '=', partner_id)]]) # Domain factorized for all reconciliation use cases if str: str_domain = self.env[ 'account.move.line'].domain_move_lines_for_reconciliation( str=str) if not partner_id: str_domain = expression.OR( [str_domain, [('partner_id.name', 'ilike', str)]]) domain = expression.AND([domain, str_domain]) if excluded_ids: domain = expression.AND([[('id', 'not in', excluded_ids)], domain]) # Domain from caller if additional_domain is None: additional_domain = [] else: additional_domain = expression.normalize_domain(additional_domain) domain = expression.AND([domain, additional_domain]) #domain = expression.AND([additional_domain]) _logger.debug('DOMAIN') _logger.debug(domain) return self.env['account.move.line'].search( domain, offset=offset, limit=limit, order="date_maturity desc, id desc")
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if not args: args = [] if name: positive_operators = ['=', 'ilike', '=ilike', 'like', '=like'] product_ids = [] if operator in positive_operators: product_ids = self._search([('default_code', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid) if not product_ids: product_ids = self._search([('barcode', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid) if not product_ids and operator not in expression.NEGATIVE_TERM_OPERATORS: # Do not merge the 2 next lines into one single search, SQL search performance would be abysmal # on a database with thousands of matching products, due to the huge merge+unique needed for the # OR operator (and given the fact that the 'name' lookup results come from the ir.translation table # Performing a quick memory merge of ids in Python will give much better performance product_ids = self._search(args + [('default_code', operator, name)], limit=limit) if not limit or len(product_ids) < limit: # we may underrun the limit because of dupes in the results, that's fine limit2 = (limit - len(product_ids)) if limit else False product2_ids = self._search( args + [('name', operator, name), ('id', 'not in', product_ids)], limit=limit2, access_rights_uid=name_get_uid) product_ids.extend(product2_ids) elif not product_ids and operator in expression.NEGATIVE_TERM_OPERATORS: domain = expression.OR([ [ '&', ('default_code', operator, name), ('name', operator, name) ], [ '&', ('default_code', '=', False), ('name', operator, name) ], ]) domain = expression.AND([args, domain]) product_ids = self._search(domain, limit=limit, access_rights_uid=name_get_uid) if not product_ids and operator in positive_operators: ptrn = re.compile('(\[(.*?)\])') res = ptrn.search(name) if res: product_ids = self._search( [('default_code', '=', res.group(2))] + args, limit=limit, access_rights_uid=name_get_uid) # still no results, partner in context: search on supplier info as last hope to find something if not product_ids and self._context.get('partner_id'): suppliers_ids = self.env['product.supplierinfo']._search( [('name', '=', self._context.get('partner_id')), '|', ('product_code', operator, name), ('product_name', operator, name)], access_rights_uid=name_get_uid) if suppliers_ids: product_ids = self._search( [('product_tmpl_id.seller_ids', 'in', suppliers_ids)], limit=limit, access_rights_uid=name_get_uid) else: product_ids = self._search(args, limit=limit, access_rights_uid=name_get_uid) return self.browse(product_ids).name_get()
def _default_sale_line_domain(self): domain = super(AccountAnalyticLine, self)._default_sale_line_domain() return expression.OR([domain, [('qty_delivered_method', '=', 'timesheet')]])
def _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_id, excluded_ids=[], search_str=False, mode='rp'): """ Return the domain for account.move.line records which can be used for bank statement reconciliation. :param aml_accounts: :param partner_id: :param excluded_ids: :param search_str: :param mode: 'rp' for receivable/payable or 'other' """ AccountMoveLine = self.env['account.move.line'] #Always exclude the journal items that have been marked as 'to be checked' in a former bank statement reconciliation to_check_excluded = AccountMoveLine.search( AccountMoveLine._get_suspense_moves_domain()).ids excluded_ids.extend(to_check_excluded) domain_reconciliation = [ '&', '&', '&', ('statement_line_id', '=', False), ('account_id', 'in', aml_accounts), ('payment_id', '<>', False), ('balance', '!=', 0.0), ] # default domain matching domain_matching = [ '&', '&', ('reconciled', '=', False), ('account_id.reconcile', '=', True), ('balance', '!=', 0.0), ] domain = expression.OR([domain_reconciliation, domain_matching]) if partner_id: domain = expression.AND( [domain, [('partner_id', '=', partner_id)]]) if mode == 'rp': domain = expression.AND([ domain, [('account_id.internal_type', 'in', ['receivable', 'payable', 'liquidity'])] ]) else: domain = expression.AND([ domain, [('account_id.internal_type', 'not in', ['receivable', 'payable', 'liquidity'])] ]) # Domain factorized for all reconciliation use cases if search_str: str_domain = self._domain_move_lines(search_str=search_str) str_domain = expression.OR( [str_domain, [('partner_id.name', 'ilike', search_str)]]) domain = expression.AND([domain, str_domain]) if excluded_ids: domain = expression.AND([[('id', 'not in', excluded_ids)], domain]) # filter on account.move.line having the same company as the statement line domain = expression.AND( [domain, [('company_id', '=', st_line.company_id.id)]]) # take only moves in valid state. Draft is accepted only when "Post At" is set # to "Bank Reconciliation" in the associated journal domain_post_at = [ '|', '&', ('move_id.state', '=', 'draft'), ('journal_id.post_at', '=', 'bank_rec'), ('move_id.state', 'not in', ['draft', 'cancel']), ] domain = expression.AND([domain, domain_post_at]) if st_line.company_id.account_bank_reconciliation_start: domain = expression.AND([ domain, [('date', '>=', st_line.company_id.account_bank_reconciliation_start)] ]) return domain
def name_search(self, name, args=None, operator='ilike', limit=100): all_loai_record = self._context.get('loai_record_more', []) default_loai_record = self._context.get('default_loai_record') if default_loai_record: all_loai_record.append(default_loai_record) if u'Công Việc' not in all_loai_record: return super(TVCV, self).name_search(name, args=args, operator=operator, limit=limit) limit = 500 try: id_int = int(name) ma_tvcv_domain = [ '|', ('code', 'ilike', name), ('id', '=', id_int) ] except: ma_tvcv_domain = [('code', 'ilike', name)] ma_tvcv_domain = expression.OR([[ '|', ('name_khong_dau', 'ilike', name), ('name_viet_tat', 'ilike', name) ], ma_tvcv_domain]) #nên giữ lại # thu_vien_id_of_gd_parent_id = self._context.get('thu_vien_id_of_gd_parent_id') # if thu_vien_id_of_gd_parent_id and self._context.get('you_at_gd_form'):#self._context.get('you_search_at_gd_form'): # thu_vien_da_chon_list_txt = self._context.get('thu_vien_da_chon_list') # if thu_vien_da_chon_list_txt==False: # thu_vien_da_chon_list = [] # else: # thu_vien_da_chon_list = json.loads(thu_vien_da_chon_list_txt) # # thu_vien_id_of_gd_parent_id = self._context.get('thu_vien_id_of_gd_parent_id') # gd_children_or_not_gd_children_domain = [('id','!=',thu_vien_da_chon_list),'|',('parent_id', '=',thu_vien_id_of_gd_parent_id),('id', '=',self.env.ref('dai_tgg.loaisuvu_viec_con_lai').id)] # else: # gd_children_or_not_gd_children_domain = [('parent_id','=',False),('id','!=',self.env.ref('dai_tgg.loaisuvu_viec_con_lai').id)] if not args: args = [] if name: category_names = name.split(' / ') parents = list(category_names) child = parents[0] parents = parents[1:] domain = [('name', operator, child)] if parents: names_ids = self.name_search(' / '.join(parents), args=args, operator='ilike', limit=limit) category_ids = [name_id[0] for name_id in names_ids] if operator in expression.NEGATIVE_TERM_OPERATORS: categories = self.search([('id', 'not in', category_ids)]) domain = expression.OR([[('parent_id', 'in', categories.ids)], domain]) else: domain = expression.AND([[('parent_id', 'in', category_ids) ], domain]) for i in range(1, len(category_names)): domain = [[('name', operator, ' / '.join(category_names[-1 - i:]))], domain] if operator in expression.NEGATIVE_TERM_OPERATORS: domain = expression.AND(domain) else: domain = expression.OR(domain) name_or_code_domain = expression.OR([domain, ma_tvcv_domain]) last_domain = expression.AND([name_or_code_domain, args]) else: last_domain = args rs = self.search(last_domain, limit=limit) return rs.name_get(from_name_search=True)
def create_tax_settlement_entry(self, journal): """ Funcion que crea asiento de liquidación a partir de información del reporte y devuelve browse del asiento generado * from_report_id * force_context * context: periods_number, cash_basis, date_filter_cmp, date_filter, date_to, date_from, hierarchy_3, company_ids, date_to_cmp, date_from_cmp, all_entries * search_disable_custom_filters * from_report_model * active_id """ self.ensure_one() # obtenemos lineas de este reporte que tengan revert (sin importar # dominio o no porque en realidad puede estar seteado en linea padre # sin dominio) revert_lines = self.line_ids.search([ ('id', 'child_of', self.line_ids.ids), ('settlement_type', '=', 'revert'), ]) # obtenemos todas las lineas hijas de las que obtuvimos que tengan # dominio (esto es para evitar tener que # configurar revert en cada linea hija) revert_lines = self.line_ids.search([ ('id', 'child_of', revert_lines.ids), ('domain', '!=', False), ('settlement_type', 'in', ['revert', False]) ]) move_lines = self.env['account.move.line'] # TODO podriamos en vez de usar el report_move_lines_action para # obtener domain, usar directamente el "_compute_line" o el "_get_sum" # pero deberiamos luego cambiar la logica del grouped move lines # o en realidad estariamos repidiento casi dos veces lo mismo domains = [] for line in revert_lines: domains.append(line.report_move_lines_action()['domain']) domain = expression.OR(domains) lines_vals = journal._get_tax_settlement_entry_lines_vals(domain) # agregamos otrs lineas ẗipo "new line" new_lines = self.line_ids.search([ ('id', 'child_of', self.line_ids.ids), ('settlement_type', 'in', ['new_line', 'new_line_negative'])]) # pasamos por contexto lo que viene adentro del contetxo como contexto # porque asi lo interpreta get_balance (en vez aparentemente # report_move_lines_action busca dentro del contexto) new_lines = new_lines.with_context( new_lines._context.get('context')) for new_line in new_lines: account = self.env['account.account'].search([ ('company_id', '=', journal.company_id.id), ('tag_ids', '=', new_line.settement_account_tag_id.id)], limit=1) if not account: raise ValidationError(_( 'No account found with tag "%s" (id: %s) for company "%s".' ' Check report and accounts configuration.') % ( new_line.settement_account_tag_id.name, new_line.settement_account_tag_id.id, journal.company_id.name)) balance = sum( [x['balance'] for x in new_line.get_balance( {}, {}, self, field_names=['balance'])]) if journal.company_id.currency_id.is_zero(balance): continue balance = new_line.settlement_type == 'new_line' \ and balance or balance * -1.0 lines_vals.append({ 'name': self.name, 'debit': balance < 0.0 and -balance, 'credit': balance >= 0.0 and balance, 'account_id': account.id, }) vals = journal._get_tax_settlement_entry_vals(lines_vals) move = self.env['account.move'].with_context( allow_no_partner=True).create(vals) if self._context.get('tax_settlement_link', True): move_lines.write({'tax_settlement_move_id': move.id}) return move
def _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_id, excluded_ids=[], search_str=False): """ Return the domain for account.move.line records which can be used for bank statement reconciliation. :param aml_accounts: :param partner_id: :param excluded_ids: :param search_str: """ AccountMoveLine = self.env['account.move.line'] #Always exclude the journal items that have been marked as 'to be checked' in a former bank statement reconciliation to_check_excluded = AccountMoveLine.search( AccountMoveLine._get_domain_for_edition_mode()).ids excluded_ids.extend(to_check_excluded) domain_reconciliation = [ '&', '&', ('statement_line_id', '=', False), ('account_id', 'in', aml_accounts), ('payment_id', '<>', False) ] # Black lines = unreconciled & (not linked to a payment or open balance created by statement domain_matching = [('reconciled', '=', False)] if partner_id: domain_matching = expression.AND([ domain_matching, [('account_id.internal_type', 'in', ['payable', 'receivable'])] ]) else: # TODO : find out what use case this permits (match a check payment, registered on a journal whose account type is other instead of liquidity) domain_matching = expression.AND( [domain_matching, [('account_id.reconcile', '=', True)]]) # Let's add what applies to both domain = expression.OR([domain_reconciliation, domain_matching]) if partner_id: domain = expression.AND( [domain, [('partner_id', '=', partner_id)]]) # Domain factorized for all reconciliation use cases if search_str: str_domain = self._domain_move_lines(search_str=search_str) if not partner_id: str_domain = expression.OR( [str_domain, [('partner_id.name', 'ilike', search_str)]]) domain = expression.AND([domain, str_domain]) if excluded_ids: domain = expression.AND([[('id', 'not in', excluded_ids)], domain]) # filter on account.move.line having the same company as the statement line domain = expression.AND( [domain, [('company_id', '=', st_line.company_id.id)]]) if st_line.company_id.account_bank_reconciliation_start: domain = expression.AND([ domain, [('date', '>=', st_line.company_id.account_bank_reconciliation_start)] ]) return domain
def name_search(self, name, args=None, operator='ilike', limit=100): def log_query(msg, id=False): # Use a new cursor to avoid rollback that could be caused by # an upper method try: db_registry = registry(self._cr.dbname) with db_registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) path = 'autofill_name_search by %s' % (self.env.user.name) data = { 'name': self._name, 'type': 'server', 'dbname': self._cr.dbname, 'level': 'DEBUG', 'message': msg, 'path': path, 'func': 'name_search', 'line': 1 } if id: env['ir.logging'].browse(id).sudo().write(data) return id else: data['func'] += ' in progress ...' ir_logging = env['ir.logging'].sudo().create(data) return ir_logging.id except psycopg2.Error: pass # Make a search for all autofill fields and clear default name arg to # avoid `expression.AND` collision if self.env.context.get("autofill_name_search"): bench = Bench().start() # To avoid long-waiting query, we first search for all lines owned # by this user. It has better performance than making a long AND # query including user_id domain = [ ('user_id', '=', self.env.uid), ('project_id', '!=', False), ] owned_ids = self.env['account.analytic.line'].search(domain) args.append(('id', 'in', owned_ids.ids)) # Execute normal search autofill_fields = self.get_autofill_fields() if len(name) > 2: extra_args = [] for value in name.split(): if len(value) > 2: value_args = [] for fname in autofill_fields: value_args = expression.OR( [value_args, [(fname, 'ilike', value)]]) extra_args = expression.AND([extra_args, value_args]) if extra_args: args = expression.AND([args, extra_args]) name = '' log_id = log_query("Autofill query: {} in progress".format(args)) # Make a search with default criteria names = super().name_search(name=name, args=args, operator=operator, limit=limit) if _logger.isEnabledFor(logging.DEBUG): if self.env.context.get("autofill_name_search"): duration = bench.stop().duration() log_query("Autofill query: {} in {}s".format(args, duration), log_id) if self.env.context.get("autofill_name_search"): autofill_fields = self.get_autofill_fields() # Add line details to quickly identify its content autofill_fields.remove('name') result = [] for item in names: rec = self.browse(item[0])[0] name = str(item[1]) extra_name = [] for fname in autofill_fields: fvalue = rec[fname] if hasattr(fvalue, 'display_name'): val = fvalue.display_name or '' elif fvalue: val = str(fvalue) else: val = False if val and val not in extra_name: extra_name.append(val) name = '{}: {}'.format(' / '.join(extra_name), name) result.append((item[0], name)) return result else: return names
def _any_is_configured(self, company_id): domain = expression.OR([[('property_tax_payable_account_id', '!=', False)], [('property_tax_receivable_account_id', '!=', False)], [('property_advance_tax_payment_account_id', '!=', False)]]) group_with_config = self.with_company(company_id).search_count(domain) return group_with_config > 0
def _timesheet_get_portal_domain(self): domain = super(AccountAnalyticLine, self)._timesheet_get_portal_domain() return expression.OR([domain, self._timesheet_in_helpdesk_get_portal_domain()])
def _get_bank_rec_report_data(self, options, line_id=None): # General data + setup rslt = {} journal_id = self._context.get('active_id') or options.get('active_id') journal = self.env['account.journal'].browse(journal_id) selected_companies = self.env['res.company'].browse( self.env.context['company_ids']) rslt['use_foreign_currency'] = \ journal.currency_id != journal.company_id.currency_id \ if journal.currency_id else False rslt['account_ids'] = list( set([ journal.default_debit_account_id.id, journal.default_credit_account_id.id ])) rslt['line_currency'] = journal.currency_id if rslt[ 'use_foreign_currency'] else False self = self.with_context(line_currency=rslt['line_currency']) lines_already_accounted = self.env['account.move.line'].search([ ('account_id', 'in', rslt['account_ids']), ('date', '<=', self.env.context['date_to']), ('company_id', 'in', self.env.context['company_ids']) ]) rslt['odoo_balance'] = sum([ line.amount_currency if rslt['use_foreign_currency'] else line.balance for line in lines_already_accounted ]) # Payments not reconciled with a bank statement line aml_domain = [ '|', '&', ('move_id.journal_id.type', 'in', ('cash', 'bank')), ('move_id.journal_id', '=', journal_id), '&', ('move_id.journal_id.type', 'not in', ('cash', 'bank')), ('payment_id.journal_id', '=', journal_id), '|', ('statement_line_id', '=', False), ('statement_line_id.date', '>', self.env.context['date_to']), ('user_type_id.type', '=', 'liquidity'), ('full_reconcile_id', '=', False), ('date', '<=', self.env.context['date_to']), ] companies_unreconciled_selection_domain = [] for company in selected_companies: company_domain = [('company_id', '=', company.id)] if company.account_bank_reconciliation_start: company_domain = expression.AND([ company_domain, [('date', '>=', company.account_bank_reconciliation_start)] ]) companies_unreconciled_selection_domain = expression.OR( [companies_unreconciled_selection_domain, company_domain]) aml_domain += companies_unreconciled_selection_domain move_lines = self.env['account.move.line'].search(aml_domain) if move_lines: rslt['not_reconciled_pmts'] = move_lines # Bank statement lines not reconciled with a payment rslt['not_reconciled_st_positive'] = self.env[ 'account.bank.statement.line'].search([ ('statement_id.journal_id', '=', journal_id), ('date', '<=', self.env.context['date_to']), ('journal_entry_ids', '=', False), ('amount', '>', 0), ('company_id', 'in', self.env.context['company_ids']) ]) rslt['not_reconciled_st_negative'] = self.env[ 'account.bank.statement.line'].search([ ('statement_id.journal_id', '=', journal_id), ('date', '<=', self.env.context['date_to']), ('journal_entry_ids', '=', False), ('amount', '<', 0), ('company_id', 'in', self.env.context['company_ids']) ]) # Final last_statement = self.env['account.bank.statement'].search( [('journal_id', '=', journal_id), ('date', '<=', self.env.context['date_to']), ('company_id', 'in', self.env.context['company_ids'])], order="date desc, id desc", limit=1) rslt['last_st_balance'] = last_statement.balance_end rslt['last_st_end_date'] = last_statement.date return rslt
def _compute_get_invoiced(self): """ Compute the invoice status of a SO. Possible statuses: - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to invoice. This is also the default value if the conditions of no other status is met. - to invoice: if any SO line is 'to invoice', the whole SO is 'to invoice' - invoiced: if all SO lines are invoiced, the SO is invoiced. - upselling: if all SO lines are invoiced or upselling, the status is upselling. The invoice_ids are obtained thanks to the invoice lines of the SO lines, and we also search for possible refunds created directly from existing invoices. This is necessary since such a refund is not directly linked to the SO. """ # Ignore the status of the deposit product # deposit_product_id = self.env['sale.advance.payment.inv']\ # ._default_product_id() for order in self: invoice_ids = order.operations.mapped("invoice_line_id").mapped( "invoice_id").filtered( lambda r: r.type in ["out_invoice", "out_refund"] ) + order.fees_lines.mapped("invoice_line_id").mapped( "invoice_id").filtered( lambda r: r.type in ["out_invoice", "out_refund"]) # Search for invoices which have been # 'cancelled' (filter_refund = 'modify' in account.invoice.refund') # use like as origin may contains multiple # references (e.g. 'SO01, SO02') refunds = invoice_ids.search([ ("origin", "like", order.name), ("company_id", "=", order.company_id.id), ("type", "in", ("out_invoice", "out_refund")), ]) invoice_ids |= refunds.filtered( lambda r: order.name in [origin.strip() for origin in r.origin.split(",")]) # Search for refunds as well domain_inv = expression.OR([[ "&", ("origin", "=", inv.number), ("journal_id", "=", inv.journal_id.id), ] for inv in invoice_ids if inv.number]) if domain_inv: refund_ids = self.env["account.invoice"].search( expression.AND([ [ "&", ("type", "=", "out_refund"), ("origin", "!=", False) ], domain_inv, ])) else: refund_ids = self.env["account.invoice"].browse() order.update({ "invoice_count": len(set(invoice_ids.ids + refund_ids.ids)), "invoice_ids": invoice_ids.ids + refund_ids.ids, })
def _domain_move_lines_for_reconciliation( self, st_line, aml_accounts, partner_id, excluded_ids=None, search_str=False, mode="rp", ): """Return the domain for account.move.line records which can be used for bank statement reconciliation. :param aml_accounts: :param partner_id: :param excluded_ids: :param search_str: :param mode: 'rp' for receivable/payable or 'other' """ AccountMoveLine = self.env["account.move.line"] # Always exclude the journal items that have been marked as # 'to be checked' in a former bank statement reconciliation to_check_excluded = AccountMoveLine.search( AccountMoveLine._get_suspense_moves_domain()).ids if excluded_ids is None: excluded_ids = [] excluded_ids.extend(to_check_excluded) domain_reconciliation = [ "&", "&", "&", ("statement_line_id", "=", False), ("account_id", "in", aml_accounts), ("payment_id", "<>", False), ("balance", "!=", 0.0), ] # default domain matching domain_matching = [ "&", "&", ("reconciled", "=", False), ("account_id.reconcile", "=", True), ("balance", "!=", 0.0), ] domain = expression.OR([domain_reconciliation, domain_matching]) if partner_id: domain = expression.AND( [domain, [("partner_id", "=", partner_id)]]) if mode == "rp": domain = expression.AND([ domain, [( "account_id.internal_type", "in", ["receivable", "payable", "liquidity"], )], ]) else: domain = expression.AND([ domain, [( "account_id.internal_type", "not in", ["receivable", "payable", "liquidity"], )], ]) # Domain factorized for all reconciliation use cases if search_str: str_domain = self._domain_move_lines(search_str=search_str) str_domain = expression.OR( [str_domain, [("partner_id.name", "ilike", search_str)]]) domain = expression.AND([domain, str_domain]) if excluded_ids: domain = expression.AND([[("id", "not in", excluded_ids)], domain]) # filter on account.move.line having the same company as the statement # line domain = expression.AND( [domain, [("company_id", "=", st_line.company_id.id)]]) if st_line.company_id.account_bank_reconciliation_start: domain = expression.AND([ domain, [( "date", ">=", st_line.company_id.account_bank_reconciliation_start, )], ]) return domain
def _get_domain_matching_suspense_moves(self): # OVERRIDE to handle the document requests in the suspense accounts domain. domain = super(AccountMove, self)._get_domain_matching_suspense_moves() return expression.OR( [domain, [('reconciliation_invoice_id', '=', self.id)]])
def _get_invoiced(self): """ Compute the invoice status of a SO. Possible statuses: - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to invoice. This is also the default value if the conditions of no other status is met. - to invoice: if any SO line is 'to invoice', the whole SO is 'to invoice' - invoiced: if all SO lines are invoiced, the SO is invoiced. - upselling: if all SO lines are invoiced or upselling, the status is upselling. The invoice_ids are obtained thanks to the invoice lines of the SO lines, and we also search for possible refunds created directly from existing invoices. This is necessary since such a refund is not directly linked to the SO. """ # Ignore the status of the deposit product deposit_product_id = self.env[ 'sale.advance.payment.inv']._default_product_id() line_invoice_status_all = [ (d['order_id'][0], d['invoice_status']) for d in self.env['sub.sale.order'].read_group( [('order_id', 'in', self.ids), ('product_id', '!=', deposit_product_id.id)], ['order_id', 'invoice_status'], ['order_id', 'invoice_status'], lazy=False) ] for order in self: invoice_ids = order.sub_sale_order_ids.mapped( 'invoice_lines').mapped('invoice_id').filtered( lambda r: r.type in ['out_invoice', 'out_refund']) # Search for invoices which have been 'cancelled' (filter_refund = 'modify' in # 'account.invoice.refund') # use like as origin may contains multiple references (e.g. 'SO01, SO02') refunds = invoice_ids.search([ ('origin', 'like', order.name), ('company_id', '=', order.company_id.id), ('type', 'in', ('out_invoice', 'out_refund')) ]) invoice_ids |= refunds.filtered( lambda r: order.name in [origin.strip() for origin in r.origin.split(',')]) # Search for refunds as well domain_inv = expression.OR([[ '&', ('origin', '=', inv.number), ('journal_id', '=', inv.journal_id.id) ] for inv in invoice_ids if inv.number]) if domain_inv: refund_ids = self.env['account.invoice'].search( expression.AND([[ '&', ('type', '=', 'out_refund'), ('origin', '!=', False) ], domain_inv])) else: refund_ids = self.env['account.invoice'].browse() line_invoice_status = [ d[1] for d in line_invoice_status_all if d[0] == order.id ] if order.state not in ('sale', 'done'): invoice_status = 'no' elif any(invoice_status == 'to invoice' for invoice_status in line_invoice_status): invoice_status = 'to invoice' elif all(invoice_status == 'invoiced' for invoice_status in line_invoice_status): invoice_status = 'invoiced' elif all(invoice_status in ['invoiced', 'upselling'] for invoice_status in line_invoice_status): invoice_status = 'upselling' else: invoice_status = 'no' order.update({ 'invoice_count': len(set(invoice_ids.ids + refund_ids.ids)), 'invoice_ids': invoice_ids.ids + refund_ids.ids, 'invoice_status': invoice_status })
def _analytic_compute_delivered_quantity_domain(self): domain = super(SaleOrderLine, self)._analytic_compute_delivered_quantity_domain() domain = expression.AND([domain, [('project_id', '=', False)]]) timesheet_domain = self._timesheet_compute_delivered_quantity_domain() return expression.OR([domain, timesheet_domain])
def _decode_ubl_2_1(self, tree): self.ensure_one() namespaces = self._get_ubl_namespaces(tree) elements = tree.xpath('//cbc:InvoiceTypeCode', namespaces=namespaces) if elements: type_code = elements[0].text type = 'in_refund' if type_code == '381' else 'in_invoice' else: type = 'in_invoice' default_journal = self.with_context( default_type=type)._get_default_journal() with Form( self.with_context( default_type=type, default_journal_id=default_journal.id)) as invoice_form: # Reference elements = tree.xpath('//cbc:ID', namespaces=namespaces) if elements: invoice_form.ref = elements[0].text elements = tree.xpath('//cbc:InstructionID', namespaces=namespaces) if elements: invoice_form.invoice_payment_ref = elements[0].text # Dates elements = tree.xpath('//cbc:IssueDate', namespaces=namespaces) if elements: invoice_form.invoice_date = elements[0].text elements = tree.xpath('//cbc:PaymentDueDate', namespaces=namespaces) if elements: invoice_form.invoice_date_due = elements[0].text # allow both cbc:PaymentDueDate and cbc:DueDate elements = tree.xpath('//cbc:DueDate', namespaces=namespaces) invoice_form.invoice_date_due = invoice_form.invoice_date_due or elements and elements[ 0].text # Currency elements = tree.xpath('//cbc:DocumentCurrencyCode', namespaces=namespaces) currency_code = elements and elements[0].text or '' currency = self.env['res.currency'].search( [('name', '=', currency_code.upper())], limit=1) if elements: invoice_form.currency_id = currency # Incoterm elements = tree.xpath( '//cbc:TransportExecutionTerms/cac:DeliveryTerms/cbc:ID', namespaces=namespaces) if elements: invoice_form.invoice_incoterm_id = self.env[ 'account.incoterms'].search( [('code', '=', elements[0].text)], limit=1) # Partner partner_element = tree.xpath( '//cac:AccountingSupplierParty/cac:Party', namespaces=namespaces) if partner_element: domains = [] partner_element = partner_element[0] elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:Name', namespaces=namespaces) if elements: partner_name = elements[0].text domains.append([('name', 'ilike', partner_name)]) elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:Telephone', namespaces=namespaces) if elements: partner_telephone = elements[0].text domains.append([('phone', '=', partner_telephone), ('mobile', '=', partner_telephone)]) elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:ElectronicMail', namespaces=namespaces) if elements: partner_mail = elements[0].text domains.append([('email', '=', partner_mail)]) elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:ID', namespaces=namespaces) if elements: partner_id = elements[0].text domains.append([('vat', 'like', partner_id)]) if domains: partner = self.env['res.partner'].search( expression.OR(domains), limit=1) if partner: invoice_form.partner_id = partner else: invoice_form.partner_id = self.env['res.partner'] # Regenerate PDF elements = tree.xpath('//cac:AdditionalDocumentReference', namespaces=namespaces) if elements: attachment_name = elements[0].xpath( 'cbc:ID', namespaces=namespaces)[0].text attachment_data = elements[0].xpath( 'cac:Attachment//cbc:EmbeddedDocumentBinaryObject', namespaces=namespaces)[0].text attachment_id = self.env['ir.attachment'].create({ 'name': attachment_name, 'res_id': self.id, 'res_model': 'account.move', 'datas': attachment_data, 'type': 'binary', }) self.with_context(no_new_invoice=True).message_post( attachment_ids=[attachment_id.id]) # Lines lines_elements = tree.xpath('//cac:InvoiceLine', namespaces=namespaces) for eline in lines_elements: with invoice_form.invoice_line_ids.new() as invoice_line_form: # Quantity elements = eline.xpath('cbc:InvoicedQuantity', namespaces=namespaces) quantity = elements and float(elements[0].text) or 1.0 invoice_line_form.quantity = quantity # Price Unit elements = eline.xpath('cac:Price/cbc:PriceAmount', namespaces=namespaces) invoice_line_form.price_unit = elements and float( elements[0].text) or 0.0 # Name elements = eline.xpath('cac:Item/cbc:Description', namespaces=namespaces) invoice_line_form.name = elements and elements[0].text or '' invoice_line_form.name = invoice_line_form.name.replace( '%month%', str( fields.Date.to_date(invoice_form.invoice_date). month)) # TODO: full name in locale invoice_line_form.name = invoice_line_form.name.replace( '%year%', str( fields.Date.to_date( invoice_form.invoice_date).year)) # Product elements = eline.xpath( 'cac:Item/cac:SellersItemIdentification/cbc:ID', namespaces=namespaces) domains = [] if elements: product_code = elements[0].text domains.append([('default_code', '=', product_code)]) elements = eline.xpath( 'cac:Item/cac:StandardItemIdentification/cbc:ID[@schemeID=\'GTIN\']', namespaces=namespaces) if elements: product_ean13 = elements[0].text domains.append([('ean13', '=', product_ean13)]) if domains: product = self.env['product.product'].search( expression.OR(domains), limit=1) if product: invoice_line_form.product_id = product # Taxes taxes_elements = eline.xpath( 'cac:TaxTotal/cac:TaxSubtotal', namespaces=namespaces) invoice_line_form.tax_ids.clear() for etax in taxes_elements: elements = etax.xpath('cbc:Percent', namespaces=namespaces) if elements: tax = self.env['account.tax'].search( [ ('company_id', '=', self.env.company.id), ('amount', '=', float(elements[0].text)), ('type_tax_use', '=', invoice_form.journal_id.type), ], order='sequence ASC', limit=1) if tax: invoice_line_form.tax_ids.add(tax) return invoice_form.save()
def _search_parent_path_names(self, operator, operand): domain = [] for value in operand.split('/'): args = [(self._rec_name_fallback(), operator, value)] domain = expression.OR([args, domain]) if domain else args return domain if domain else [(self._rec_name_fallback(), operator, "")]
def action_view_opportunity(self): action = super().action_view_opportunity() action['domain'] = expression.OR([ action.get('domain', []), [('partner_assigned_id', '=', self.id)] ]) return action
def _get_search_domain(self, search, category, attrib_values): """ Modifica el domain original para mostrar los productos en funcion de los nuevos subdominios. domain_swp: controla que no se muestren los productos sin stock en conjunto con el cron act_stock_published de product.py. El resto de domains solo busca dentro de esos ids. attr_domain: para buscar productos dentro del contexto por filtros de atributos. search: pasa del contexto y realiza la busqueda por los terminos introducidos en el search box. """ # Set fuzzy search for more results request.env.cr.execute("SELECT set_limit(0.2);") domain_origin = super(WebsiteSaleExtended, self)._get_search_domain(search, category, attrib_values) attr_domain = [] has_att_filter = False filter_args = request.httprequest.args # Search and filters work together if search and search != 0: for srch in shlex.split(search): if len(srch) > 2: domain_search = ['|', '|', '|', '|', '|', '|', ('name', '%', srch), ('ref_template', 'ilike', srch), ('product_color', 'ilike', srch), ('product_variant_ids.attribute_value_ids', 'ilike', srch), ('public_categ_ids.complete_name', 'ilike', srch), ('public_categ_ids.public_categ_tag_ids', 'ilike', srch), # ('product_variant_ids', 'ilike', srch), ('product_variant_ids.product_brand_id', 'ilike', srch)] domain_origin = expression.normalize_domain(domain_origin) domain_origin = expression.OR([domain_origin, domain_search]) if filter_args: brand = int(filter_args.get('brand', False)) context = dict(request.env.context) if context.get('brand_id') == 0: context.pop('brand_id') domain_origin.remove([d for d in domain_origin if 'product_brand_id' in d][0]) if brand and brand != 0: domain_origin.append(('product_brand_id', '=', brand)) tags = request.env['product.attribute.tag'].sudo() gender = filter_args.get('gender', False) if gender: gender_domain = ['&', ('type', '=', 'gender'), ('value', '=', gender)] if brand and brand != 0: gender_domain += [('product_brand_id', '=', brand)] tag_gender = tags.search(gender_domain) if tag_gender: attr_domain += [('product_gender_id', 'in', tag_gender.ids)] has_att_filter = True age = filter_args.get('age', False) if age: tag_domain = ['&', ('type', '=', 'age'), ('value', '=', age)] if brand and brand != 0: tag_domain += [('product_brand_id', '=', brand)] tag_age = tags.search(tag_domain) if tag_age: attr_domain += [('product_age_id', 'in', tag_age.ids)] has_att_filter = True if has_att_filter: product_attributes = request.env['product.attribute'].sudo().search(attr_domain) product_attribute_lines = request.env['product.attribute.line'].sudo().search([ ('attribute_id', 'in', product_attributes.ids) ]) domain_origin += [('attribute_line_ids', 'in', product_attribute_lines.ids)] # Only can put on context products with stock > 0 or with stock = 0 but published # search and filters and all domain have to respect this. So that we need add this like an AND website = request.website domain_swp = [('website_id', '=', website.id), ('stock_website_published', '=', True)] product_ids = request.env['template.stock.web'].sudo().search(domain_swp).mapped('product_id').ids domain_origin += [('id', 'in', product_ids)] return domain_origin
def _analytic_compute_delivered_quantity_domain(self): domain = super(SaleOrderLine, self)._analytic_compute_delivered_quantity_domain() timesheet_domain = self._timesheet_compute_delivered_quantity_domain() return expression.OR([domain, timesheet_domain])
def _get_stage_id_domain(self): domain = [('job_ids', '=', False)] if self.job_id: domain = expression.OR([domain, [('job_ids', 'in', self.job_id)]]) return domain
def _check_barcode_uniqueness(self): """ With GS1 nomenclature, products and packagins use the same pattern. Therefore, we need to ensure the uniqueness between products' barcodes and packagings' ones""" condition = expression.OR([[('barcode', '=', b)] for b in self.mapped('barcode') if b]) if self.env['product.product'].search(condition, limit=1): raise ValidationError(_("A product already uses the barcode"))
def _get_translation_frontend_modules_domain(cls): domain = super(IrHttp, cls)._get_translation_frontend_modules_domain() return expression.OR([domain, [('name', '=', 'web_editor')]])
def _get_invoice_basis_domain(self, domain_params): domain_company = [("company_id", "in", domain_params["company_ids"])] domain_tax_date = self._get_tax_date_domain(domain_params) domain_account_date = self._get_accounting_date_domain(domain_params) domain_dates = expression.OR([domain_tax_date, domain_account_date]) return expression.AND([domain_company, domain_dates])
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if not args: args = [] if name: positive_operators = ['=', 'ilike', '=ilike', 'like', '=like'] category_ids = [] if operator in positive_operators: category_ids = self._search([('code', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid) if not category_ids and operator not in expression.NEGATIVE_TERM_OPERATORS: # Do not merge the 2 next lines into one single search, SQL # search performance would be abysmal on a database with # thousands of matching products, due to the huge merge+unique # needed for the OR operator (and given the fact that the # 'name' lookup results come from the ir.translation table # Performing a quick memory merge of ids in Python will give # much better performance category_ids = self._search(args + [('code', operator, name)], limit=limit) if not limit or len(category_ids) < limit: # we may underrun the limit because of dupes in the # results, that's fine limit2 = (limit - len(category_ids)) if limit else False product2_ids = self._search( args + [('name', operator, name), ('id', 'not in', category_ids)], limit=limit2, access_rights_uid=name_get_uid) category_ids.extend(product2_ids) elif not category_ids and operator in expression.NEGATIVE_TERM_OPERATORS: domain = expression.OR([ [ '&', ('code', operator, name), ('name', operator, name), ], [ '&', ('code', '=', False), ('name', operator, name), ], ]) domain = expression.AND([args, domain]) category_ids = self._search(domain, limit=limit, access_rights_uid=name_get_uid) if not category_ids and operator in positive_operators: ptrn = re.compile('(\[(.*?)\])') res = ptrn.search(name) if res: category_ids = self._search([('code', '=', res.group(2))] + args, limit=limit, access_rights_uid=name_get_uid) else: category_ids = self._search(args, limit=limit, access_rights_uid=name_get_uid) return self.browse(category_ids).name_get()
def _domain_move_lines(self, search_str): str_domain = super()._domain_move_lines(search_str) account_code_domain = [('account_id.code', '=ilike', search_str + '%')] str_domain = expression.OR([str_domain, account_code_domain]) return str_domain
def _import_ubl(self, tree, invoice): """ Decodes an UBL invoice into an invoice. :param tree: the UBL tree to decode. :param invoice: the invoice to update or an empty recordset. :returns: the invoice where the UBL data was imported. """ def _get_ubl_namespaces(): ''' If the namespace is declared with xmlns='...', the namespaces map contains the 'None' key that causes an TypeError: empty namespace prefix is not supported in XPath Then, we need to remap arbitrarily this key. :param tree: An instance of etree. :return: The namespaces map without 'None' key. ''' namespaces = tree.nsmap namespaces['inv'] = namespaces.pop(None) return namespaces namespaces = _get_ubl_namespaces() if not invoice: invoice = self.env['account.move'].create({}) elements = tree.xpath('//cbc:InvoiceTypeCode', namespaces=namespaces) if elements: type_code = elements[0].text move_type = 'in_refund' if type_code == '381' else 'in_invoice' else: move_type = 'in_invoice' default_journal = invoice.with_context( default_move_type=move_type)._get_default_journal() with Form( invoice.with_context( default_move_type=move_type, default_journal_id=default_journal.id)) as invoice_form: # Reference elements = tree.xpath('//cbc:ID', namespaces=namespaces) if elements: invoice_form.ref = elements[0].text elements = tree.xpath('//cbc:InstructionID', namespaces=namespaces) if elements: invoice_form.payment_reference = elements[0].text # Dates elements = tree.xpath('//cbc:IssueDate', namespaces=namespaces) if elements: invoice_form.invoice_date = elements[0].text elements = tree.xpath('//cbc:PaymentDueDate', namespaces=namespaces) if elements: invoice_form.invoice_date_due = elements[0].text # allow both cbc:PaymentDueDate and cbc:DueDate elements = tree.xpath('//cbc:DueDate', namespaces=namespaces) invoice_form.invoice_date_due = invoice_form.invoice_date_due or elements and elements[ 0].text # Currency elements = tree.xpath('//cbc:DocumentCurrencyCode', namespaces=namespaces) currency_code = elements and elements[0].text or '' currency = self.env['res.currency'].search( [('name', '=', currency_code.upper())], limit=1) if elements: invoice_form.currency_id = currency # Incoterm elements = tree.xpath( '//cbc:TransportExecutionTerms/cac:DeliveryTerms/cbc:ID', namespaces=namespaces) if elements: invoice_form.invoice_incoterm_id = self.env[ 'account.incoterms'].search( [('code', '=', elements[0].text)], limit=1) # Partner partner_element = tree.xpath( '//cac:AccountingSupplierParty/cac:Party', namespaces=namespaces) if partner_element: domains = [] partner_element = partner_element[0] elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:Name', namespaces=namespaces) if elements: partner_name = elements[0].text domains.append([('name', 'ilike', partner_name)]) else: partner_name = '' elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:Telephone', namespaces=namespaces) if elements: partner_telephone = elements[0].text domains.append([('phone', '=', partner_telephone), ('mobile', '=', partner_telephone)]) elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:ElectronicMail', namespaces=namespaces) if elements: partner_mail = elements[0].text domains.append([('email', '=', partner_mail)]) elements = partner_element.xpath( '//cac:AccountingSupplierParty/cac:Party//cbc:ID', namespaces=namespaces) if elements: partner_id = elements[0].text domains.append([('vat', 'like', partner_id)]) if domains: partner = self.env['res.partner'].search( expression.OR(domains), limit=1) if partner: invoice_form.partner_id = partner partner_name = partner.name else: invoice_form.partner_id = self.env['res.partner'] # Regenerate PDF attachments = self.env['ir.attachment'] elements = tree.xpath('//cac:AdditionalDocumentReference', namespaces=namespaces) for element in elements: attachment_name = element.xpath('cbc:ID', namespaces=namespaces) attachment_data = element.xpath( 'cac:Attachment//cbc:EmbeddedDocumentBinaryObject', namespaces=namespaces) if attachment_name and attachment_data: text = attachment_data[0].text attachments |= self.env['ir.attachment'].create({ 'name': attachment_name[0].text, 'res_id': invoice.id, 'res_model': 'account.move', 'datas': text + '=' * (len(text) % 3), # Fix incorrect padding 'type': 'binary', }) if attachments: invoice.with_context(no_new_invoice=True).message_post( attachment_ids=attachments.ids) # Lines lines_elements = tree.xpath('//cac:InvoiceLine', namespaces=namespaces) for eline in lines_elements: with invoice_form.invoice_line_ids.new() as invoice_line_form: # Product elements = eline.xpath( 'cac:Item/cac:SellersItemIdentification/cbc:ID', namespaces=namespaces) domains = [] if elements: product_code = elements[0].text domains.append([('default_code', '=', product_code)]) elements = eline.xpath( 'cac:Item/cac:StandardItemIdentification/cbc:ID[@schemeID=\'GTIN\']', namespaces=namespaces) if elements: product_ean13 = elements[0].text domains.append([('barcode', '=', product_ean13)]) if domains: product = self.env['product.product'].search( expression.OR(domains), limit=1) if product: invoice_line_form.product_id = product # Quantity elements = eline.xpath('cbc:InvoicedQuantity', namespaces=namespaces) quantity = elements and float(elements[0].text) or 1.0 invoice_line_form.quantity = quantity # Price Unit elements = eline.xpath('cac:Price/cbc:PriceAmount', namespaces=namespaces) price_unit = elements and float(elements[0].text) or 0.0 elements = eline.xpath('cbc:LineExtensionAmount', namespaces=namespaces) line_extension_amount = elements and float( elements[0].text) or 0.0 invoice_line_form.price_unit = price_unit or line_extension_amount / invoice_line_form.quantity or 0.0 # Name elements = eline.xpath('cac:Item/cbc:Description', namespaces=namespaces) if elements and elements[0].text: invoice_line_form.name = elements[0].text invoice_line_form.name = invoice_line_form.name.replace( '%month%', str( fields.Date.to_date(invoice_form.invoice_date). month)) # TODO: full name in locale invoice_line_form.name = invoice_line_form.name.replace( '%year%', str( fields.Date.to_date( invoice_form.invoice_date).year)) else: invoice_line_form.name = "%s (%s)" % ( partner_name or '', invoice_form.invoice_date) # Taxes taxes_elements = eline.xpath( 'cac:TaxTotal/cac:TaxSubtotal', namespaces=namespaces) invoice_line_form.tax_ids.clear() for etax in taxes_elements: elements = etax.xpath('cbc:Percent', namespaces=namespaces) if elements: tax = self.env['account.tax'].search( [ ('company_id', '=', self.env.company.id), ('amount', '=', float(elements[0].text)), ('type_tax_use', '=', invoice_form.journal_id.type), ], order='sequence ASC', limit=1) if tax: invoice_line_form.tax_ids.add(tax) return invoice_form.save()
def get_rule_ids(self, test_record_ids, model_name, mode="read"): if self._uid == SUPERUSER_ID: return [] res_ids = [] model_env = self.env[model_name] self._cr.execute( """ SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id = m.id) WHERE m.model = %s AND r.active is True AND r.perm_""" + mode + """ AND (r.id IN ( SELECT rule_group_id FROM rule_group_rel g_rel JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) WHERE u_rel.uid = %s) OR r.global) """, (model_name, self._uid)) rule_ids = [x[0] for x in self._cr.fetchall()] if rule_ids: # browse user as super-admin root to avoid access errors! user_obj = self.env['res.users'].sudo().browse(self._uid) rule_data_objs = self.env['ir.rule'].browse(rule_ids) for rule in rule_data_objs: # list of domains global_domains = [] # map: group -> list of domains group_domains = {} # read 'domain' as UID to have the correct eval context # for the rule. rule_domain = rule.domain # rule_domain = rule_domain['domain'] dom = expression.normalize_domain(rule_domain) for group in rule.groups: if group in user_obj.groups_id: group_domains.setdefault(group, []).append(dom) if not rule.groups: global_domains.append(dom) # combine global domains and group domains if group_domains: group_domain = expression.OR( map(expression.OR, group_domains.values())) else: group_domain = [] domain = expression.AND(global_domains + [group_domain]) if domain: # _where_calc is called as superuser. # This means that rules can involve objects on # which the real uid has no acces rights. # This means also there is no implicit restriction # (e.g. an object references another object # the user can't see). query = self.env[model_name].sudo()._where_calc( domain, active_test=False) where_clause, where_params, tables = query.where_clause,\ query.where_clause_params, query.tables if where_clause: where_clause = ' and ' + ' and '.join(where_clause) self._cr.execute( 'SELECT ' + model_env._table + '.id FROM ' + ','.join(tables) + ' WHERE ' + model_env._table + '.id IN %s' + where_clause, ([tuple(test_record_ids)] + where_params)) returned_ids = [ x['id'] for x in self._cr.dictfetchall() ] check_rs = self.sudo( self._uid).profile_check_record_rules_result_count( test_record_ids, returned_ids, mode, model_env) if not check_rs: res_ids.append(rule.id) return res_ids
def _get_translation_frontend_modules_domain(cls): domain = super(IrHttp, cls)._get_translation_frontend_modules_domain() return expression.OR([domain, [('name', 'ilike', 'crnd_wsd')]])