If you want to apply ir_rules by filtering out follow the following code .
rows = self.env.cr.dictfetchall()
ids = [x['account_id'] for x in rows]
allowed_ids = set(self.env['account.account'].browse(ids).ids)
rows = [row for row in rows if row['account_id'] in allowed_ids]
if is_partner:
ids = [x['partner_id'] for x in rows]
allowed_ids = set(self.env['res.partner'].browse(ids).ids)
rows = [row for row in rows if row['partner_id'] in allowed_ids]
# Fetch other data
for row in rows:
account = self.env['account.account'].browse(row['account_id'])
row['currency_id'] = account.currency_id.id or account.company_id.currency_id.id
partner_id = is_partner and row['partner_id'] or None
row['reconciliation_proposition'] = self.get_reconciliation_proposition(account.id, partner_id)
return rows
@api.model
def get_reconciliation_proposition(self, account_id, partner_id=False):
""" Returns two lines whose amount are opposite """
# Get pairs
partner_id_condition = partner_id and 'AND a.partner_id = %(partner_id)s AND b.partner_id = %(partner_id)s' or ''
query = """
SELECT a.id, b.id
FROM account_move_line a, account_move_line b
WHERE a.amount_residual = -b.amount_residual
AND NOT a.reconciled AND NOT b.reconciled
AND a.account_id = %(account_id)s AND b.account_id = %(account_id)s
{partner_id_condition}
ORDER BY a.date asc
LIMIT 10
""".format(**locals())
self.env.cr.execute(query, locals())
pairs = self.env.cr.fetchall()
# Apply ir_rules by filtering out
all_pair_ids = [element for tupl in pairs for element in tupl]
allowed_ids = set(self.env['account.move.line'].browse(all_pair_ids).ids)
pairs = [pair for pair in pairs if pair[0] in allowed_ids and pair[1] in allowed_ids]
# Return lines formatted
if len(pairs) > 0:
target_currency = self.currency_id or self.company_id.currency_id
lines = self.browse(list(pairs[0]))
return lines.prepare_move_lines_for_reconciliation_widget(target_currency=target_currency)
return []
@api.model
def domain_move_lines_for_reconciliation(self, excluded_ids=None, str=False):
""" Returns the domain which is common to both manual and bank statement reconciliation.
:param excluded_ids: list of ids of move lines that should not be fetched
:param str: search string
"""
context = (self._context or {})
if excluded_ids is None:
excluded_ids = []
domain = []
if excluded_ids:
domain = expression.AND([domain, [('id', 'not in', excluded_ids)]])
if str:
str_domain = [
'|', ('move_id.name', 'ilike', str),
'|', ('move_id.ref', 'ilike', str),
'|', ('date_maturity', 'like', str),
'&', ('name', '!=', '/'), ('name', 'ilike', str)
]
try:
amount = float(str)
amount_domain = ['|', ('amount_residual', '=', amount), '|', ('amount_residual_currency', '=', amount), '|', ('amount_residual', '=', -amount), ('amount_residual_currency', '=', -amount)]
str_domain = expression.OR([str_domain, amount_domain])
except:
pass
# When building a domain for the bank statement reconciliation, if there's no partner
# and a search string, search also a match in the partner names
if 'bank_statement_line' in context and not context['bank_statement_line'].partner_id.id:
str_domain = expression.OR([str_domain, [('partner_id.name', 'ilike', str)]])
domain = expression.AND([domain, str_domain])
return domain
def _domain_move_lines_for_manual_reconciliation(self, account_id, partner_id=False, excluded_ids=None, str=False):
""" Create domain criteria that are relevant to manual reconciliation. """
domain = ['&', ('reconciled', '=', False), ('account_id', '=', account_id)]
if partner_id:
domain = expression.AND([domain, [('partner_id', '=', partner_id)]])
generic_domain = self.domain_move_lines_for_reconciliation(excluded_ids=excluded_ids, str=str)
return expression.AND([generic_domain, domain])
@api.model
def get_move_lines_for_manual_reconciliation(self, account_id, partner_id=False, excluded_ids=None, str=False, offset=0, limit=None, target_currency_id=False):
""" Returns unreconciled move lines for an account or a partner+account, formatted for the manual reconciliation widget """
domain = self._domain_move_lines_for_manual_reconciliation(account_id, partner_id, excluded_ids, str)
lines = self.search(domain, offset=offset, limit=limit, order="date_maturity asc, id asc")
if target_currency_id:
target_currency = self.env['res.currency'].browse(target_currency_id)
else:
account = self.env['account.account'].browse(account_id)
target_currency = account.currency_id or account.company_id.currency_id
return lines.prepare_move_lines_for_reconciliation_widget(target_currency=target_currency)
@api.v7
def prepare_move_lines_for_reconciliation_widget(self, cr, uid, line_ids, target_currency_id=False, context=None):
target_currency = target_currency_id and self.pool.get('res.currency').browse(cr, uid, target_currency_id, context=context) or False
return self.browse(cr, uid, line_ids, context).prepare_move_lines_for_reconciliation_widget(target_currency=target_currency)
@api.v8
def prepare_move_lines_for_reconciliation_widget(self, target_currency=False, target_date=False):
""" Returns move lines formatted for the manual/bank reconciliation widget
:param target_currency: curreny you want the move line debit/credit converted into
:param target_date: date to use for the monetary conversion
"""
context = dict(self._context or {})
ret = []
for line in self:
company_currency = line.account_id.company_id.currency_id
ret_line = {
'id': line.id,
'name': line.name != '/' and line.move_id.name + ': ' + line.name or line.move_id.name,
'ref': line.move_id.ref or '',
# For reconciliation between statement transactions and already registered payments (eg. checks)
# NB : we don't use the 'reconciled' field because the line we're selecting is not the one that gets reconciled
'already_paid': line.account_id.internal_type == 'liquidity',
'account_code': line.account_id.code,
'account_name': line.account_id.name,
'account_type': line.account_id.internal_type,
'date_maturity': line.date_maturity,
'date': line.date,
'journal_name': line.journal_id.name,
'partner_id': line.partner_id.id,
'partner_name': line.partner_id.name,
'currency_id': line.currency_id.id or False,
}
debit = line.debit
credit = line.credit
amount = line.amount_residual
amount_currency = line.amount_residual_currency
# For already reconciled lines, don't use amount_residual(_currency)
if line.account_id.internal_type == 'liquidity':
amount = abs(debit - credit)
amount_currency = abs(line.amount_currency)
# Get right debit / credit:
target_currency = target_currency or company_currency
line_currency = line.currency_id or company_currency
amount_currency_str = ""
total_amount_currency_str = ""
if line_currency != company_currency:
total_amount = line.amount_currency
actual_debit = debit > 0 and amount_currency or 0.0
actual_credit = credit > 0 and -amount_currency or 0.0
else:
total_amount = abs(debit - credit)
actual_debit = debit > 0 and amount or 0.0
actual_credit = credit > 0 and -amount or 0.0
if line_currency != target_currency:
amount_currency_str = formatLang(self.env, abs(actual_debit or actual_credit), currency_obj=line_currency)
total_amount_currency_str = formatLang(self.env, total_amount, currency_obj=line_currency)
ctx = context.copy()
ctx.update({'date': line.date})
total_amount = line_currency.with_context(ctx).compute(total_amount, target_currency)
actual_debit = line_currency.with_context(ctx).compute(actual_debit, target_currency)
actual_credit = line_currency.with_context(ctx).compute(actual_credit, target_currency)
amount_str = formatLang(self.env, abs(actual_debit or actual_credit), currency_obj=target_currency)
total_amount_str = formatLang(self.env, total_amount, currency_obj=target_currency)
ret_line['debit'] = abs(actual_debit)
ret_line['credit'] = abs(actual_credit)
ret_line['amount_str'] = amount_str
ret_line['total_amount_str'] = total_amount_str
ret_line['amount_currency_str'] = amount_currency_str
ret_line['total_amount_currency_str'] = total_amount_currency_str
ret.append(ret_line)
return ret
0 Comment(s)