From 64871c6950734f53d722080449cee962c0497360 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 11 Nov 2014 11:17:27 +0100 Subject: [PATCH 01/16] 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. +

+
+
+ +
+
From fc360e656c1450cd9eefc2a2ad8d226a7e915501 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Nov 2014 09:14:18 +0100 Subject: [PATCH 02/16] Add a test suite --- .../model/account_statement_operation_rule.py | 3 + .../tests/__init__.py | 22 +++ .../tests/test_rule.py | 183 ++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 account_statement_operation_rule/tests/__init__.py create mode 100644 account_statement_operation_rule/tests/test_rule.py diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py index 3500bc32..d19866cd 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -113,6 +113,9 @@ class AccountStatementOperationRule(models.Model): balance = statement_line.amount for move_line in move_lines: balance += move_line.credit - move_line.debit + # TODO use is_zero + if not balance: + return self.browse() rules = self.search([]) # return the first applicable rule diff --git a/account_statement_operation_rule/tests/__init__.py b/account_statement_operation_rule/tests/__init__.py new file mode 100644 index 00000000..23fa21ab --- /dev/null +++ b/account_statement_operation_rule/tests/__init__.py @@ -0,0 +1,22 @@ +# -*- 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 . import test_rule diff --git a/account_statement_operation_rule/tests/test_rule.py b/account_statement_operation_rule/tests/test_rule.py new file mode 100644 index 00000000..480dba02 --- /dev/null +++ b/account_statement_operation_rule/tests/test_rule.py @@ -0,0 +1,183 @@ +# -*- 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.tests import common + + +class TestRule(common.TransactionCase): + + def setUp(self): + super(TestRule, self).setUp() + self.operation_obj = self.env['account.statement.operation.template'] + self.rule_obj = self.env['account.statement.operation.rule'] + self.operation_round_1 = self.operation_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'label': 'Rounding', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + + }) + self.rule_round_1 = self.rule_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'rule_type': 'balance', + 'operations': [(6, 0, (self.operation_round_1.id, ))], + 'amount_min': -1.0, + 'amount_max': 0, + 'sequence': 1, + }) + self.operation_round_2 = self.operation_obj.create({ + 'name': 'Rounding -2.0 to -1.0', + 'label': 'Rounding', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + + }) + self.rule_round_2 = self.rule_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'rule_type': 'balance', + 'operations': [(6, 0, (self.operation_round_2.id, ))], + 'amount_min': -2.0, + 'amount_max': -1.0, + 'sequence': 2, + }) + self.operation_round_3 = self.operation_obj.create({ + 'name': 'Rounding 0.0 to 2.0', + 'label': 'Rounding', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + + }) + self.rule_round_3 = self.rule_obj.create({ + 'name': 'Rounding 0.0 to 2.0', + 'rule_type': 'balance', + 'operations': [(6, 0, (self.operation_round_3.id, ))], + 'amount_min': 0, + 'amount_max': 2, + 'sequence': 2, + }) + + def _prepare_statement(self, difference): + amount = 100 + statement_obj = self.env['account.bank.statement'] + statement_line_obj = self.env['account.bank.statement.line'] + move_obj = self.env['account.move'] + move_line_obj = self.env['account.move.line'] + statement = statement_obj.create({ + 'name': '/', + 'journal_id': self.ref('account.cash_journal') + }) + statement_line = statement_line_obj.create({ + 'name': '001', + 'amount': amount + difference, + 'statement_id': statement.id, + }) + move = move_obj.create({ + 'journal_id': self.ref('account.sales_journal') + }) + move_line = move_line_obj.create({ + 'move_id': move.id, + 'name': '001', + 'account_id': self.ref('account.a_recv'), + 'debit': amount, + }) + move_line_obj.create({ + 'move_id': move.id, + 'name': '001', + 'account_id': self.ref('account.a_sale'), + 'credit': amount, + }) + return statement_line, move_line + + def test_rule_round_1(self): + """-0.5 => rule round 1""" + statement_line, move_line = self._prepare_statement(-0.5) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_1) + + def test_rule_round_1_limit(self): + """-1 => rule round 1""" + statement_line, move_line = self._prepare_statement(-1) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_1) + + def test_rule_round_1_near_limit(self): + """-1.0001 => rule round 1""" + statement_line, move_line = self._prepare_statement(-1.0001) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_1) + + def test_rule_round_2(self): + """-1.01 => rule round 2""" + statement_line, move_line = self._prepare_statement(-1.01) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_2) + + def test_rule_round_2_limit(self): + """-2 => rule round 2""" + statement_line, move_line = self._prepare_statement(-2) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_2) + + def test_rule_round_3(self): + """+1.5 => rule round 3""" + statement_line, move_line = self._prepare_statement(1.5) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_3) + + def test_rule_round_3_limit(self): + """+2 => rule round 3""" + statement_line, move_line = self._prepare_statement(2) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_round_3) + + def test_rule_no_round_below(self): + """-3 => no rule""" + statement_line, move_line = self._prepare_statement(-3) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_rule_no_round_above(self): + """+3 => no rule""" + statement_line, move_line = self._prepare_statement(3) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_rule_no_round_zero(self): + """0 => no rule""" + statement_line, move_line = self._prepare_statement(0) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_rule_no_round_near_zero(self): + """0.0001 => no rule""" + statement_line, move_line = self._prepare_statement(0.0001) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_operations(self): + """test operations_for_reconciliation()""" + statement_line, move_line = self._prepare_statement(-0.5) + ops = self.rule_obj.operations_for_reconciliation(statement_line.id, + move_line.ids) + self.assertEquals(ops, self.operation_round_1) From 58979a77c14f1b610a14fdb2b16aabad0444bc27 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Nov 2014 09:59:41 +0100 Subject: [PATCH 03/16] Use float comparisons --- .../model/account_statement_operation_rule.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py index d19866cd..72edb00d 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -55,8 +55,14 @@ class AccountStatementOperationRule(models.Model): @api.multi def _is_valid_balance(self, statement_line, move_lines, balance): - # TODO use float compare - return self.amount_min <= balance <= self.amount_max + currency = (statement_line.currency_id or + statement_line.statement_id.currency) + # FIXME: is_valid_balance must not work with multicurrency + if currency.compare_amounts(balance, self.amount_min) == -1: + return False + if currency.compare_amounts(balance, self.amount_max) == 1: + return False + return True @api.multi def _is_valid_multicurrency(self, statement_line, move_lines, balance): @@ -74,6 +80,7 @@ class AccountStatementOperationRule(models.Model): # 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): + # FIXME: is_valid_balance must not work with multicurrency return self._is_valid_balance(statement_line, move_lines, balance) return False @@ -113,8 +120,10 @@ class AccountStatementOperationRule(models.Model): balance = statement_line.amount for move_line in move_lines: balance += move_line.credit - move_line.debit - # TODO use is_zero - if not balance: + + currency = (statement_line.currency_id or + statement_line.statement_id.currency) + if currency.is_zero(balance): return self.browse() rules = self.search([]) From e2ecb1bb3aa25af193355358ca21396a27ac8ad8 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Nov 2014 10:10:02 +0100 Subject: [PATCH 04/16] The 'balance' rules must not match when we are in multicurrency --- .../model/account_statement_operation_rule.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py index 72edb00d..dc69f166 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -54,22 +54,35 @@ class AccountStatementOperationRule(models.Model): ) @api.multi - def _is_valid_balance(self, statement_line, move_lines, balance): - currency = (statement_line.currency_id or - statement_line.statement_id.currency) - # FIXME: is_valid_balance must not work with multicurrency + def _balance_in_range(self, balance, currency): if currency.compare_amounts(balance, self.amount_min) == -1: return False if currency.compare_amounts(balance, self.amount_max) == 1: return False return True + @api.model + def _is_multicurrency(self, statement_line): + currency = (statement_line.currency_id or + statement_line.statement_id.currency) + company_currency = statement_line.company_id.currency_id + return currency != company_currency + + @api.multi + def _is_valid_balance(self, statement_line, move_lines, balance): + if self._is_multicurrency(statement_line): + return False + currency = (statement_line.currency_id or + statement_line.statement_id.currency) + return self._balance_in_range(balance, currency) + @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 + if self._is_multicurrency(statement_line): return False + currency = (statement_line.currency_id or + statement_line.statement_id.currency) amount_currency = statement_line.amount_currency for move_line in move_lines: if move_line.currency_id != statement_line.currency_id: @@ -80,8 +93,7 @@ class AccountStatementOperationRule(models.Model): # 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): - # FIXME: is_valid_balance must not work with multicurrency - return self._is_valid_balance(statement_line, move_lines, balance) + return self._balance_in_range(balance, currency) return False @api.multi From a4b2800d42b493a46fd5d6275ff831098c4e74e4 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Nov 2014 11:07:34 +0100 Subject: [PATCH 05/16] Extract a helper so it can be reused --- .../tests/common.py | 58 +++++++++++++++++++ .../tests/test_rule.py | 58 +++++-------------- 2 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 account_statement_operation_rule/tests/common.py diff --git a/account_statement_operation_rule/tests/common.py b/account_statement_operation_rule/tests/common.py new file mode 100644 index 00000000..d8cf7d75 --- /dev/null +++ b/account_statement_operation_rule/tests/common.py @@ -0,0 +1,58 @@ +# -*- 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 . +# +############################################################################## + + +def prepare_statement(test, difference): + """ Prepare a bank statement line and a move line + + The difference is applied on the bank statement line relatively to + the move line. + """ + amount = 100 + statement_obj = test.env['account.bank.statement'] + statement_line_obj = test.env['account.bank.statement.line'] + move_obj = test.env['account.move'] + move_line_obj = test.env['account.move.line'] + statement = statement_obj.create({ + 'name': '/', + 'journal_id': test.ref('account.cash_journal') + }) + statement_line = statement_line_obj.create({ + 'name': '001', + 'amount': amount + difference, + 'statement_id': statement.id, + }) + move = move_obj.create({ + 'journal_id': test.ref('account.sales_journal') + }) + move_line = move_line_obj.create({ + 'move_id': move.id, + 'name': '001', + 'account_id': test.ref('account.a_recv'), + 'debit': amount, + }) + move_line_obj.create({ + 'move_id': move.id, + 'name': '001', + 'account_id': test.ref('account.a_sale'), + 'credit': amount, + }) + return statement_line, move_line diff --git a/account_statement_operation_rule/tests/test_rule.py b/account_statement_operation_rule/tests/test_rule.py index 480dba02..8dde1f1a 100644 --- a/account_statement_operation_rule/tests/test_rule.py +++ b/account_statement_operation_rule/tests/test_rule.py @@ -21,6 +21,8 @@ from openerp.tests import common +from .common import prepare_statement + class TestRule(common.TransactionCase): @@ -77,107 +79,75 @@ class TestRule(common.TransactionCase): 'sequence': 2, }) - def _prepare_statement(self, difference): - amount = 100 - statement_obj = self.env['account.bank.statement'] - statement_line_obj = self.env['account.bank.statement.line'] - move_obj = self.env['account.move'] - move_line_obj = self.env['account.move.line'] - statement = statement_obj.create({ - 'name': '/', - 'journal_id': self.ref('account.cash_journal') - }) - statement_line = statement_line_obj.create({ - 'name': '001', - 'amount': amount + difference, - 'statement_id': statement.id, - }) - move = move_obj.create({ - 'journal_id': self.ref('account.sales_journal') - }) - move_line = move_line_obj.create({ - 'move_id': move.id, - 'name': '001', - 'account_id': self.ref('account.a_recv'), - 'debit': amount, - }) - move_line_obj.create({ - 'move_id': move.id, - 'name': '001', - 'account_id': self.ref('account.a_sale'), - 'credit': amount, - }) - return statement_line, move_line - def test_rule_round_1(self): """-0.5 => rule round 1""" - statement_line, move_line = self._prepare_statement(-0.5) + statement_line, move_line = prepare_statement(self, -0.5) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_1) def test_rule_round_1_limit(self): """-1 => rule round 1""" - statement_line, move_line = self._prepare_statement(-1) + statement_line, move_line = prepare_statement(self, -1) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_1) def test_rule_round_1_near_limit(self): """-1.0001 => rule round 1""" - statement_line, move_line = self._prepare_statement(-1.0001) + statement_line, move_line = prepare_statement(self, -1.0001) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_1) def test_rule_round_2(self): """-1.01 => rule round 2""" - statement_line, move_line = self._prepare_statement(-1.01) + statement_line, move_line = prepare_statement(self, -1.01) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_2) def test_rule_round_2_limit(self): """-2 => rule round 2""" - statement_line, move_line = self._prepare_statement(-2) + statement_line, move_line = prepare_statement(self, -2) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_2) def test_rule_round_3(self): """+1.5 => rule round 3""" - statement_line, move_line = self._prepare_statement(1.5) + statement_line, move_line = prepare_statement(self, 1.5) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_3) def test_rule_round_3_limit(self): """+2 => rule round 3""" - statement_line, move_line = self._prepare_statement(2) + statement_line, move_line = prepare_statement(self, 2) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertEquals(rule, self.rule_round_3) def test_rule_no_round_below(self): """-3 => no rule""" - statement_line, move_line = self._prepare_statement(-3) + statement_line, move_line = prepare_statement(self, -3) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertFalse(rule) def test_rule_no_round_above(self): """+3 => no rule""" - statement_line, move_line = self._prepare_statement(3) + statement_line, move_line = prepare_statement(self, 3) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertFalse(rule) def test_rule_no_round_zero(self): """0 => no rule""" - statement_line, move_line = self._prepare_statement(0) + statement_line, move_line = prepare_statement(self, 0) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertFalse(rule) def test_rule_no_round_near_zero(self): """0.0001 => no rule""" - statement_line, move_line = self._prepare_statement(0.0001) + statement_line, move_line = prepare_statement(self, 0.0001) rule = self.rule_obj.find_first_rule(statement_line, [move_line]) self.assertFalse(rule) def test_operations(self): """test operations_for_reconciliation()""" - statement_line, move_line = self._prepare_statement(-0.5) + statement_line, move_line = prepare_statement(self, -0.5) ops = self.rule_obj.operations_for_reconciliation(statement_line.id, move_line.ids) self.assertEquals(ops, self.operation_round_1) From b376806d597297289b5d8b399ea573fe96ace026 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Nov 2014 12:00:15 +0100 Subject: [PATCH 06/16] Extract a function which is reused in account_statement_operation_rule_dunning_fees --- .../model/account_statement_operation_rule.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py index dc69f166..9c616556 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -53,14 +53,26 @@ class AccountStatementOperationRule(models.Model): help="If several rules match, the first one is used.", ) - @api.multi - def _balance_in_range(self, balance, currency): - if currency.compare_amounts(balance, self.amount_min) == -1: + @staticmethod + def _between_with_bounds(low, value, high, currency): + """ Equivalent to a three way comparison: ``min <= value <= high`` + + The comparisons are done with the currency to use the correct + precision. + """ + if currency.compare_amounts(value, low) == -1: return False - if currency.compare_amounts(balance, self.amount_max) == 1: + if currency.compare_amounts(value, high) == 1: return False return True + @api.multi + def _balance_in_range(self, balance, currency): + amount_min = self.amount_min + amount_max = self.amount_max + return self._between_with_bounds(amount_min, balance, + amount_max, currency) + @api.model def _is_multicurrency(self, statement_line): currency = (statement_line.currency_id or From 49f3ee9cabe58c330d23a051c3ba8a25bbf40e9b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 3 Dec 2014 13:20:11 +0100 Subject: [PATCH 07/16] Add a security group an account.statement.operation.rule --- account_statement_operation_rule/__openerp__.py | 1 + account_statement_operation_rule/security/ir.model.access.csv | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 account_statement_operation_rule/security/ir.model.access.csv diff --git a/account_statement_operation_rule/__openerp__.py b/account_statement_operation_rule/__openerp__.py index ab5cd38a..1302d8da 100644 --- a/account_statement_operation_rule/__openerp__.py +++ b/account_statement_operation_rule/__openerp__.py @@ -30,6 +30,7 @@ 'website': 'http://www.camptocamp.com', 'data': ['view/account_statement_operation_rule.xml', 'view/account_statement_operation_rule_view.xml', + 'security/ir.model.access.csv', ], 'installable': True, 'auto_install': False, diff --git a/account_statement_operation_rule/security/ir.model.access.csv b/account_statement_operation_rule/security/ir.model.access.csv new file mode 100644 index 00000000..f6b7bfb6 --- /dev/null +++ b/account_statement_operation_rule/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_statement_operation_rule,account.statement.operation.rule,model_account_statement_operation_rule,account.group_account_user,1,1,1,1 From ae6934e27073050f70caad2e38767dd5d782ad81 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 3 Dec 2014 14:23:36 +0100 Subject: [PATCH 08/16] Rename the basic rule 'Balance' to 'Roundings' --- .../model/account_statement_operation_rule.py | 6 +++--- account_statement_operation_rule/tests/test_rule.py | 6 +++--- .../view/account_statement_operation_rule_view.xml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/account_statement_operation_rule/model/account_statement_operation_rule.py b/account_statement_operation_rule/model/account_statement_operation_rule.py index 9c616556..3de82c85 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -30,10 +30,10 @@ class AccountStatementOperationRule(models.Model): name = fields.Char() rule_type = fields.Selection( - selection=[('balance', 'Balance'), + selection=[('rounding', 'Roundings'), ('currency', 'Currencies')], string='Type', - default='balance', + default='rounding', required=True, ) operations = fields.Many2many( @@ -126,7 +126,7 @@ class AccountStatementOperationRule(models.Model): rule when called on multiple rules. """ self.ensure_one() - if self.rule_type == 'balance': + if self.rule_type == 'rounding': return self._is_valid_balance(statement_line, move_lines, balance) elif self.rule_type == 'currency': return self._is_valid_multicurrency(statement_line, diff --git a/account_statement_operation_rule/tests/test_rule.py b/account_statement_operation_rule/tests/test_rule.py index 8dde1f1a..2f6ea990 100644 --- a/account_statement_operation_rule/tests/test_rule.py +++ b/account_statement_operation_rule/tests/test_rule.py @@ -40,7 +40,7 @@ class TestRule(common.TransactionCase): }) self.rule_round_1 = self.rule_obj.create({ 'name': 'Rounding -1.0 to 0.0', - 'rule_type': 'balance', + 'rule_type': 'rounding', 'operations': [(6, 0, (self.operation_round_1.id, ))], 'amount_min': -1.0, 'amount_max': 0, @@ -56,7 +56,7 @@ class TestRule(common.TransactionCase): }) self.rule_round_2 = self.rule_obj.create({ 'name': 'Rounding -1.0 to 0.0', - 'rule_type': 'balance', + 'rule_type': 'rounding', 'operations': [(6, 0, (self.operation_round_2.id, ))], 'amount_min': -2.0, 'amount_max': -1.0, @@ -72,7 +72,7 @@ class TestRule(common.TransactionCase): }) self.rule_round_3 = self.rule_obj.create({ 'name': 'Rounding 0.0 to 2.0', - 'rule_type': 'balance', + 'rule_type': 'rounding', 'operations': [(6, 0, (self.operation_round_3.id, ))], 'amount_min': 0, 'amount_max': 2, 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 index c4e9a3a4..ba34b050 100644 --- a/account_statement_operation_rule/view/account_statement_operation_rule_view.xml +++ b/account_statement_operation_rule/view/account_statement_operation_rule_view.xml @@ -17,7 +17,7 @@ - + - From 475d47c33e98257115ffdbd8af39d3bf8abdd2ad Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Mon, 16 Mar 2015 15:52:12 +0100 Subject: [PATCH 12/16] Add translation template --- .../i18n/account_statement_operation_rule.pot | 152 +++++++++++++++++ account_statement_operation_rule/i18n/fr.po | 158 ++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 account_statement_operation_rule/i18n/account_statement_operation_rule.pot create mode 100644 account_statement_operation_rule/i18n/fr.po diff --git a/account_statement_operation_rule/i18n/account_statement_operation_rule.pot b/account_statement_operation_rule/i18n/account_statement_operation_rule.pot new file mode 100644 index 00000000..430e735e --- /dev/null +++ b/account_statement_operation_rule/i18n/account_statement_operation_rule.pot @@ -0,0 +1,152 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_statement_operation_rule +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-03-16 14:46+0000\n" +"PO-Revision-Date: 2015-03-16 14:46+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_statement_operation_rule +#: model:ir.actions.act_window,help:account_statement_operation_rule.action_account_statement_operation_rule +msgid "

