diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index 998d74b0e8b..761bf8eec5c 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -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]) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 9bed6f7120c..77a6ff2ed86 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -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 = { diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js index b60861138f7..fa7ebc11269 100644 --- a/addons/account/static/src/js/account_widgets.js +++ b/addons/account/static/src/js/account_widgets.js @@ -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"));