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 d5c9673f..633fb2a3 100644 --- a/account_statement_operation_rule/model/account_statement_operation_rule.py +++ b/account_statement_operation_rule/model/account_statement_operation_rule.py @@ -48,6 +48,12 @@ class AccountStatementOperationRule(models.Model): string='Max. Amount', digits=dp.get_precision('Account'), ) + currencies = fields.Many2many( + comodel_name='res.currency', + string='Currencies', + help="For 'Currencies' rules, you can choose for which currencies " + "the rule will be applicable.", + ) sequence = fields.Integer( default=20, help="If several rules match, the first one is used.", @@ -88,15 +94,24 @@ class AccountStatementOperationRule(models.Model): @api.multi def _is_valid_multicurrency(self, statement_line, move_lines, balance): - # FIXME: surely wrong - if self._is_multicurrency(statement_line): + """ Check if the multi-currency rule can be applied + + The rule is applied if and only if: + * The currency is not company's one + * The currency of the statement line and all the lines is the same + * The balance of the amount currencies is 0 + * The balance is between the bounds configured on the rule + """ + if not self._is_multicurrency(statement_line): return False currency = statement_line.currency_for_rules() + if currency not in self.currencies: + 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() + return False amount_currency -= move_line.amount_currency # amount in currency is the same, so the balance is diff --git a/account_statement_operation_rule/tests/__init__.py b/account_statement_operation_rule/tests/__init__.py index 5b8ab23a..a33e398b 100644 --- a/account_statement_operation_rule/tests/__init__.py +++ b/account_statement_operation_rule/tests/__init__.py @@ -20,3 +20,4 @@ ############################################################################## from . import test_rule_rounding +from . import test_rule_currency diff --git a/account_statement_operation_rule/tests/common.py b/account_statement_operation_rule/tests/common.py index 6ab6123c..96621947 100644 --- a/account_statement_operation_rule/tests/common.py +++ b/account_statement_operation_rule/tests/common.py @@ -22,13 +22,15 @@ def prepare_statement(test, difference, statement_line_currency=None, - move_line_currency=None): + move_line_currency=None, + amount_currency_difference=0): """ 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 + amount_currency = 120 statement_obj = test.env['account.bank.statement'] statement_line_obj = test.env['account.bank.statement.line'] move_obj = test.env['account.move'] @@ -43,7 +45,11 @@ def prepare_statement(test, difference, 'statement_id': statement.id, } if statement_line_currency: - line_vals['currency_id'] = statement_line_currency.id + line_vals.update({ + 'currency_id': statement_line_currency.id, + 'amount_currency': amount_currency + amount_currency_difference, + }) + statement_line = statement_line_obj.create(line_vals) move = move_obj.create({ 'journal_id': test.ref('account.sales_journal') @@ -55,7 +61,10 @@ def prepare_statement(test, difference, 'debit': amount, } if move_line_currency: - line_vals['currency_id'] = move_line_currency.id + line_vals.update({ + 'currency_id': move_line_currency.id, + 'amount_currency': amount_currency, + }) move_line = move_line_obj.create(line_vals) line_vals = { 'move_id': move.id, diff --git a/account_statement_operation_rule/tests/test_rule_currency.py b/account_statement_operation_rule/tests/test_rule_currency.py new file mode 100644 index 00000000..ecf9fe6d --- /dev/null +++ b/account_statement_operation_rule/tests/test_rule_currency.py @@ -0,0 +1,164 @@ +# -*- 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 + +from .common import prepare_statement + + +class TestRuleCurrency(common.TransactionCase): + + def setUp(self): + super(TestRuleCurrency, self).setUp() + self.operation_obj = self.env['account.statement.operation.template'] + self.rule_obj = self.env['account.statement.operation.rule'] + self.aed = self.browse_ref('base.AED') + self.afn = self.browse_ref('base.AFN') + self.all = self.browse_ref('base.ALL') + self.amd = self.browse_ref('base.AMD') + self.aoa = self.browse_ref('base.AOA') + self.operation_currency_1 = self.operation_obj.create({ + 'name': 'Currency AED, AFR, ALL -1.0 to 0.0', + 'label': 'Currency', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + }) + self.rule_currency_1 = self.rule_obj.create({ + 'name': 'Currency AED, AFR, ALL -1.0 to 0.0', + 'rule_type': 'currency', + 'operations': [(6, 0, (self.operation_currency_1.id, ))], + 'amount_min': -1.0, + 'amount_max': 0, + 'sequence': 1, + 'currencies': [(6, 0, [self.aed.id, self.afn.id, self.all.id])], + }) + self.operation_currency_2 = self.operation_obj.create({ + 'name': 'Currency AED, AFR, ALL -2.0 to -1.0', + 'label': 'Currency', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + }) + self.rule_currency_2 = self.rule_obj.create({ + 'name': 'Currency AED, AFR, ALL -2.0 to 1.0', + 'rule_type': 'currency', + 'operations': [(6, 0, (self.operation_currency_2.id, ))], + 'amount_min': -2.0, + 'amount_max': -1.0, + 'sequence': 2, + 'currencies': [(6, 0, [self.aed.id, self.afn.id, self.all.id])], + }) + self.operation_currency_3 = self.operation_obj.create({ + 'name': 'Currency AMD, AOA -2.0 to 0.0', + 'label': 'Currency', + 'account_id': self.ref('account.rsa'), + 'amount_type': 'percentage_of_total', + 'amount': 100.0, + + }) + self.rule_currency_3 = self.rule_obj.create({ + 'name': 'Currency AMD, AOA -2.0 to 0.0', + 'rule_type': 'currency', + 'operations': [(6, 0, (self.operation_currency_3.id, ))], + 'amount_min': -2, + 'amount_max': 0, + 'sequence': 2, + 'currencies': [(6, 0, [self.amd.id, self.aoa.id])], + }) + + def test_no_currency_match(self): + """No rules for the current currency""" + sek = self.browse_ref('base.SEK') + statement_line, move_line = prepare_statement( + self, -0.5, + statement_line_currency=sek, + move_line_currency=sek) + ops = self.rule_obj.operations_for_reconciliation(statement_line.id, + move_line.ids) + self.assertFalse(ops) + + def test_rounding_lines(self): + """No Currencies rules on lines with company currency""" + statement_line, move_line = prepare_statement(self, -0.5) + ops = self.rule_obj.operations_for_reconciliation(statement_line.id, + move_line.ids) + self.assertFalse(ops) + + def test_currency_rule_1(self): + """Rule 1 is found with -0.5 AED""" + statement_line, move_line = prepare_statement( + self, -0.5, + statement_line_currency=self.aed, + move_line_currency=self.aed, + amount_currency_difference=0) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_currency_1) + + def test_currency_rule_2(self): + """Rule 2 is found with -2 AED""" + statement_line, move_line = prepare_statement( + self, -2, + statement_line_currency=self.aed, + move_line_currency=self.aed, + amount_currency_difference=0) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_currency_2) + + def test_currency_rule_3(self): + """Rule 3 is found with -2 AOA""" + statement_line, move_line = prepare_statement( + self, -2, + statement_line_currency=self.aoa, + move_line_currency=self.aoa, + amount_currency_difference=0) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_currency_3) + + def test_currency_rule_not_in_bounds(self): + """No rule is found with -3 AOA""" + statement_line, move_line = prepare_statement( + self, -3, + statement_line_currency=self.aoa, + move_line_currency=self.aoa, + amount_currency_difference=0) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_no_rule_amount_currency_different(self): + """No rule when amount currency is different""" + statement_line, move_line = prepare_statement( + self, -0.5, + statement_line_currency=self.aed, + move_line_currency=self.aed, + amount_currency_difference=0.5) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertFalse(rule) + + def test_rule_amount_currency_difference_near_zero(self): + """Apply the rule when the difference is near 0""" + statement_line, move_line = prepare_statement( + self, -0.5, + statement_line_currency=self.aed, + move_line_currency=self.aed, + amount_currency_difference=-0.001) + rule = self.rule_obj.find_first_rule(statement_line, [move_line]) + self.assertEquals(rule, self.rule_currency_1) diff --git a/account_statement_operation_rule/tests/test_rule_rounding.py b/account_statement_operation_rule/tests/test_rule_rounding.py index 1a522cd1..de0639e6 100644 --- a/account_statement_operation_rule/tests/test_rule_rounding.py +++ b/account_statement_operation_rule/tests/test_rule_rounding.py @@ -19,7 +19,6 @@ # ############################################################################## -import unittest2 from openerp.tests import common from .common import prepare_statement 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 ba34b050..d2d12577 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 @@ -23,9 +23,13 @@ And +