From 321b2394869a606db58c74669014223b1fa512a3 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 29 Mar 2017 16:42:43 +0200 Subject: [PATCH] [ADD] operator to match for an exact amount, reference and partner --- .../README.rst | 8 +++ .../__openerp__.py | 1 + .../models/__init__.py | 3 +- ...nt_bank_statement_import_auto_reconcile.py | 50 +++++++++++++ ...ment_import_auto_reconcile_exact_amount.py | 71 ++++++++++--------- ...nk_statement_import_auto_reconcile_odoo.py | 20 ++++++ oca_dependencies.txt | 1 + 7 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_odoo.py diff --git a/account_bank_statement_import_auto_reconcile/README.rst b/account_bank_statement_import_auto_reconcile/README.rst index 5317550..5fc0d67 100644 --- a/account_bank_statement_import_auto_reconcile/README.rst +++ b/account_bank_statement_import_auto_reconcile/README.rst @@ -21,6 +21,14 @@ Usage After a journal is configured for automatic reconciliations, it simply happens during an import on this journal. If there were automatic reconciliations, you'll see a notification about that and the lines in question will also show up as reconciled. +Reconciliation rules +-------------------- + + Odoo standard + Do exactly what Odoo does when proposing reconciliations. This searches for an exact match on amount and reference first, but falls back to less exact matches if none are found before. If there's only one match, do the reconciliation + Exact amount and reference + Strictly only match if we have the same partner, amount and reference + .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot :target: https://runbot.odoo-community.org/runbot/174/8.0 diff --git a/account_bank_statement_import_auto_reconcile/__openerp__.py b/account_bank_statement_import_auto_reconcile/__openerp__.py index b556b05..5f8f27e 100644 --- a/account_bank_statement_import_auto_reconcile/__openerp__.py +++ b/account_bank_statement_import_auto_reconcile/__openerp__.py @@ -12,6 +12,7 @@ "depends": [ 'account_bank_statement_import', 'web_widget_one2many_tags', + 'base_domain_operator', ], "demo": [ "demo/account_bank_statement_import_auto_reconcile_rule.xml", diff --git a/account_bank_statement_import_auto_reconcile/models/__init__.py b/account_bank_statement_import_auto_reconcile/models/__init__.py index 3b4cbfb..dd35274 100644 --- a/account_bank_statement_import_auto_reconcile/models/__init__.py +++ b/account_bank_statement_import_auto_reconcile/models/__init__.py @@ -4,5 +4,6 @@ from . import account_bank_statement_import_auto_reconcile from . import account_bank_statement_import_auto_reconcile_rule from . import account_journal -from . import account_bank_statement_import_auto_reconcile_exact_amount +from . import account_bank_statement_import_auto_reconcile_odoo from . import account_bank_statement_import +from . import account_bank_statement_import_auto_reconcile_exact_amount diff --git a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile.py b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile.py index 3d07a63..f549f80 100644 --- a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile.py +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp.tools import float_compare, float_round from openerp import api, fields, models @@ -15,6 +16,55 @@ class AccountBankStatementImportAutoReconcile(models.AbstractModel): # between different reconciliations options = fields.Serialized('Options') + @property + def _digits(self): + try: + return self.__digits + except: + self.__digits = self.env['decimal.precision'].precision_get( + 'Account' + ) + return self.__digits + + @api.model + def _round(self, value): + return float_round(value, precision_digits=self._digits) + + @api.model + def _matches_amount(self, statement_line, debit, credit): + """helper to compare if an amount matches some move line data""" + return ( + float_compare( + debit, statement_line.amount, + precision_digits=self._digits + ) == 0 or + float_compare( + -credit, statement_line.amount, + precision_digits=self._digits + ) == 0 + ) + + @api.model + def _reconcile_move_line(self, statement_line, move_line_id): + """Helper to reconcile some move line with a bank statement. + This will create a move to reconcile with and assigns journal_entry_id + """ + move = self.env['account.move'].create( + self.env['account.bank.statement']._prepare_move( + statement_line, + ( + statement_line.statement_id.name or statement_line.name + ) + "/" + str(statement_line.sequence or '') + ) + ) + move_line_dict = self.env['account.bank.statement']\ + ._prepare_bank_move_line( + statement_line, move.id, -statement_line.amount, + statement_line.statement_id.company_id.currency_id.id, + ) + move_line_dict['counterpart_move_line_id'] = move_line_id + statement_line.process_reconciliation([move_line_dict]) + @api.multi def reconcile(self, statement_line): """Will be called on your model, with wizard_id pointing diff --git a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_exact_amount.py b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_exact_amount.py index c1918be..491315a 100644 --- a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_exact_amount.py +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_exact_amount.py @@ -1,45 +1,52 @@ # -*- coding: utf-8 -*- # © 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import api, models -from openerp.tools import float_compare +from openerp import api, fields, models class AccountBankStatementImportAutoReconcileExactAmount(models.AbstractModel): _inherit = 'account.bank.statement.import.auto.reconcile' _name = 'account.bank.statement.import.auto.reconcile.exact.amount' - _description = 'Exact match on amount' + _description = 'Exact partner, amount and reference' + + substring_match = fields.Boolean('Match for substrings', default=False) + case_sensitive = fields.Boolean('Case sensitive matching', default=False) @api.multi def reconcile(self, statement_line): - """Find an open invoice for the statement line's partner""" - # TODO: this is the lazy version, searching a bit more specialized - # and with some caching should speed this up a lot - matches = statement_line.get_reconciliation_proposition(statement_line) - digits = self.env['decimal.precision'].precision_get('Account') - if len(matches) == 1 and ( - float_compare( - matches[0]['debit'], statement_line.amount, - precision_digits=digits - ) == 0 or - float_compare( - -matches[0]['credit'], statement_line.amount, - precision_digits=digits - ) == 0 + if not statement_line.partner_id or ( + not statement_line.ref and not statement_line.name ): - move = self.env['account.move'].create( - self.env['account.bank.statement']._prepare_move( - statement_line, - ( - statement_line.statement_id.name or statement_line.name - ) + "/" + str(statement_line.sequence or '') - ) - ) - move_line_dict = self.env['account.bank.statement']\ - ._prepare_bank_move_line( - statement_line, move.id, -statement_line.amount, - statement_line.statement_id.company_id.currency_id.id, - ) - move_line_dict['counterpart_move_line_id'] = matches[0]['id'] - statement_line.process_reconciliation([move_line_dict]) + return + + operator = '=ilike' + if self.substring_match: + operator = 'substring_of' + elif self.case_sensitive: + operator = '=like' + + amount_field = 'debit' + sign = 1 + if statement_line.currency_id or statement_line.journal_id.currency: + if statement_line.amount < 0: + amount_field = 'credit' + sign = -1 + else: + amount_field = 'amount_currency' + + domain = [ + '|', '|', '|', + ('ref', operator, statement_line.ref), + ('name', operator, statement_line.name), + ('ref', operator, statement_line.name), + ('name', operator, statement_line.ref), + ('reconcile_id', '=', False), + ('state', '=', 'valid'), + ('account_id.reconcile', '=', True), + ('partner_id', '=', statement_line.partner_id.id), + (amount_field, '=', self._round(sign * statement_line.amount)), + ] + move_lines = self.env['account.move.line'].search(domain, limit=1) + if move_lines: + self._reconcile_move_line(statement_line, move_lines.id) return True diff --git a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_odoo.py b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_odoo.py new file mode 100644 index 0000000..760a829 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_odoo.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, models + + +class AccountBankStatementImportAutoReconcileOdoo(models.AbstractModel): + _inherit = 'account.bank.statement.import.auto.reconcile' + _name = 'account.bank.statement.import.auto.reconcile.odoo' + _description = 'Odoo standard' + + @api.multi + def reconcile(self, statement_line): + """Find an open invoice for the statement line's partner""" + matches = statement_line.get_reconciliation_proposition(statement_line) + if len(matches) == 1 and self._matches_amount( + statement_line, matches[0]['debit'], -matches[0]['credit'], + ): + self._reconcile_move_line(statement_line, matches[0]['id']) + return True diff --git a/oca_dependencies.txt b/oca_dependencies.txt index 9c9cf7e..14a7937 100644 --- a/oca_dependencies.txt +++ b/oca_dependencies.txt @@ -1,3 +1,4 @@ # list the OCA project dependencies, one per line # add a github url if you need a forked version web +server-tools