\n" +" Click to create a statement operation rule.\n" +"

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

\n" +" " +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "And" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "And the currency is one of" +msgstr "" + +#. module: account_statement_operation_rule +#: model:ir.model,name:account_statement_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,currencies:0 +#: selection:account.statement.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "" + +#. module: account_statement_operation_rule +#: help:account.statement.operation.rule,currencies:0 +msgid "For 'Currencies' rules, you can choose for which currencies the rule will be applicable." +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_statement_operation_rule +#: help:account.statement.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,name:0 +msgid "Name" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,operations:0 +msgid "Operations" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Result" +msgstr "" + +#. module: account_statement_operation_rule +#: selection:account.statement.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Rule" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Statement Operation Rule" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_search +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_tree +#: model:ir.actions.act_window,name:account_statement_operation_rule.action_account_statement_operation_rule +#: model:ir.ui.menu,name:account_statement_operation_rule.menu_action_account_statement_operation_rule +msgid "Statement Operation Rules" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,rule_type:0 +msgid "Type" +msgstr "" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "When the balance is between" +msgstr "" + diff --git a/account_statement_operation_rule/i18n/fr.po b/account_statement_operation_rule/i18n/fr.po new file mode 100644 index 00000000..4e22afe3 --- /dev/null +++ b/account_statement_operation_rule/i18n/fr.po @@ -0,0 +1,158 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_statement_operation_rule +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-03-16 14:46+0000\n" +"PO-Revision-Date: 2015-03-16 14:46+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_statement_operation_rule +#: model:ir.actions.act_window,help:account_statement_operation_rule.action_account_statement_operation_rule +msgid "

