From 4ebb2cbc72e2a8982b4bd53b2b8e08f9412e5ff5 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 11 Nov 2014 11:17:27 +0100 Subject: [PATCH] Add module account_statement_operation_rule This module allows to automatically apply Statement Operations (or "presets") on the statement lines reconciliations according to rules, for instance based on the balance. --- account_statement_operation_rule/README.rst | 101 +++++++++++++ account_statement_operation_rule/__init__.py | 3 + .../__openerp__.py | 36 +++++ .../model/__init__.py | 3 + .../model/account_statement_operation_rule.py | 138 ++++++++++++++++++ .../static/src/js/account_widgets.js | 37 +++++ .../view/account_statement_operation_rule.xml | 11 ++ .../account_statement_operation_rule_view.xml | 83 +++++++++++ 8 files changed, 412 insertions(+) create mode 100644 account_statement_operation_rule/README.rst create mode 100644 account_statement_operation_rule/__init__.py create mode 100644 account_statement_operation_rule/__openerp__.py create mode 100644 account_statement_operation_rule/model/__init__.py create mode 100644 account_statement_operation_rule/model/account_statement_operation_rule.py create mode 100644 account_statement_operation_rule/static/src/js/account_widgets.js create mode 100644 account_statement_operation_rule/view/account_statement_operation_rule.xml create mode 100644 account_statement_operation_rule/view/account_statement_operation_rule_view.xml diff --git a/account_statement_operation_rule/README.rst b/account_statement_operation_rule/README.rst new file mode 100644 index 00000000..9f6b82d2 --- /dev/null +++ b/account_statement_operation_rule/README.rst @@ -0,0 +1,101 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License + +Bank Statement Operation Rules +============================== + +This module complements the Reconciliation of the bank statements. When +the bank statement matches one or more journal entry for a line and +there is a remaining balance, Odoo proposes you to click on buttons that +will generate write-off entries according to pre-configured *Statement +Operation Templates*. The aim of this module is to automatically click +for you on these buttons (i.e. create the write-off journal entries) +when some rules are respected, rules that you can configure. + +It contains 2 types of rules (but can be extended with additional rules), +described below: + +Roundings + The most basic rule: when the remaining balance is within a range, 1 + or more operations are applied. + +Currencies + When the remaining balance is within a range and the currency of all + the lines is the same but different from the company's, and the amount + currency is the same, 1 or more operations are applied. + + +Configuration +------------- + +As this module aims to automatize the ``Statement Operation Templates``, +you first want to ensure that you have at least one operation configured. +You can find them in ``Invoicing > Configuration > Miscellaneous > +Statement Operation Templates``. An example of a common operation is: + +=================== ========================== ======= ======== +Account Amount Type Amount Label +=================== ========================== ======= ======== +Depends of the l10n Percentage of open balance 100.0 % Rounding +=================== ========================== ======= ======== + +The configuration of the rules themselves happens in ``Invoicing > +Configuration > Miscellaneous > Statement Operation Rules``. Refer to +the description of the types of rules above in case of doubt. The form +is divided in 2 parts: **Rule** and **Result**. The rule part is where +you will set the conditions and the result part is what operations will +be done if the conditions are valid. + +For the **Roundings** rules, you will set a min. and a max. amount. It +can be negative or positive. The amount is compared to the remaining +balance when lines are matched in the bank statement. Example: if you +want to create a move line in a loss account when you received 1.- not +enough, you can create a rule with an min. amount of -1.0 and a max. +amount of 0.0. + +For the **Currencies** rules, the min. and max. amount have the same +properties, but you will also set the currencies for which the rule +applies. Setting the currency allows to configure different amounts +according to the currencies. + +Only the first rule matching the current situation is used, so if you +have several rules overlapping for some reason, be sure to order them +appropriately in the list view. + +Usage +----- + +When you use the *Reconcile* button of a bank statement, Odoo +automatically proposes you matching journal entries for each statement +line. This module automatically adds journal entries generated from the +*Statement Operation Templates* if a rule matches with the current +situation, so there is nothing special to do once the rules are +configured. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/98/8.0 + +Credits +======= + +Contributors +------------ + +* Guewen Baconnier + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://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 +http://odoo-community.org. diff --git a/account_statement_operation_rule/__init__.py b/account_statement_operation_rule/__init__.py new file mode 100644 index 00000000..bad9dcdd --- /dev/null +++ b/account_statement_operation_rule/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import model diff --git a/account_statement_operation_rule/__openerp__.py b/account_statement_operation_rule/__openerp__.py new file mode 100644 index 00000000..ab5cd38a --- /dev/null +++ b/account_statement_operation_rule/__openerp__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2014 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{'name': 'Bank Statement Operation Rules', + 'version': '8.0.1.0.0', + 'author': 'Camptocamp', + 'maintainer': 'Camptocamp', + 'license': 'AGPL-3', + 'category': 'Accounting & Finance', + 'depends': ['account', + ], + 'website': 'http://www.camptocamp.com', + 'data': ['view/account_statement_operation_rule.xml', + 'view/account_statement_operation_rule_view.xml', + ], + 'installable': True, + 'auto_install': False, + } diff --git a/account_statement_operation_rule/model/__init__.py b/account_statement_operation_rule/model/__init__.py new file mode 100644 index 00000000..f8bd646b --- /dev/null +++ b/account_statement_operation_rule/model/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import account_statement_operation_rule diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py new file mode 100644 index 00000000..3500bc32 --- /dev/null +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2014 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api +from openerp.addons import decimal_precision as dp + + +class AccountStatementOperationRule(models.Model): + _name = 'account.statement.operation.rule' + + _order = 'sequence ASC, id ASC' + + name = fields.Char() + rule_type = fields.Selection( + selection=[('balance', 'Balance'), + ('currency', 'Currencies')], + string='Type', + default='balance', + required=True, + ) + operations = fields.Many2many( + comodel_name='account.statement.operation.template', + relation='account_statement_oper_rule_rel', + ) + amount_min = fields.Float( + string='Min. Amount', + digits=dp.get_precision('Account'), + ) + amount_max = fields.Float( + string='Max. Amount', + digits=dp.get_precision('Account'), + ) + sequence = fields.Integer( + default=20, + help="If several rules match, the first one is used.", + ) + + @api.multi + def _is_valid_balance(self, statement_line, move_lines, balance): + # TODO use float compare + return self.amount_min <= balance <= self.amount_max + + @api.multi + def _is_valid_multicurrency(self, statement_line, move_lines, balance): + # FIXME: surely wrong + if statement_line.currency_id == statement_line.company_id.currency_id: + # not multicurrency + return False + amount_currency = statement_line.amount_currency + for move_line in move_lines: + if move_line.currency_id != statement_line.currency_id: + # use case not supported, no rule found + return self.browse() + amount_currency -= move_line.amount_currency + + # amount in currency is the same, so the balance is + # a difference due to currency rates + if statement_line.currency_id.is_zero(amount_currency): + return self._is_valid_balance(statement_line, move_lines, balance) + return False + + @api.multi + def is_valid(self, statement_line, move_lines, balance): + """ Returns True if a rule applies to a group of statement_line + + move lines. + + This is the public method where the rule is evaluated whatever + its type is. When a rule returns True, it means that it is a + candidate for the current reconciliation. The rule with the lowest + number in the ``sequence`` field is chosen. + + :param statement_line: the line to reconcile + :param move_lines: the selected move lines for reconciliation + :param balance: the balance between the statement_line and the + move_lines. It could be computed here but it is + computed before to avoid to compute it for each + rule when called on multiple rules. + """ + self.ensure_one() + if self.rule_type == 'balance': + return self._is_valid_balance(statement_line, move_lines, balance) + elif self.rule_type == 'currency': + return self._is_valid_multicurrency(statement_line, + move_lines, + balance) + + @api.model + def find_first_rule(self, statement_line, move_lines): + """ Find the rules that apply to a statement line and + a selection of move lines. + + :param statement_line: the line to reconcile + :param move_lines: the selected move lines for reconciliation + """ + balance = statement_line.amount + for move_line in move_lines: + balance += move_line.credit - move_line.debit + + rules = self.search([]) + # return the first applicable rule + for rule in rules: + if rule.is_valid(statement_line, move_lines, balance): + return rule + return self.browse() + + @api.model + @api.returns('account.statement.operation.template') + def operations_for_reconciliation(self, statement_line_id, move_line_ids): + """ Find the rule for the current reconciliation and returns the + ``account.statement.operation.template`` of the found rule. + + Called from the javascript reconciliation view. + + """ + line_obj = self.env['account.bank.statement.line'] + move_line_obj = self.env['account.move.line'] + statement_line = line_obj.browse(statement_line_id) + move_lines = move_line_obj.browse(move_line_ids) + rules = self.find_first_rule(statement_line, move_lines) + return rules.operations diff --git a/account_statement_operation_rule/static/src/js/account_widgets.js b/account_statement_operation_rule/static/src/js/account_widgets.js new file mode 100644 index 00000000..8912a7eb --- /dev/null +++ b/account_statement_operation_rule/static/src/js/account_widgets.js @@ -0,0 +1,37 @@ +openerp.account_statement_operation_rule = function (instance) { + + var _t = instance.web._t, + _lt = instance.web._lt; + var QWeb = instance.web.qweb; + + instance.web.account_statement_operation_rule = instance.web.account_statement_operation_rule || {}; + + instance.web.account.bankStatementReconciliationLine.include({ + operation_rules: function() { + var self = this; + var model_operation_rule = new instance.web.Model("account.statement.operation.rule"); + model_operation_rule.call("operations_for_reconciliation", + [self.st_line.id, + _.pluck(self.get("mv_lines_selected"), 'id')]) + .then(function (operations) { + _.each(operations, function(operation_id) { + preset_btn = self.$("button.preset[data-presetid='" + operation_id + "']"); + preset_btn.click(); + self.addLineBeingEdited(); + }); + }); + }, + render: function() { + deferred = this._super(); + if (deferred) { + deferred.done(this.operation_rules()); + } + return deferred; + }, + restart: function() { + deferred = this._super(); + deferred.done(this.operation_rules()); + return deferred; + }, + }); +}; diff --git a/account_statement_operation_rule/view/account_statement_operation_rule.xml b/account_statement_operation_rule/view/account_statement_operation_rule.xml new file mode 100644 index 00000000..dacd629c --- /dev/null +++ b/account_statement_operation_rule/view/account_statement_operation_rule.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/account_statement_operation_rule/view/account_statement_operation_rule_view.xml b/account_statement_operation_rule/view/account_statement_operation_rule_view.xml new file mode 100644 index 00000000..c4e9a3a4 --- /dev/null +++ b/account_statement_operation_rule/view/account_statement_operation_rule_view.xml @@ -0,0 +1,83 @@ + + + + + + account.statement.operation.rule.form + account.statement.operation.rule + +
+ +
+
+ + + + + + + +
+
+
+
+ + account.statement.operation.rule.tree + account.statement.operation.rule + + + + + + + + + + + + + account.statement.operation.rule.search + account.statement.operation.rule + + + + + + + + + + + + Statement Operation Rules + account.statement.operation.rule + form + tree,form + + +

+ Click to create a statement operation rule. +

+ Those can be used to automatically create a move line when reconciling + your bank statements. +

+
+
+ +
+