[IMP] account: bank statement reconciliation: allow to filter account.move.line on their residual amount
This commit is contained in:
@@ -28,6 +28,7 @@ from openerp.exceptions import UserError
|
||||
|
||||
from operator import add
|
||||
import time
|
||||
import math
|
||||
|
||||
class account_bank_statement(osv.osv):
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
@@ -567,7 +568,7 @@ class account_bank_statement_line(osv.osv):
|
||||
currency_id = st_line.currency_id.id or st_line.journal_id.currency.id
|
||||
# NB : amount can't be == 0 ; so float precision is not an issue for amount > 0 or amount < 0
|
||||
amount = st_line.amount_currency or st_line.amount
|
||||
domain = [('reconcile_partial_id', '=', False)]
|
||||
domain = []
|
||||
if currency_id:
|
||||
domain += [('currency_id', '=', currency_id)]
|
||||
sign = 1 # correct the fact that st_line.amount is signed and debit/credit is not
|
||||
@@ -580,7 +581,8 @@ class account_bank_statement_line(osv.osv):
|
||||
amount_field = 'amount_currency'
|
||||
|
||||
# Look for a matching amount
|
||||
domain_exact_amount = domain + [(amount_field, '=', float_round(sign * amount, precision_digits=precision_digits))]
|
||||
exact_match_amount_field = amount_field in ('debit', 'credit') and 'amount_residual' or 'amount_residual_currency'
|
||||
domain_exact_amount = domain + [(exact_match_amount_field, '=', float_round(amount, precision_digits=precision_digits))]
|
||||
match_id = self.get_move_lines_for_reconciliation(cr, uid, st_line, excluded_ids=excluded_ids, offset=0, limit=1, additional_domain=domain_exact_amount)
|
||||
if match_id:
|
||||
return match_id
|
||||
@@ -589,6 +591,7 @@ class account_bank_statement_line(osv.osv):
|
||||
return []
|
||||
|
||||
# Look for a set of move line whose amount is <= to the line's amount
|
||||
domain += [('reconcile_partial_id', '=', False)]
|
||||
domain += [('account_id.type', 'in', ((amount > 0 and 'receivable' or 'payable'), 'liquidity'))] # Make sure we can't mix receivable and payable
|
||||
if amount_field == 'amount_currency' and amount < 0:
|
||||
domain += [(amount_field, '<', 0), (amount_field, '>', (sign * amount))]
|
||||
@@ -648,6 +651,19 @@ class account_bank_statement_line(osv.osv):
|
||||
]
|
||||
if not st_line.partner_id.id:
|
||||
str_domain = expression.OR([str_domain, [('partner_id.name', 'ilike', str)]])
|
||||
# Filter on amount
|
||||
amount = False
|
||||
try: # Casting a str to float either throws a ValueError or return a float (or nan)
|
||||
amount = float(str)
|
||||
except ValueError:
|
||||
pass
|
||||
if amount and not math.isnan(amount):
|
||||
amount_domain = ['|', ('amount_residual', '=', amount),
|
||||
'|', ('amount_residual', '=', -amount),
|
||||
'|', ('amount_residual_currency', '=', amount),
|
||||
('amount_residual_currency', '=', -amount)]
|
||||
str_domain = expression.OR([str_domain, amount_domain])
|
||||
|
||||
domain = expression.AND([domain, str_domain])
|
||||
|
||||
return expression.AND([additional_domain, domain])
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from openerp import workflow
|
||||
@@ -27,10 +28,13 @@ from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
import openerp.addons.decimal_precision as dp
|
||||
from openerp import tools
|
||||
from openerp.tools import float_compare
|
||||
from openerp.report import report_sxw
|
||||
import openerp
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class account_move_line(osv.osv):
|
||||
_name = "account.move.line"
|
||||
_description = "Journal Items"
|
||||
@@ -157,6 +161,36 @@ class account_move_line(osv.osv):
|
||||
res[move_line.id]['amount_residual'] = sign * line_total_in_company_currency
|
||||
return res
|
||||
|
||||
def _amount_residual_search(self, cursor, user, obj, name, args, domain=None, context=None):
|
||||
ids = []
|
||||
for cond in args:
|
||||
comparator = cond[1]
|
||||
search_amount = cond[2]
|
||||
if comparator != '=':
|
||||
_logger.error('Error searching on field %s of model account_move_line : the only supported operator is =' % name)
|
||||
continue
|
||||
|
||||
if search_amount == 0:
|
||||
ids += self.search(cursor, user, [('reconcile_id', '!=', False)])
|
||||
continue
|
||||
|
||||
amount_field = name == 'amount_residual_currency' and 'amount_currency' or (search_amount > 0 and 'debit' or 'credit')
|
||||
search_amount_sign_corrected = amount_field in ('debit', 'credit') and abs(search_amount) or search_amount
|
||||
|
||||
# Get unreconciled move lines (for those, debit/credit/amount_currency is the residual amount)
|
||||
ids += self.search(cursor, user, [('reconcile_id', '=', False), ('reconcile_partial_id', '=', False), (amount_field, '=', search_amount_sign_corrected)])
|
||||
|
||||
# Get partially reconciled move lines (for those, we need to query the computed field amount_residual(_currency))
|
||||
amount_comparator = (amount_field == 'amount_currency' and search_amount < 0) and '<=' or '>='
|
||||
candidate_ids = self.search(cursor, user, [('reconcile_partial_id', '!=', False), (amount_field, amount_comparator, search_amount_sign_corrected)])
|
||||
candidates = self.browse(cursor, user, candidate_ids, context)
|
||||
if name == 'amount_residual_currency': # Note : amount_residual(_currency) is unsigned
|
||||
ids += [x.id for x in candidates if float_compare(x.amount_residual_currency, abs(search_amount), precision_digits=4) == 0]
|
||||
elif name == 'amount_residual':
|
||||
ids += [x.id for x in candidates if float_compare(x.amount_residual, abs(search_amount), precision_digits=4) == 0]
|
||||
|
||||
return [('id', 'in', ids)]
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
data = self._default_get(cr, uid, fields, context=context)
|
||||
for f in data.keys():
|
||||
@@ -462,8 +496,8 @@ class account_move_line(osv.osv):
|
||||
'reconcile_ref': fields.function(_get_reconcile, type='char', string='Reconcile Ref', oldname='reconcile', store={
|
||||
'account.move.line': (lambda self, cr, uid, ids, c={}: ids, ['reconcile_id','reconcile_partial_id'], 50),'account.move.reconcile': (_get_move_from_reconcile, None, 50)}),
|
||||
'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')),
|
||||
'amount_residual_currency': fields.function(_amount_residual, string='Residual Amount in Currency', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in its currency (maybe different of the company currency)."),
|
||||
'amount_residual': fields.function(_amount_residual, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in the company currency."),
|
||||
'amount_residual_currency': fields.function(_amount_residual, string='Residual Amount in Currency', multi="residual", fnct_search=_amount_residual_search, help="The residual amount on a receivable or payable of a journal entry expressed in its currency (maybe different of the company currency)."),
|
||||
'amount_residual': fields.function(_amount_residual, string='Residual Amount', multi="residual", fnct_search=_amount_residual_search, help="The residual amount on a receivable or payable of a journal entry expressed in the company currency."),
|
||||
'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."),
|
||||
'journal_id': fields.related('move_id', 'journal_id', string='Journal', type='many2one', relation='account.journal', required=True, select=True,
|
||||
store = {
|
||||
|
||||
@@ -1266,7 +1266,15 @@ openerp.account = function (instance) {
|
||||
var slice_start = self.get("pager_index") * self.max_move_lines_displayed;
|
||||
var slice_end = (self.get("pager_index")+1) * self.max_move_lines_displayed;
|
||||
_( _.filter(self.mv_lines_deselected, function(o){
|
||||
return o.name.indexOf(self.filter) !== -1 || o.ref.indexOf(self.filter) !== -1 })
|
||||
var floatFromFilter = false;
|
||||
try { floatFromFilter = instance.web.parse_value(self.filter, {type: 'float'}); } catch(e){}
|
||||
return o.name.indexOf(self.filter) !== -1
|
||||
|| (o.ref && o.ref.indexOf(self.filter) !== -1)
|
||||
|| (isFinite(floatFromFilter)
|
||||
&& (o.debit === floatFromFilter
|
||||
|| o.credit === floatFromFilter
|
||||
|| o.debit_currency === floatFromFilter
|
||||
|| o.credit_currency === floatFromFilter ))})
|
||||
.slice(slice_start, slice_end)).each(function(line){
|
||||
var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: false}));
|
||||
self.bindPopoverTo($line.find(".line_info_button"));
|
||||
|
||||
Reference in New Issue
Block a user