\n" +" Click to create a statement operation rule.\n" +"

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

\n" +" " +msgstr "

\n" +" Cliquer pour créer une nouvelle règle d'opération relevé.\n" +"

\n" +" Elles peuvent être utilisées pour automatiser la création de lignes " +" quand vous réconciliez des relevés bancaires." +"

\n" +" " + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "And" +msgstr "Et" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "And the currency is one of" +msgstr "Et la devise est une des suivantes" + +#. module: account_statement_operation_rule +#: model:ir.model,name:account_statement_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Ligne de relevé bancaire" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,currencies:0 +#: selection:account.statement.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "Devises" + +#. module: account_statement_operation_rule +#: help:account.statement.operation.rule,currencies:0 +msgid "For 'Currencies' rules, you can choose for which currencies the rule will be applicable." +msgstr "Pour les règles 'Devises', vous pouvez sélectionner les devises pour lesquelles la règle s'applique." + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_statement_operation_rule +#: help:account.statement.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "Si plusieurs règles correspondent, la première est utilisée." + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "Montant max." + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "Montant min." + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,name:0 +msgid "Name" +msgstr "Nom" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,operations:0 +msgid "Operations" +msgstr "Opérations" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Result" +msgstr "Résultat" + +#. module: account_statement_operation_rule +#: selection:account.statement.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "Arrondis" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Rule" +msgstr "Règle" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,sequence:0 +msgid "Sequence" +msgstr "Séquence" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Statement Operation Rule" +msgstr "Règle d'opération de relevé" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_search +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_tree +#: model:ir.actions.act_window,name:account_statement_operation_rule.action_account_statement_operation_rule +#: model:ir.ui.menu,name:account_statement_operation_rule.menu_action_account_statement_operation_rule +msgid "Statement Operation Rules" +msgstr "Règles d'opération de relevé" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "Alors l'opération suivant sera appliquée :" + +#. module: account_statement_operation_rule +#: field:account.statement.operation.rule,rule_type:0 +msgid "Type" +msgstr "Type" + +#. module: account_statement_operation_rule +#: view:account.statement.operation.rule:account_statement_operation_rule.view_account_statement_operation_rule_form +msgid "When the balance is between" +msgstr "Quand la balance est entre" + From e44c46467fba5add60a9084c9dbc7bbaf7ecac74 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 4 Dec 2014 10:15:38 +0100 Subject: [PATCH 13/16] Improve usability by splitting the view in 2 parts: rule, result --- .../account_statement_operation_rule_view.xml | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) 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 index d2d12577..8025126d 100644 --- a/account_statement_operation_rule/view/account_statement_operation_rule_view.xml +++ b/account_statement_operation_rule/view/account_statement_operation_rule_view.xml @@ -17,18 +17,20 @@ - -