diff --git a/account_operation_rule/README.rst b/account_operation_rule/README.rst new file mode 100644 index 00000000..0f1a5247 --- /dev/null +++ b/account_operation_rule/README.rst @@ -0,0 +1,102 @@ +.. 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 ``Reconciliation Models``, +you first want to ensure that you have at least one operation configured. +You can find them in ``Invoicing > Dashboard > Bank card > More +> Reconciliation Models``. 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 > +Dashboard > Bank card > More > Reconciliation 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 +*Reconciliation Models* 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/9.0 + +Credits +======= + +Contributors +------------ + +* Guewen Baconnier +* Cyril Gaudin + +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_operation_rule/__init__.py b/account_operation_rule/__init__.py new file mode 100644 index 00000000..bad9dcdd --- /dev/null +++ b/account_operation_rule/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import model diff --git a/account_operation_rule/__openerp__.py b/account_operation_rule/__openerp__.py new file mode 100644 index 00000000..863afcd5 --- /dev/null +++ b/account_operation_rule/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +{'name': 'Bank Statement Operation Rules', + 'version': '9.0.1.0.0', + 'author': 'Camptocamp, Odoo Community Association (OCA)', + 'maintainer': 'Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'category': 'Accounting & Finance', + 'depends': [ + 'account', + ], + 'website': 'http://www.camptocamp.com', + 'data': [ + 'view/account_operation_rule.xml', + 'view/account_operation_rule_view.xml', + 'security/ir.model.access.csv', + ], + 'installable': True, + 'auto_install': False, + } diff --git a/account_operation_rule/i18n/account_statement_operation_rule.pot b/account_operation_rule/i18n/account_statement_operation_rule.pot new file mode 100644 index 00000000..65bd7c36 --- /dev/null +++ b/account_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_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_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,currencies:0 +msgid "For 'Currencies' rules, you can choose for which currencies the rule will be applicable." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "" + diff --git a/account_operation_rule/i18n/de.po b/account_operation_rule/i18n/de.po new file mode 100644 index 00000000..a1acc918 --- /dev/null +++ b/account_operation_rule/i18n/de.po @@ -0,0 +1,161 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_operation_rule +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: bank-statement-reconcile (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-04-20 02:39+0000\n" +"PO-Revision-Date: 2016-04-19 11:45+0000\n" +"Last-Translator: <>\n" +"Language-Team: German (http://www.transifex.com/oca/OCA-bank-statement-reconcile-8-0/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: account_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Kontoauszugzeile" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "Angelegt durch" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "Angelegt am" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Dunning Fees" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,currencies:0 +msgid "" +"For 'Currencies' rules, you can choose for which currencies the rule will be" +" applicable." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "ID" + +#. module: account_operation_rule +#: help:account.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "Letzte Aktualisierung durch" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "Letzte Aktualisierung am" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "Bezeichnung" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "Reihenfolge" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "Art" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "" diff --git a/account_operation_rule/i18n/es.po b/account_operation_rule/i18n/es.po new file mode 100644 index 00000000..5b2120ad --- /dev/null +++ b/account_operation_rule/i18n/es.po @@ -0,0 +1,161 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_operation_rule +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: bank-statement-reconcile (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-04-20 02:39+0000\n" +"PO-Revision-Date: 2016-04-19 11:45+0000\n" +"Last-Translator: <>\n" +"Language-Team: Spanish (http://www.transifex.com/oca/OCA-bank-statement-reconcile-8-0/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: account_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Dunning Fees" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,currencies:0 +msgid "" +"For 'Currencies' rules, you can choose for which currencies the rule will be" +" applicable." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "Nombre" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "Secuencia" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "Tipo" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "" diff --git a/account_operation_rule/i18n/fr.po b/account_operation_rule/i18n/fr.po new file mode 100644 index 00000000..96c367e3 --- /dev/null +++ b/account_operation_rule/i18n/fr.po @@ -0,0 +1,158 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_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_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "Et" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "Et la devise est une des suivantes" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Ligne de relevé bancaire" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "Devises" + +#. module: account_operation_rule +#: help:account.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_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_operation_rule +#: help:account.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_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "Montant max." + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "Montant min." + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "Nom" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "Opérations" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "Résultat" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "Arrondis" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "Règle" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "Séquence" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "Règle d'opération de relevé" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "Règles d'opération de relevé" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "Alors l'opération suivant sera appliquée :" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "Type" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "Quand la balance est entre" + diff --git a/account_operation_rule/i18n/it.po b/account_operation_rule/i18n/it.po new file mode 100644 index 00000000..3c1ffd61 --- /dev/null +++ b/account_operation_rule/i18n/it.po @@ -0,0 +1,161 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_operation_rule +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: bank-statement-reconcile (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-04-20 02:39+0000\n" +"PO-Revision-Date: 2016-04-19 11:45+0000\n" +"Last-Translator: <>\n" +"Language-Team: Italian (http://www.transifex.com/oca/OCA-bank-statement-reconcile-8-0/language/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: account_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Linea estratto conto" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Dunning Fees" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,currencies:0 +msgid "" +"For 'Currencies' rules, you can choose for which currencies the rule will be" +" applicable." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "" + +#. module: account_operation_rule +#: help:account.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "" diff --git a/account_operation_rule/i18n/sl.po b/account_operation_rule/i18n/sl.po new file mode 100644 index 00000000..0674a816 --- /dev/null +++ b/account_operation_rule/i18n/sl.po @@ -0,0 +1,162 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_operation_rule +# +# Translators: +# Matjaž Mozetič , 2016 +msgid "" +msgstr "" +"Project-Id-Version: bank-statement-reconcile (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-04-20 02:39+0000\n" +"PO-Revision-Date: 2016-04-20 05:32+0000\n" +"Last-Translator: Matjaž Mozetič \n" +"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-bank-statement-reconcile-8-0/language/sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: sl\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" + +#. module: account_operation_rule +#: model:ir.actions.act_window,help:account_operation_rule.action_account_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 Dodaj pravilo za operacije na izpiskih.\n

\n Uporabijo se lahko za samodejno ustvarjanje postavk premikov ob usklajevanju\n bančnih izpiskov.\n

\n " + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And" +msgstr "in" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "And the currency is one of" +msgstr "in je valuta ena izmed" + +#. module: account_operation_rule +#: model:ir.model,name:account_operation_rule.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Postavka bančnega izpiska" + +#. module: account_operation_rule +#: field:account.operation.rule,create_uid:0 +msgid "Created by" +msgstr "Ustvaril" + +#. module: account_operation_rule +#: field:account.operation.rule,create_date:0 +msgid "Created on" +msgstr "Ustvarjeno" + +#. module: account_operation_rule +#: field:account.operation.rule,currencies:0 +#: selection:account.operation.rule,rule_type:0 +msgid "Currencies" +msgstr "Valute" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Dunning Fees" +msgstr "Provizije pri izterjavi" + +#. module: account_operation_rule +#: help:account.operation.rule,currencies:0 +msgid "" +"For 'Currencies' rules, you can choose for which currencies the rule will be" +" applicable." +msgstr "Pri pravilih 'valut' lahko izberete, na katere valute se pravilo nanaša." + +#. module: account_operation_rule +#: field:account.operation.rule,id:0 +msgid "ID" +msgstr "ID" + +#. module: account_operation_rule +#: help:account.operation.rule,sequence:0 +msgid "If several rules match, the first one is used." +msgstr "Če se ujema več pravil, se uporabi prvo." + +#. module: account_operation_rule +#: field:account.operation.rule,write_uid:0 +msgid "Last Updated by" +msgstr "Zadnji posodobil" + +#. module: account_operation_rule +#: field:account.operation.rule,write_date:0 +msgid "Last Updated on" +msgstr "Zadnjič posodobljeno" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_max:0 +msgid "Max. Amount" +msgstr "Maks. znesek" + +#. module: account_operation_rule +#: field:account.operation.rule,amount_min:0 +msgid "Min. Amount" +msgstr "Min. znesek" + +#. module: account_operation_rule +#: field:account.operation.rule,name:0 +msgid "Name" +msgstr "Naziv" + +#. module: account_operation_rule +#: field:account.operation.rule,operations:0 +msgid "Operations" +msgstr "Operacije" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Result" +msgstr "Rezultat" + +#. module: account_operation_rule +#: selection:account.operation.rule,rule_type:0 +msgid "Roundings" +msgstr "Zaokroževanja" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Rule" +msgstr "Pravilo" + +#. module: account_operation_rule +#: field:account.operation.rule,sequence:0 +msgid "Sequence" +msgstr "Zaporedje" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Statement Operation Rule" +msgstr "Pravilo operacij z izpiski" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_search +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_tree +#: model:ir.actions.act_window,name:account_operation_rule.action_account_operation_rule +#: model:ir.ui.menu,name:account_operation_rule.menu_action_account_operation_rule +msgid "Statement Operation Rules" +msgstr "Pravilo operacij z izpiski" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "Then the following operations will be applied:" +msgstr "se izvedejo naslednje operacije" + +#. module: account_operation_rule +#: field:account.operation.rule,rule_type:0 +msgid "Type" +msgstr "Tip" + +#. module: account_operation_rule +#: view:account.operation.rule:account_operation_rule.view_account_operation_rule_form +msgid "When the balance is between" +msgstr "Ko je stanje med" diff --git a/account_operation_rule/model/__init__.py b/account_operation_rule/model/__init__.py new file mode 100644 index 00000000..01f3b18d --- /dev/null +++ b/account_operation_rule/model/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import account_journal +from . import account_operation_rule +from . import account_statement_line diff --git a/account_operation_rule/model/account_journal.py b/account_operation_rule/model/account_journal.py new file mode 100644 index 00000000..65529b90 --- /dev/null +++ b/account_operation_rule/model/account_journal.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import api, models + + +class AccountJournal(models.Model): + _inherit = 'account.journal' + + @api.multi + def open_reconciliation_rules(self): + return self.env['ir.actions.act_window'].for_xml_id( + "account_operation_rule", + "action_account_operation_rule" + ) diff --git a/account_operation_rule/model/account_operation_rule.py b/account_operation_rule/model/account_operation_rule.py new file mode 100644 index 00000000..4f80deff --- /dev/null +++ b/account_operation_rule/model/account_operation_rule.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields, api +from openerp.addons import decimal_precision as dp + + +class AccountOperationRule(models.Model): + _name = 'account.operation.rule' + + _order = 'sequence ASC, id ASC' + + name = fields.Char() + rule_type = fields.Selection( + selection=[('rounding', 'Roundings'), + ('currency', 'Currencies')], + string='Type', + default='rounding', + required=True, + ) + operations = fields.Many2many( + comodel_name='account.operation.template', + ) + amount_min = fields.Float( + string='Min. Amount', + digits=dp.get_precision('Account'), + ) + amount_max = fields.Float( + 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.", + ) + + @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(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_for_rules() + company_currency = statement_line.company_id.currency_id + return currency != company_currency + + @api.multi + def _is_valid_balance(self, statement_line, balance): + if self._is_multicurrency(statement_line): + return False + currency = statement_line.currency_for_rules() + return self._balance_in_range(balance, currency) + + @api.multi + def _is_valid_multicurrency(self, statement_line, move_lines, balance): + """ 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 False + 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._balance_in_range(balance, currency) + 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 == 'rounding': + return self._is_valid_balance(statement_line, 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 + + currency = statement_line.currency_for_rules() + if currency.is_zero(balance): + return self.browse() + + 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.operation.template') + def operations_for_reconciliation(self, statement_line_id, move_line_ids): + """ Find the rule for the current reconciliation and returns the + ``account.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_operation_rule/model/account_statement_line.py b/account_operation_rule/model/account_statement_line.py new file mode 100644 index 00000000..4b15caa8 --- /dev/null +++ b/account_operation_rule/model/account_statement_line.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from openerp import models, api + + +class AccountBankStatementLine(models.Model): + _inherit = 'account.bank.statement.line' + + @api.multi + def currency_for_rules(self): + return self.currency_id or self.statement_id.currency_id diff --git a/account_operation_rule/security/ir.model.access.csv b/account_operation_rule/security/ir.model.access.csv new file mode 100644 index 00000000..a551798b --- /dev/null +++ b/account_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_operation_rule,account.statement.operation.rule,model_account_operation_rule,account.group_account_user,1,1,1,1 diff --git a/account_operation_rule/static/src/js/account_widgets.js b/account_operation_rule/static/src/js/account_widgets.js new file mode 100644 index 00000000..8d7a34a7 --- /dev/null +++ b/account_operation_rule/static/src/js/account_widgets.js @@ -0,0 +1,62 @@ +odoo.define('account_operation_rule', function (require) { + "use strict"; + + var core = require('web.core'); + var Model = require('web.Model'); + + var reconciliation = require('account.reconciliation'); + + reconciliation.bankStatementReconciliationLine.include({ + init: function(parent, context) { + this._super(parent, context); + this.preset_auto_clicked = false; + }, + + operation_rules: function () { + var self = this; + var model_operation_rule = new Model("account.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) { + var preset_btn = self.$("button.preset[data-presetid='" + operation_id + "']"); + preset_btn.trigger('click'); + + // Cannot click on add_line link for user here + // even with a when().done() + // because preset_btn click handler makes a rpc call + // via formCreateInputChanged method + // and we have to wait for response + self.preset_auto_clicked = true; + }); + }); + }, + + /** + * Click on add_line link if preset button have been clicked + * automatically. + */ + formCreateInputChanged: function(elt, val) { + var self = this; + var deferred = this._super(elt, val); + deferred.done(function() { + if (self.preset_auto_clicked) { + self.addLineBeingEdited(); + } + }); + }, + + render: function () { + var deferred = this._super(); + if (deferred) { + deferred.done(this.operation_rules()); + } + return deferred; + }, + restart: function () { + var deferred = this._super(); + deferred.done(this.operation_rules()); + return deferred; + } + }); +}); diff --git a/account_operation_rule/tests/__init__.py b/account_operation_rule/tests/__init__.py new file mode 100644 index 00000000..65ba9f17 --- /dev/null +++ b/account_operation_rule/tests/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_journal +from . import test_rule_rounding +from . import test_rule_currency diff --git a/account_operation_rule/tests/common.py b/account_operation_rule/tests/common.py new file mode 100644 index 00000000..8cbe1022 --- /dev/null +++ b/account_operation_rule/tests/common.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.tests.common import TransactionCase + + +class AccountOperationTestCase(TransactionCase): + + def setUp(self): + super(AccountOperationTestCase, self).setUp() + self.cash_journal = self.env['account.journal'].create({ + 'name': 'Unittest Cash journal', + 'code': 'CASH', + 'type': 'cash', + }) + + self.sale_journal = self.env['account.journal'].create({ + 'name': 'Unittest Customer Invoices', + 'code': 'INV', + 'type': 'sale', + }) + + receivable_type = self.env['account.account.type'].create({ + 'name': 'Receivable', + 'type': 'receivable' + }) + + self.account_receivable = self.env['account.account'].create({ + 'name': 'Unittest Account Receivable', + 'user_type_id': receivable_type.id, + 'code': 'TEST101200', + 'reconcile': True, + }) + + income_type = self.env['account.account.type'].create({ + 'name': 'Unittest Income', + 'type': 'other' + }) + + self.account_sale = self.env['account.account'].create({ + 'name': 'Unittest Account Sale', + 'user_type_id': income_type.id, + 'code': 'TEST200000', + 'reconcile': False, + }) + + def prepare_statement(self, difference, + statement_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 = self.env['account.bank.statement'].create({ + 'name': '/', + 'journal_id': self.cash_journal.id + }) + line_vals = { + 'name': '001', + 'amount': amount + difference, + 'statement_id': statement.id, + } + if statement_line_currency: + line_vals.update({ + 'currency_id': statement_line_currency.id, + 'amount_currency': + amount_currency + amount_currency_difference, + }) + + statement_line = self.env['account.bank.statement.line'].create( + line_vals + ) + debit_line_vals = { + 'name': '001', + 'account_id': self.account_receivable.id, + 'debit': amount, + } + if move_line_currency: + debit_line_vals.update({ + 'currency_id': move_line_currency.id, + 'amount_currency': amount_currency, + }) + + credit_line_vals = { + 'name': '001', + 'account_id': self.account_sale.id, + 'credit': amount, + } + if move_line_currency: + credit_line_vals['currency_id'] = move_line_currency.id + + move = self.env['account.move'].create({ + 'journal_id': self.sale_journal.id, + 'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)], + }) + + return statement_line, move.line_ids.filtered( + lambda l: l.debit != 0.0 + ) diff --git a/account_operation_rule/tests/test_journal.py b/account_operation_rule/tests/test_journal.py new file mode 100644 index 00000000..b4d93da0 --- /dev/null +++ b/account_operation_rule/tests/test_journal.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.tests.common import TransactionCase + + +class TestJournal(TransactionCase): + + def test_open_reconciliation_rules(self): + # Just test that method returned the good view + + result = self.env['account.journal'].open_reconciliation_rules() + self.assertEqual('account.operation.rule', result['res_model']) + self.assertEqual('form', result['view_type']) diff --git a/account_operation_rule/tests/test_rule_currency.py b/account_operation_rule/tests/test_rule_currency.py new file mode 100644 index 00000000..7f3226ae --- /dev/null +++ b/account_operation_rule/tests/test_rule_currency.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from .common import AccountOperationTestCase + + +class TestRuleCurrency(AccountOperationTestCase): + + def setUp(self): + super(TestRuleCurrency, self).setUp() + self.operation_obj = self.env['account.operation.template'] + self.rule_obj = self.env['account.operation.rule'] + self.aed = self.browse_ref('base.AED') + self.aed.active = True + self.afn = self.browse_ref('base.AFN') + self.afn.active = True + self.all = self.browse_ref('base.ALL') + self.all.active = True + self.amd = self.browse_ref('base.AMD') + self.amd.active = True + self.aoa = self.browse_ref('base.AOA') + self.aoa.active = True + + self.operation_currency_1 = self.operation_obj.create({ + 'name': 'Currency AED, AFR, ALL -1.0 to 0.0', + 'label': 'Currency', + 'account_id': self.account_receivable.id, + 'amount_type': 'percentage', + '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', + 'amount_type': 'percentage', + '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', + 'amount_type': 'percentage', + '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 = self.prepare_statement( + -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 = self.prepare_statement(-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 = self.prepare_statement( + -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 = self.prepare_statement( + -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 = self.prepare_statement( + -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 = self.prepare_statement( + -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 = self.prepare_statement( + -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 = self.prepare_statement( + -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_operation_rule/tests/test_rule_rounding.py b/account_operation_rule/tests/test_rule_rounding.py new file mode 100644 index 00000000..20290eaa --- /dev/null +++ b/account_operation_rule/tests/test_rule_rounding.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +# Author: Guewen Baconnier +# © 2014-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from .common import AccountOperationTestCase + + +class TestRuleRounding(AccountOperationTestCase): + + def setUp(self): + super(TestRuleRounding, self).setUp() + self.operation_obj = self.env['account.operation.template'] + self.rule_obj = self.env['account.operation.rule'] + self.operation_round_1 = self.operation_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'label': 'Rounding', + 'amount_type': 'percentage', + 'amount': 100.0, + + }) + self.rule_round_1 = self.rule_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'rule_type': 'rounding', + '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', + 'amount_type': 'percentage', + 'amount': 100.0, + + }) + self.rule_round_2 = self.rule_obj.create({ + 'name': 'Rounding -1.0 to 0.0', + 'rule_type': 'rounding', + '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', + 'amount_type': 'percentage', + 'amount': 100.0, + + }) + self.rule_round_3 = self.rule_obj.create({ + 'name': 'Rounding 0.0 to 2.0', + 'rule_type': 'rounding', + 'operations': [(6, 0, (self.operation_round_3.id, ))], + 'amount_min': 0, + 'amount_max': 2, + 'sequence': 2, + }) + + 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) + + def test_multicurrency_lines(self): + """No rounding rules on multi-currency lines""" + currency = self.browse_ref('base.AED') + statement_line, move_line = self.prepare_statement( + -0.5, + statement_line_currency=currency, + move_line_currency=currency + ) + ops = self.rule_obj.operations_for_reconciliation(statement_line.id, + move_line.ids) + self.assertFalse(ops) diff --git a/account_operation_rule/view/account_operation_rule.xml b/account_operation_rule/view/account_operation_rule.xml new file mode 100644 index 00000000..f31ede73 --- /dev/null +++ b/account_operation_rule/view/account_operation_rule.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/account_operation_rule/view/account_operation_rule_view.xml b/account_operation_rule/view/account_operation_rule_view.xml new file mode 100644 index 00000000..f749ce96 --- /dev/null +++ b/account_operation_rule/view/account_operation_rule_view.xml @@ -0,0 +1,105 @@ + + + + + account.operation.rule.form + account.operation.rule + +
+ +
+
+ + + + + + + + + +
+
+
+
+ + + + account.operation.rule.tree + account.operation.rule + + + + + + + + + + + + + + + account.operation.rule.search + account.operation.rule + + + + + + + + + + + + + + Reconciliation Rules + account.operation.rule + form + tree,form + + +

+ Click to create a reconciliation rule. +

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

+
+
+ + + + account.journal.dashboard.kanban.inherit + account.journal + + + + + + + + +