diff --git a/account_bank_statement_import_auto_reconcile/README.rst b/account_bank_statement_import_auto_reconcile/README.rst new file mode 100644 index 0000000..33f9098 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/README.rst @@ -0,0 +1,81 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +===================================== +Automatic reconciliation after import +===================================== + +This addon allows you have Odoo reconcile transactions from a bank statement import automatically in cases where the matching transaction can be determined unambigously. + +Configuration +============= + +To configure this module, you need to: + +#. go to the journal your bank account uses +#. in the field ``Automatic reconciliation rules``, add at least one rule + +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. + +.. 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 + +Background +========== + +Mainly, this module is a framework for conveniently (for programmers) adding new custom automatic reconciliation rules. To do this, study the provided AbstractModels. + +Known issues / Roadmap +====================== + +* add more matching rules: + * AmountDiffuse (let the user configure the threshold) + * SameCompany (if A from company C bought it, but B from the same company/organization pays) + * AmountTransposedDigits (reconcile if only two digits are swapped. Dangerous and a special case of AmountDiffuse) + * whatever else we can think of +* add some helpers/examples for using the options field +* allow to turn off automatic reconciliations during a specific import +* allow to fiddle with the parameters of configured rules during a specific import + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Holger Brunn + +Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list `_ or the `appropriate specialized mailinglist `_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_bank_statement_import_auto_reconcile/__init__.py b/account_bank_statement_import_auto_reconcile/__init__.py new file mode 100644 index 0000000..86cb334 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/account_bank_statement_import_auto_reconcile/__openerp__.py b/account_bank_statement_import_auto_reconcile/__openerp__.py new file mode 100644 index 0000000..f7ffc31 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/__openerp__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Automatic reconciliation after import", + "version": "8.0.1.0.0", + "author": "Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": 'Banking addons', + "summary": "This module allows you to define automatic " + "reconciliation rules to be run after a bank statement is imported", + "depends": [ + 'account_bank_statement_import', + 'web_widget_one2many_tags', + ], + "data": [ + "views/account_journal.xml", + "views/account_bank_statement_import_auto_reconcile_rule.xml", + 'security/ir.model.access.csv', + ], +} diff --git a/account_bank_statement_import_auto_reconcile/models/__init__.py b/account_bank_statement_import_auto_reconcile/models/__init__.py new file mode 100644 index 0000000..3b4cbfb --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +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 diff --git a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import.py b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import.py new file mode 100644 index 0000000..740774a --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import.py @@ -0,0 +1,43 @@ +# -*- 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 AccountBankStatementImport(models.TransientModel): + _inherit = 'account.bank.statement.import' + + @api.model + def _create_bank_statement(self, stmt_vals): + statement_id, notifications = super( + AccountBankStatementImport, self + )._create_bank_statement(stmt_vals) + if not statement_id: + return statement_id, notifications + statement = self.env['account.bank.statement'].browse(statement_id) + reconcile_rules = statement.journal_id\ + .statement_import_auto_reconcile_rule_ids.mapped( + lambda x: self.env[x.rule_type].new({ + 'wizard_id': self.id, + 'options': x.options + }) + ) + auto_reconciled_ids = [] + for line in statement.line_ids: + for rule in reconcile_rules: + if rule.reconcile(line): + auto_reconciled_ids.append(line.id) + break + if auto_reconciled_ids: + notifications.append({ + 'type': 'warning', + 'message': + _("%d transactions were reconciled automatically.") % + len(auto_reconciled_ids), + 'details': { + 'name': _('Automatically reconciled'), + 'model': 'account.bank.statement.line', + 'ids': auto_reconciled_ids, + }, + }) + return statement_id, notifications 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 new file mode 100644 index 0000000..3d07a63 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, fields, models + + +class AccountBankStatementImportAutoReconcile(models.AbstractModel): + """Inherit from this class and implement the reconcile function""" + + _name = 'account.bank.statement.import.auto.reconcile' + _description = 'Base class for automatic reconciliation rules' + + wizard_id = fields.Many2one('account.bank.statement.import', required=True) + # this is meant as a field to save options in and/or to carry state + # between different reconciliations + options = fields.Serialized('Options') + + @api.multi + def reconcile(self, statement_line): + """Will be called on your model, with wizard_id pointing + to the currently open statement import wizard. If your rule consumes + any options or similar, get the values from there. + Return True if you reconciled this line, something Falsy otherwise""" + raise NotImplementedError() 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 new file mode 100644 index 0000000..37799f8 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_exact_amount.py @@ -0,0 +1,31 @@ +# -*- 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 + + +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' + + @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 + ): + statement_line.process_reconciliation(matches) + return True diff --git a/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_rule.py b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_rule.py new file mode 100644 index 0000000..b6ba788 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_bank_statement_import_auto_reconcile_rule.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import _, api, exceptions, fields, models +from .account_bank_statement_import_auto_reconcile import\ + AccountBankStatementImportAutoReconcile as auto_reconcile_base + + +class AccountBankStatementImportAutoReconcileRule(models.Model): + _name = 'account.bank.statement.import.auto.reconcile.rule' + _description = 'Automatic reconciliation rule' + + rule_type = fields.Selection('_sel_rule_type', required=True) + journal_id = fields.Many2one('account.journal', 'Journal', required=True) + options = fields.Serialized('Options') + + @api.model + def _sel_rule_type(self): + model_names = [ + model for model in self.env.registry + if self.env[model]._name != auto_reconcile_base._name and + issubclass(self.env[model].__class__, auto_reconcile_base) + ] + return self.env['ir.model'].search([ + ('model', 'in', model_names), + ]).mapped(lambda x: (x.model, x.name)) + + @api.constrains('rule_type') + def _check_rule_type(self): + for this in self: + if this.mapped( + 'journal_id.statement_import_auto_reconcile_rule_ids' + ).filtered(lambda x: x != this and x.rule_type == this.rule_type): + raise exceptions.ValidationError( + _('Reconciliation rules must be unique per journal') + ) + + @api.multi + def name_get(self): + return [ + (this.id, self.env[this.rule_type]._description) + for this in self + ] diff --git a/account_bank_statement_import_auto_reconcile/models/account_journal.py b/account_bank_statement_import_auto_reconcile/models/account_journal.py new file mode 100644 index 0000000..7b2b921 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/models/account_journal.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import fields, models + + +class AccountJournal(models.Model): + _inherit = 'account.journal' + + statement_import_auto_reconcile_rule_ids = fields.One2many( + 'account.bank.statement.import.auto.reconcile.rule', + 'journal_id', string='Automatic reconciliation rules', + help='When importing a bank statement into this journal ,' + 'apply the following rules for automatic reconciliation', + ) diff --git a/account_bank_statement_import_auto_reconcile/security/ir.model.access.csv b/account_bank_statement_import_auto_reconcile/security/ir.model.access.csv new file mode 100644 index 0000000..b6ea73f --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +account_bank_statement_import_auto_reconcile_rule,account.bank.statement.import.auto.reconcile.rule manager,model_account_bank_statement_import_auto_reconcile_rule,account.group_account_user,1,0,0,0 +account_bank_statement_import_auto_reconcile_rule_manager,account.bank.statement.import.auto.reconcile.rule manager,model_account_bank_statement_import_auto_reconcile_rule,account.group_account_manager,1,1,1,1 diff --git a/account_bank_statement_import_auto_reconcile/static/description/icon.png b/account_bank_statement_import_auto_reconcile/static/description/icon.png new file mode 100644 index 0000000..3a0328b Binary files /dev/null and b/account_bank_statement_import_auto_reconcile/static/description/icon.png differ diff --git a/account_bank_statement_import_auto_reconcile/tests/__init__.py b/account_bank_statement_import_auto_reconcile/tests/__init__.py new file mode 100644 index 0000000..785c8f5 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import test_account_bank_statement_import_auto_reconcile diff --git a/account_bank_statement_import_auto_reconcile/tests/test_account_bank_statement_import_auto_reconcile.py b/account_bank_statement_import_auto_reconcile/tests/test_account_bank_statement_import_auto_reconcile.py new file mode 100644 index 0000000..c5179ec --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/tests/test_account_bank_statement_import_auto_reconcile.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# © 2017 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp.tests.common import TransactionCase + + +class TestAccountBankStatementImportAutoReconcile(TransactionCase): + def test_account_bank_statement_import_auto_reconcile(self): + pass diff --git a/account_bank_statement_import_auto_reconcile/views/account_bank_statement_import_auto_reconcile_rule.xml b/account_bank_statement_import_auto_reconcile/views/account_bank_statement_import_auto_reconcile_rule.xml new file mode 100644 index 0000000..6706c80 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/views/account_bank_statement_import_auto_reconcile_rule.xml @@ -0,0 +1,23 @@ + + + + + account.bank.statement.import.auto.reconcile.rule + +
+ + + +
+
+
+ + account.bank.statement.import.auto.reconcile.rule + + + + + + +
+
diff --git a/account_bank_statement_import_auto_reconcile/views/account_journal.xml b/account_bank_statement_import_auto_reconcile/views/account_journal.xml new file mode 100644 index 0000000..753c3e4 --- /dev/null +++ b/account_bank_statement_import_auto_reconcile/views/account_journal.xml @@ -0,0 +1,14 @@ + + + + + account.journal + + + + + + + + +