diff --git a/l10n_ch_base_bank/README.rst b/l10n_ch_base_bank/README.rst new file mode 100644 index 000000000..cc1db2c09 --- /dev/null +++ b/l10n_ch_base_bank/README.rst @@ -0,0 +1,125 @@ +======================= +Switzerland - Bank type +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:51552dc058fb6842651372cdb6fd137a9cc413812f14c56d324f9d97e9c56273 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--switzerland-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-switzerland/tree/14.0/l10n_ch_base_bank + :alt: OCA/l10n-switzerland +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-switzerland-14-0/l10n-switzerland-14-0-l10n_ch_base_bank + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-switzerland&target_branch=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon extend the features of l10n_ch. + +Most of the former features have been moved in l10n_ch module. + + +Features: + +Improve UX with onchanges: + +- automatically set bank based on clearing part of IBAN +- allow direct entry of l10n_ch_postal which will fill acc_number +- search invoices by ISR, with or without spaces + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +In partner bank account the type will be discovered automatically. + +* For IBAN accounts fill account number with IBAN. + * if the IBAN is an IBAN from PostFinance it will fill the Postal account number +* For Postal accounts: + * fill the account number with a postal account number 9 digits format (e.g. 10-8060-7). + * or fill the "Swiss postal account" with a postal account number 9 digits format (e.g. 10-8060-7). + +Entering a postal number of 9 digits will auto-complete the bank with PostFinance. (You might create it if you haven't installed `l10n_ch_bank`) + +* For ISR subscription numbers (postal account starting with 01 or 03): + * fill the account number with a postal account number 9 digits format (e.g. 01-23456-1). + * or fill the "Swiss postal account" with a postal account number 9 digits format (e.g. 01-23456-1). + +It will automatically change the content of account number by adding "ISR" and the partner name to avoid +duplicates with partner using the same ISR subscription number owned by a bank (ISR-B). + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Nicolas Bessi (Camptocamp) +* Vincent Renaville +* Joël Grand-Guillaume +* Guewen Baconnier +* Paul Catinean +* Yannick Vaucher +* Akim Juillerat +* Iryna Vyshnevska +* Simone Vanin + +Other credits +~~~~~~~~~~~~~ + +The development of this module has been financially supported by: + +* Hasa SA +* Open Net SA +* Prisme Solutions Informatique SA +* Quod SA + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/l10n-switzerland `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_ch_base_bank/__init__.py b/l10n_ch_base_bank/__init__.py new file mode 100644 index 000000000..36c4b3ab7 --- /dev/null +++ b/l10n_ch_base_bank/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import postfinance diff --git a/l10n_ch_base_bank/__manifest__.py b/l10n_ch_base_bank/__manifest__.py new file mode 100644 index 000000000..30748f8d3 --- /dev/null +++ b/l10n_ch_base_bank/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Switzerland - Bank type", + "summary": "Types and number validation for swiss electronic pmnt. DTA, ESR", + "version": "16.0.1.0.0", + "author": "Camptocamp,Odoo Community Association (OCA)", + "category": "Localization", + "website": "https://github.com/OCA/l10n-switzerland", + "license": "AGPL-3", + "depends": ["base_iban", "l10n_ch"], + "data": ["views/bank.xml"], + "auto_install": True, + "installable": True, +} diff --git a/l10n_ch_base_bank/i18n/de.po b/l10n_ch_base_bank/i18n/de.po new file mode 100644 index 000000000..c8c625e0a --- /dev/null +++ b/l10n_ch_base_bank/i18n/de.po @@ -0,0 +1,179 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_ch_base_bank +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-12-16 06:26+0000\n" +"PO-Revision-Date: 2018-11-24 20:10+0000\n" +"Last-Translator: chrispi-ch \n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.2.2\n" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_bank +msgid "Bank" +msgstr "Bank" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_partner_bank +msgid "Bank Accounts" +msgstr "Bankkonten" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "Bank account must contain a subscription number for ISR ref type." +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "" +"Bank account shouldn't be empty, for ISR ref type, you can set it manually " +"or set appropriate payment mode." +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "Banks" +msgstr "Banken" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__city +msgid "City" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__city +msgid "City of the bank" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__clearing +msgid "Clearing number" +msgstr "Clearingnummer" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__code +msgid "Code" +msgstr "Code" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__country_code +msgid "Country code" +msgstr "Ländercode" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__id +msgid "ID" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {} {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__code +msgid "Internal reference" +msgstr "Interne Referenz" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "PostFinance" +msgstr "PostFinance" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__clearing +msgid "Swiss unique bank identifier also used in IBAN number" +msgstr "Instituts-Identifikation (IID; früher Clearingnummer)" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__country_code +msgid "" +"The ISO country code in two chars. \n" +"You can use this field for quick search." +msgstr "" +"Der zweistellige ISO Ländercode. \n" +"Sie können dieses Feld für die Schnellsuche verwenden." + +#~ msgid "Bank ISR adherent number" +#~ msgstr "ESR-Teilnehmernummer der Bank" + +#, python-format +#~ msgid "Bank/CCP Undefined" +#~ msgstr "Bank/Postkonto nicht definiert" + +#, python-format +#~ msgid "Bank/CCP {}" +#~ msgstr "Bank/Postkonto {}" + +#~ msgid "CCP/CP-Konto" +#~ msgstr "Postkonto" + +#~ msgid "CCP/CP-Konto of the bank" +#~ msgstr "Postkonto der Bank" + +#~ msgid "Invoice" +#~ msgstr "Rechnung" + +#, python-format +#~ msgid "Please enter a correct postal number. (01-23456-1 or 12345)" +#~ msgstr "" +#~ "Bitte geben Sie eine korrekte Postkonto-Nummer ein (01-23456-1 oder 12345)" + +#~ msgid "The ISR adherent number must be unique !" +#~ msgstr "Die zugehörige ESR-Nummer muss eindeutig sein!" + +#~ msgid "" +#~ "Your Bank adherent number to be printed in references of your ISR. This " +#~ "is not a postal account number." +#~ msgstr "" +#~ "Die ESR-Teilnehmernummer, welche in der Codierzeile des " +#~ "Einzahlungsscheins gedruckt wird. Hinweis: Dies ist kein Postkonto." + +#, python-format +#~ msgid "" +#~ "Your bank ISR adherent number must contain only digits!\n" +#~ "Please check your company bank account." +#~ msgstr "" +#~ "Die ESR-Teilnehmernummer Ihrer Bank darf nur Ziffern enthalten.\n" +#~ "Bitte überprüfen Sie das Bankkonto Ihres Unternehmens." diff --git a/l10n_ch_base_bank/i18n/fr.po b/l10n_ch_base_bank/i18n/fr.po new file mode 100644 index 000000000..c5c3d758a --- /dev/null +++ b/l10n_ch_base_bank/i18n/fr.po @@ -0,0 +1,180 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_ch_base_bank +# +# Translators: +# OCA Transbot , 2017 +# Yannick Vaucher , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 07:11+0000\n" +"PO-Revision-Date: 2019-08-14 09:44+0000\n" +"Last-Translator: Valaeys Stéphane \n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_bank +msgid "Bank" +msgstr "Banque" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_partner_bank +msgid "Bank Accounts" +msgstr "Comptes bancaires" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "Bank account must contain a subscription number for ISR ref type." +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "" +"Bank account shouldn't be empty, for ISR ref type, you can set it manually " +"or set appropriate payment mode." +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "Banks" +msgstr "Banques" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__city +msgid "City" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__city +msgid "City of the bank" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__clearing +msgid "Clearing number" +msgstr "Numéro de clearing" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__code +msgid "Code" +msgstr "Code" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__country_code +msgid "Country code" +msgstr "Code pays" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__id +msgid "ID" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {} {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__code +msgid "Internal reference" +msgstr "Référence interne" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "PostFinance" +msgstr "PostFinance" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__clearing +msgid "Swiss unique bank identifier also used in IBAN number" +msgstr "Identifiant Suisse unique de la banque, utilisé dans le numéro IBAN" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__country_code +msgid "" +"The ISO country code in two chars. \n" +"You can use this field for quick search." +msgstr "" +"Le code pays ISO a deux caractères.\n" +"Vous pouvez l'utiliser pour des recherches rapides." + +#~ msgid "Bank ISR adherent number" +#~ msgstr "Numéro d'adhérent BVR" + +#, python-format +#~ msgid "Bank/CCP Undefined" +#~ msgstr "Banque / CCP indéfini" + +#, python-format +#~ msgid "Bank/CCP {}" +#~ msgstr "Banque / CCP {}" + +#~ msgid "CCP/CP-Konto" +#~ msgstr "Compte CCP/CP" + +#~ msgid "CCP/CP-Konto of the bank" +#~ msgstr "Compte CCP/CP de la banque" + +#~ msgid "Invoice" +#~ msgstr "Facture" + +#, python-format +#~ msgid "Please enter a correct postal number. (01-23456-1 or 12345)" +#~ msgstr "Merci d'entrer un numéro postal correct (01-23456-1 ou 12345)" + +#~ msgid "The ISR adherent number must be unique !" +#~ msgstr "Le numéro d'adhérent BVR doit être unique !" + +#~ msgid "" +#~ "Your Bank adherent number to be printed in references of your ISR. This " +#~ "is not a postal account number." +#~ msgstr "" +#~ "Votre numéro d'adhérent BVR qui sera imprimé sur vos BVRs. Ce n'est pas " +#~ "un numéro de compte postal." + +#, python-format +#~ msgid "" +#~ "Your bank ISR adherent number must contain only digits!\n" +#~ "Please check your company bank account." +#~ msgstr "" +#~ "Votre numéro d'adhérent BVR de votre banque ne doit contenir que des " +#~ "chiffres!\n" +#~ "Veuillez vérifier le compte bancaire de votre société." diff --git a/l10n_ch_base_bank/i18n/it.po b/l10n_ch_base_bank/i18n/it.po new file mode 100644 index 000000000..0c5edadb1 --- /dev/null +++ b/l10n_ch_base_bank/i18n/it.po @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_ch_base_bank +# +# Translators: +# OCA Transbot , 2017 +# Stefano , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 07:11+0000\n" +"PO-Revision-Date: 2024-05-06 14:42+0000\n" +"Last-Translator: mymage \n" +"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_bank +msgid "Bank" +msgstr "Banca" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_partner_bank +msgid "Bank Accounts" +msgstr "Conti bancari" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "Bank account must contain a subscription number for ISR ref type." +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "" +"Bank account shouldn't be empty, for ISR ref type, you can set it manually " +"or set appropriate payment mode." +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "Banks" +msgstr "Banche" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__city +msgid "City" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__city +msgid "City of the bank" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__clearing +msgid "Clearing number" +msgstr "Numero Clearing" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__code +msgid "Code" +msgstr "Codice" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__country_code +msgid "Country code" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__id +msgid "ID" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {} {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__code +msgid "Internal reference" +msgstr "Riferimento interno" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "PostFinance" +msgstr "PostFinance" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__clearing +msgid "Swiss unique bank identifier also used in IBAN number" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__country_code +msgid "" +"The ISO country code in two chars. \n" +"You can use this field for quick search." +msgstr "" + +#~ msgid "CCP/CP-Konto" +#~ msgstr "Conto CCP/CP" + +#~ msgid "CCP/CP-Konto of the bank" +#~ msgstr "Conto CCP/CP per la Banca" + +#~ msgid "Invoice" +#~ msgstr "Fattura" + +#, python-format +#~ msgid "Please enter a correct postal number. (01-23456-1 or 12345)" +#~ msgstr "Inserire un conto postale corretto. (01-23456-1 or 12345)" + +#~ msgid "The ISR adherent number must be unique !" +#~ msgstr "Il numero di adesione PVR deve essere univoco" diff --git a/l10n_ch_base_bank/i18n/l10n_ch_base_bank.pot b/l10n_ch_base_bank/i18n/l10n_ch_base_bank.pot new file mode 100644 index 000000000..8f410cacf --- /dev/null +++ b/l10n_ch_base_bank/i18n/l10n_ch_base_bank.pot @@ -0,0 +1,128 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_ch_base_bank +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \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: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_bank +msgid "Bank" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_res_partner_bank +msgid "Bank Accounts" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "Bank account must contain a subscription number for ISR ref type." +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/invoice.py:0 +#, python-format +msgid "" +"Bank account shouldn't be empty, for ISR ref type, you can set it manually " +"or set appropriate payment mode." +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "Banks" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__city +msgid "City" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__city +msgid "City of the bank" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__clearing +msgid "Clearing number" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__code +msgid "Code" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__country_code +msgid "Country code" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__display_name +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank__id +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank__id +msgid "ID" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: code:addons/l10n_ch_base_bank/models/partner_bank.py:0 +#, python-format +msgid "ISR {} {}" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__code +msgid "Internal reference" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model,name:l10n_ch_base_bank.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_bank____last_update +#: model:ir.model.fields,field_description:l10n_ch_base_bank.field_res_partner_bank____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_ch_base_bank +#: model_terms:ir.ui.view,arch_db:l10n_ch_base_bank.view_bank_search +msgid "PostFinance" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__clearing +msgid "Swiss unique bank identifier also used in IBAN number" +msgstr "" + +#. module: l10n_ch_base_bank +#: model:ir.model.fields,help:l10n_ch_base_bank.field_res_bank__country_code +msgid "" +"The ISO country code in two chars. \n" +"You can use this field for quick search." +msgstr "" diff --git a/l10n_ch_base_bank/models/__init__.py b/l10n_ch_base_bank/models/__init__.py new file mode 100644 index 000000000..a52bdb7e5 --- /dev/null +++ b/l10n_ch_base_bank/models/__init__.py @@ -0,0 +1,3 @@ +from . import bank +from . import partner_bank +from . import invoice diff --git a/l10n_ch_base_bank/models/bank.py b/l10n_ch_base_bank/models/bank.py new file mode 100644 index 000000000..e9d88f121 --- /dev/null +++ b/l10n_ch_base_bank/models/bank.py @@ -0,0 +1,52 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + +from .. import postfinance + + +class Bank(models.Model): + """Inherit res.bank class in order to add swiss specific field""" + + _inherit = "res.bank" + + code = fields.Char(help="Internal reference") + clearing = fields.Char( + string="Clearing number", + help="Swiss unique bank identifier also used in IBAN number", + ) + city = fields.Char(help="City of the bank") + country_code = fields.Char(related="country.code", readonly=True) + + def is_swiss_post(self): + return self.bic == postfinance.BIC + + def name_get(self): + """Format displayed name""" + res = [] + cols = ("bic", "name", "street", "city") + for bank in self: + vals = (bank[x] for x in cols if bank[x]) + res.append((bank.id, " - ".join(vals))) + return res + + @api.model + def name_search(self, name, args=None, operator="ilike", limit=80): + """Extends to look on bank code, bic, name, street and city""" + if args is None: + args = [] + ids = [] + cols = ("code", "bic", "name", "street", "city") + if name: + for val in name.split(" "): + for col in cols: + tmp_ids = self.search([(col, "ilike", val)] + args, limit=limit) + if tmp_ids: + ids += tmp_ids.ids + break + else: + ids = self.search(args, limit=limit).ids + # we sort by occurrence + to_ret_ids = list(set(ids)) + to_ret_ids = sorted(to_ret_ids, key=lambda x: ids.count(x), reverse=True) + return self.browse(to_ret_ids).name_get() diff --git a/l10n_ch_base_bank/models/invoice.py b/l10n_ch_base_bank/models/invoice.py new file mode 100644 index 000000000..1448d4885 --- /dev/null +++ b/l10n_ch_base_bank/models/invoice.py @@ -0,0 +1,117 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import _, api, exceptions, models + + +class AccountMove(models.Model): + + _inherit = "account.move" + + def _search( + self, + args, + offset=0, + limit=None, + order=None, + count=False, + access_rights_uid=None, + ): + domain = [] + for arg in args: + if not isinstance(arg, (tuple, list)) or len(arg) != 3: + domain.append(arg) + continue + field, operator, value = arg + if field != "ref": + domain.append(arg) + continue + if operator not in ( + "like", + "ilike", + "=like", + "=ilike", + "not like", + "not ilike", + ): + domain.append(arg) + continue + if value: + value = value.replace(" ", "") + if not value: + # original value contains only spaces, the query + # would return all rows, so avoid a costly search + # and drop the domain triplet + continue + # add wildcards for the like search, except if the operator + # is =like of =ilike because they are supposed to be there yet + if operator.startswith("="): + operator = operator[1:] + else: + value = "%{}%".format(value) + # add filtered operator to query + query_op = ( + "SELECT id FROM account_move " + "WHERE REPLACE(ref, ' ', '') %s %%s" % (operator,) + ) + # avoid pylint check on no-sql-injection query_op is safe + query = query_op + self.env.cr.execute(query, (value,)) + ids = [t[0] for t in self.env.cr.fetchall()] + domain.append(("id", "in", ids)) + + return super()._search( + domain, + offset=offset, + limit=limit, + order=order, + count=count, + access_rights_uid=access_rights_uid, + ) + + @api.constrains("ref", "payment_reference") + def _check_bank_type_for_type_isr(self): + """Compatibility with module `account_payment_partner`""" + for move in self: + if move.move_type == "out_invoice" and move._has_isr_ref(): + if hasattr(super(), "partner_banks_to_show"): + bank_acc = move.partner_banks_to_show() + else: + bank_acc = move.partner_bank_id + if not bank_acc: + raise exceptions.ValidationError( + _( + "Bank account shouldn't be empty, for ISR ref" + " type, you can set it manually or set appropriate" + " payment mode." + ) + ) + if ( + bank_acc.acc_type != "qr-iban" + and ( + move.currency_id.name == "CHF" + and not bank_acc.l10n_ch_isr_subscription_chf + ) + or ( + move.currency_id.name == "EUR" + and not bank_acc.l10n_ch_isr_subscription_eur + ) + ): + raise exceptions.ValidationError( + _( + "Bank account must contain a subscription number for" + " ISR ref type." + ) + ) + return True + + def partner_banks_to_show(self): + """ + Extend method from account_payment_partner to add specific + logic for switzerland bank payments if base method does not give + a result + """ + res = super().partner_banks_to_show() + if not res: + if self.journal_id: + return self.journal_id.bank_account_id + return res diff --git a/l10n_ch_base_bank/models/partner_bank.py b/l10n_ch_base_bank/models/partner_bank.py new file mode 100644 index 000000000..e623bc838 --- /dev/null +++ b/l10n_ch_base_bank/models/partner_bank.py @@ -0,0 +1,133 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, models + + +class ResPartnerBank(models.Model): + """Inherit res.partner.bank class in order to add swiss specific fields + and state controls + + Statements: + acc_type could be of 3 types: + - postal + - iban + - bank + + if account has postal number and acc_type = 'postal' we dropped acc_number + and compute it based on postal number, and partner + + if acc_number given in 'iban' format just transform to iban format, but no + further modification on it, and acc_type = 'iban' + + it means that postal number in account is a number directly identifying + the partner acc_number can contains the postal number + + if given bank account is 'bank' and l10n_ch_postal is set + if given bank type is a 'bank' then postal number in account should be + acc_number recomputed + acc_number in this case recomputed by as partner_name + l10n_ch_postal + + """ + + _inherit = "res.partner.bank" + + def is_isr_issuer(self): + """Supplier will provide ISR/QRR reference numbers in two cases: + + - postal account number starting by 01 or 03 + - QR-IBAN + """ + # acc_type can be bank for isrb + if self.acc_type in ["bank", "postal"] and self.l10n_ch_postal: + return self.l10n_ch_postal[:2] in ["01", "03"] + return self.acc_type == "iban" and self._is_qr_iban() + + def _get_ch_bank_from_iban(self): + """Extract clearing number from CH iban to find the bank""" + if self.acc_type != "iban" and self.acc_number[:2] != "CH": + return False + clearing = self.sanitized_acc_number[4:9].lstrip("0") + return clearing and self.env["res.bank"].search( + [("clearing", "=", clearing)], limit=1 + ) + + @api.onchange("acc_number", "acc_type") + def _onchange_acc_number_set_swiss_bank(self): + """Deduce information from IBAN + + Bank is defined as: + - Found bank by clearing when using iban + """ + bank = self.bank_id + if self.acc_type == "iban": + bank = self._get_ch_bank_from_iban() + self.bank_id = bank + + @api.onchange("l10n_ch_postal") + def _onchange_postal_set_acc_number(self): + """Set acc_number from postal field""" + if self.acc_type != "iban" and self.l10n_ch_postal: + self._update_acc_number() + + @api.onchange("partner_id") + def onchange_partner_set_acc_number(self): + # When acc_number was computed automatically we call regeneration + # as partner name is part of acc_number + # This is only required for ISR subscription numbers + if self.l10n_ch_postal and self.l10n_ch_postal[:2] in ["01", "03"]: + self._update_acc_number() + + def _update_acc_number(self): + """Compute value for field acc_number + based on an postal account or ISR subscription number""" + part_name = self.partner_id.name + if not part_name and self.env.context.get("default_partner_id"): + partner_id = self.env.context.get("default_partner_id") + part_name = self.env["res.partner"].browse(partner_id)[0].name + self.acc_number = self._compute_name_from_postal_number( + part_name, self.l10n_ch_postal + ) + + @api.model + def _compute_name_from_postal_number(self, partner_name, postal_number): + """This method makes sure to generate a unique name""" + if postal_number and postal_number[:2] in ["01", "03"]: + if partner_name: + acc_name = _( + "ISR %(pos_n)s %(pn)s", pos_n=postal_number, pn=partner_name + ) + else: + acc_name = _("ISR %(postal_number)s", postal_number=postal_number) + else: + return postal_number + + exist_count = self.env["res.partner.bank"].search_count( + [("acc_number", "=like", acc_name)] + ) + # if acc_number not unique iterate on bank_accounts while not get + # unique number + if exist_count: + name_exist = exist_count + while name_exist: + new_name = acc_name + " #{}".format(exist_count) + name_exist = self.env["res.partner.bank"].search_count( + [("acc_number", "=", new_name)] + ) + exist_count += 1 + acc_name = new_name + return acc_name + + @api.model + def create(self, vals): + """ + acc_number is mandatory for model, but in localization it could be not + mandatory when we have postal number, so we compute acc_number in + onchange methods and check it here also + """ + if not vals.get("acc_number") and vals.get("l10n_ch_postal"): + partner = self.env["res.partner"].browse(vals.get("partner_id")) + vals["acc_number"] = self._compute_name_from_postal_number( + partner.name, vals["l10n_ch_postal"] + ) + return super().create(vals) diff --git a/l10n_ch_base_bank/postfinance.py b/l10n_ch_base_bank/postfinance.py new file mode 100644 index 000000000..b507a833d --- /dev/null +++ b/l10n_ch_base_bank/postfinance.py @@ -0,0 +1,5 @@ +# Copyright 2020 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +CLEARING = "09000" +BIC = "POFICHBEXXX" diff --git a/l10n_ch_base_bank/readme/CONTRIBUTORS.rst b/l10n_ch_base_bank/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..8b60bf4f9 --- /dev/null +++ b/l10n_ch_base_bank/readme/CONTRIBUTORS.rst @@ -0,0 +1,10 @@ +* Nicolas Bessi (Camptocamp) +* Vincent Renaville +* Joël Grand-Guillaume +* Guewen Baconnier +* Paul Catinean +* Yannick Vaucher +* Akim Juillerat +* Iryna Vyshnevska +* Simone Vanin +* Alberto Nieto diff --git a/l10n_ch_base_bank/readme/CREDITS.rst b/l10n_ch_base_bank/readme/CREDITS.rst new file mode 100644 index 000000000..7f96bd934 --- /dev/null +++ b/l10n_ch_base_bank/readme/CREDITS.rst @@ -0,0 +1,6 @@ +The development of this module has been financially supported by: + +* Hasa SA +* Open Net SA +* Prisme Solutions Informatique SA +* Quod SA diff --git a/l10n_ch_base_bank/readme/DESCRIPTION.rst b/l10n_ch_base_bank/readme/DESCRIPTION.rst new file mode 100644 index 000000000..102759c91 --- /dev/null +++ b/l10n_ch_base_bank/readme/DESCRIPTION.rst @@ -0,0 +1,12 @@ +This addon extend the features of l10n_ch. + +Most of the former features have been moved in l10n_ch module. + + +Features: + +Improve UX with onchanges: + +- automatically set bank based on clearing part of IBAN +- allow direct entry of l10n_ch_postal which will fill acc_number +- search invoices by ISR, with or without spaces diff --git a/l10n_ch_base_bank/readme/USAGE.rst b/l10n_ch_base_bank/readme/USAGE.rst new file mode 100644 index 000000000..8b1c02072 --- /dev/null +++ b/l10n_ch_base_bank/readme/USAGE.rst @@ -0,0 +1,16 @@ +In partner bank account the type will be discovered automatically. + +* For IBAN accounts fill account number with IBAN. + * if the IBAN is an IBAN from PostFinance it will fill the Postal account number +* For Postal accounts: + * fill the account number with a postal account number 9 digits format (e.g. 10-8060-7). + * or fill the "Swiss postal account" with a postal account number 9 digits format (e.g. 10-8060-7). + +Entering a postal number of 9 digits will auto-complete the bank with PostFinance. (You might create it if you haven't installed `l10n_ch_bank`) + +* For ISR subscription numbers (postal account starting with 01 or 03): + * fill the account number with a postal account number 9 digits format (e.g. 01-23456-1). + * or fill the "Swiss postal account" with a postal account number 9 digits format (e.g. 01-23456-1). + +It will automatically change the content of account number by adding "ISR" and the partner name to avoid +duplicates with partner using the same ISR subscription number owned by a bank (ISR-B). diff --git a/l10n_ch_base_bank/static/description/icon.png b/l10n_ch_base_bank/static/description/icon.png new file mode 100644 index 000000000..5175c19c7 Binary files /dev/null and b/l10n_ch_base_bank/static/description/icon.png differ diff --git a/l10n_ch_base_bank/static/description/index.html b/l10n_ch_base_bank/static/description/index.html new file mode 100644 index 000000000..57297f21c --- /dev/null +++ b/l10n_ch_base_bank/static/description/index.html @@ -0,0 +1,468 @@ + + + + + + +Switzerland - Bank type + + + +
+

Switzerland - Bank type

+ + +

Beta License: AGPL-3 OCA/l10n-switzerland Translate me on Weblate Try me on Runboat

+

This addon extend the features of l10n_ch.

+

Most of the former features have been moved in l10n_ch module.

+

Features:

+

Improve UX with onchanges:

+
    +
  • automatically set bank based on clearing part of IBAN
  • +
  • allow direct entry of l10n_ch_postal which will fill acc_number
  • +
  • search invoices by ISR, with or without spaces
  • +
+

Table of contents

+ +
+

Usage

+

In partner bank account the type will be discovered automatically.

+
    +
  • For IBAN accounts fill account number with IBAN. +* if the IBAN is an IBAN from PostFinance it will fill the Postal account number
  • +
  • For Postal accounts: +* fill the account number with a postal account number 9 digits format (e.g. 10-8060-7). +* or fill the “Swiss postal account” with a postal account number 9 digits format (e.g. 10-8060-7).
  • +
+

Entering a postal number of 9 digits will auto-complete the bank with PostFinance. (You might create it if you haven’t installed l10n_ch_bank)

+
    +
  • For ISR subscription numbers (postal account starting with 01 or 03): +* fill the account number with a postal account number 9 digits format (e.g. 01-23456-1). +* or fill the “Swiss postal account” with a postal account number 9 digits format (e.g. 01-23456-1).
  • +
+

It will automatically change the content of account number by adding “ISR” and the partner name to avoid +duplicates with partner using the same ISR subscription number owned by a bank (ISR-B).

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The development of this module has been financially supported by:

+
    +
  • Hasa SA
  • +
  • Open Net SA
  • +
  • Prisme Solutions Informatique SA
  • +
  • Quod SA
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/l10n-switzerland project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_ch_base_bank/tests/__init__.py b/l10n_ch_base_bank/tests/__init__.py new file mode 100644 index 000000000..e3713b557 --- /dev/null +++ b/l10n_ch_base_bank/tests/__init__.py @@ -0,0 +1,4 @@ +from . import test_bank +from . import test_bank_type +from . import test_create_invoice +from . import test_search_invoice diff --git a/l10n_ch_base_bank/tests/test_bank.py b/l10n_ch_base_bank/tests/test_bank.py new file mode 100644 index 000000000..33dab61bd --- /dev/null +++ b/l10n_ch_base_bank/tests/test_bank.py @@ -0,0 +1,400 @@ +# Copyright 2014-2015 Nicolas Bessi (Azure Interior SA) +# Copyright 2015-2019 Yannick Vaucher (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import exceptions +from odoo.tests import tagged +from odoo.tests.common import Form, TransactionCase +from odoo.tools import mute_logger + +CH_SUBSCRIPTION = "01-162-8" # partner ISR subsr num we register under postal +CH_SUBSCRIPTION_9DIGITS = "010001628" # same ISR subsr num in 9 digits format +CH_POSTAL = "10-8060-7" +CH_IBAN = "CH15 3881 5158 3845 3843 7" +CH_POSTFINANCE_IBAN = "CH09 0900 0000 1000 8060 7" +FR_IBAN = "FR83 8723 4133 8709 9079 4002 530" + + +@tagged("post_install", "-at_install") +class TestBank(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.partner = cls.env.ref("base.res_partner_12") + cls.bank = cls.env["res.bank"].create( + { + "name": "Alternative Bank Schweiz AG", + "bic": "ALSWCH21XXX", + "clearing": "38815", + } + ) + cls.post_bank = cls.env["res.bank"].search([("bic", "=", "POFICHBEXXX")]) + if not cls.post_bank: + cls.post_bank = cls.env["res.bank"].create( + {"name": "PostFinance AG", "bic": "POFICHBEXXX", "clearing": "9000"} + ) + + def new_form(self): + form = Form( + self.env["res.partner.bank"], + view="l10n_ch.isr_partner_bank_form", + ) + form.partner_id = self.partner + return form + + def new_empty_form(self): + # in some cases we need form without partner + form = Form( + self.env["res.partner.bank"], + view="l10n_ch.isr_partner_bank_form", + ) + return form + + def test_bank_iban(self): + + bank_acc = self.new_form() + bank_acc.acc_number = CH_IBAN.replace(" ", "") + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.bank) + self.assertEqual(account.acc_number, CH_IBAN) + self.assertFalse(account.l10n_ch_postal) + self.assertEqual(account.acc_type, "iban") + + def test_bank_iban_with_spaces(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_IBAN + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.bank) + self.assertEqual(account.acc_number, CH_IBAN) + self.assertFalse(account.l10n_ch_postal) + self.assertEqual(account.acc_type, "iban") + + def test_bank_iban_lower_case(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_IBAN.lower() + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.bank) + self.assertEqual(account.acc_number, CH_IBAN.lower()) + self.assertFalse(account.l10n_ch_postal) + self.assertEqual(account.acc_type, "iban") + + def test_bank_iban_foreign(self): + bank_acc = self.new_form() + bank_acc.acc_number = FR_IBAN + account = bank_acc.save() + + self.assertFalse(account.bank_id) + self.assertEqual(account.acc_number, FR_IBAN) + self.assertFalse(account.l10n_ch_postal) + self.assertEqual(account.acc_type, "iban") + + def test_bank_postal(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_SUBSCRIPTION + bank_acc.bank_id = self.bank + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.bank) + self.assertEqual( + account.acc_number, + "ISR {} Azure Interior".format(CH_SUBSCRIPTION), + ) + self.assertEqual(account.l10n_ch_postal, CH_SUBSCRIPTION) + self.assertEqual(account.acc_type, "bank") + + def test_postal_set_bank_post(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTAL + account = bank_acc.save() + + self.assertFalse(account.bank_id) + # if acc_number given by user don't update it + self.assertEqual( + account.acc_number, + CH_POSTAL, + ) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "postal") + + bank_acc.bank_id = self.post_bank + bank_acc.save() + + self.assertEqual(account.bank_id, self.post_bank) + self.assertEqual(account.acc_number, CH_POSTAL) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "postal") + + def test_postal_with_bank(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTAL + bank_acc.bank_id = self.post_bank + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.post_bank) + self.assertEqual(account.acc_number, CH_POSTAL) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "postal") + + def test_postal_without_bank(self): + """It doesn't start with 01 or 03 + it is a postal account""" + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTAL + account = bank_acc.save() + + self.assertFalse(account.bank_id) + self.assertEqual(account.acc_number, CH_POSTAL) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "postal") + + def test_iban_postal(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTFINANCE_IBAN.replace(" ", "") + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.post_bank) + self.assertEqual(account.acc_number, CH_POSTFINANCE_IBAN) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "iban") + + def test_iban_postal_with_spaces(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTFINANCE_IBAN + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.post_bank) + self.assertEqual(account.acc_number, CH_POSTFINANCE_IBAN) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "iban") + + def test_iban_postal_lower_case(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_POSTFINANCE_IBAN.lower() + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.post_bank) + self.assertEqual(account.acc_number, CH_POSTFINANCE_IBAN.lower()) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.acc_type, "iban") + + def test_other_bank(self): + bank_acc = self.new_form() + # the sequence is important + bank_acc.bank_id = self.bank + bank_acc.acc_number = "R 12312123" + account = bank_acc.save() + + self.assertEqual(account.bank_id, self.bank) + self.assertEqual(account.acc_number, "R 12312123") + self.assertEqual(account.l10n_ch_postal, False) + self.assertEqual(account.acc_type, "bank") + + def test_set_postal_bank(self): + # we create bank account + # action runs in UI before creation + bank_acc = self.new_form() + # bank_acc.acc_number = None + bank_acc.l10n_ch_postal = CH_POSTAL + bank_acc.bank_id = self.bank + account = bank_acc.save() + + # in result we should get new ccp number as we have bank_id and + # this he has ccp, new acc_number + + self.assertEqual(account.acc_number, CH_POSTAL) + self.assertEqual(account.l10n_ch_postal, CH_POSTAL) + self.assertEqual(account.bank_id, self.bank) + + def test_constraint_postal(self): + with self.assertRaises(exceptions.ValidationError): + with mute_logger(): + self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "bank_id": self.bank.id, + "acc_number": "R 12312123", + "l10n_ch_postal": "520-54025-54054", + } + ) + + def test_constraint_subscription_number(self): + with self.assertRaises(exceptions.ValidationError): + with mute_logger(): + self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "acc_number": "12312123", + "l10n_ch_isr_subscription_chf": "Not a valid number", + } + ) + + self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "acc_number": "12312123", + "l10n_ch_isr_subscription_chf": CH_SUBSCRIPTION, + } + ) + + self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "acc_number": "12312124", + "l10n_ch_isr_subscription_chf": CH_SUBSCRIPTION_9DIGITS, + } + ) + + def test_create_bank_default_acc_number(self): + bank_acc = self.new_form() + bank_acc.bank_id = self.bank + bank_acc.l10n_ch_postal = CH_SUBSCRIPTION + account = bank_acc.save() + + # account number set based on ccp + self.assertEqual( + account.acc_number, + "ISR {} Azure Interior".format(CH_SUBSCRIPTION), + ) + self.assertEqual(account.l10n_ch_postal, CH_SUBSCRIPTION) + + def test_onchange_post_bank_acc_number(self): + """Check postal is copied to acc_number""" + bank_acc = self.new_empty_form() + bank_acc.bank_id = self.post_bank + bank_acc.l10n_ch_postal = CH_POSTAL + + # if it's postal, copy the value in acc_number + self.assertEqual(bank_acc.l10n_ch_postal, CH_POSTAL) + self.assertEqual(bank_acc.acc_number, CH_POSTAL) + + # if it's ISR subscription, copy ISR + value in acc_number + bank_acc.l10n_ch_postal = CH_SUBSCRIPTION + self.assertEqual( + bank_acc.acc_number, + "ISR {}".format(CH_SUBSCRIPTION), + ) + + # if it's ISR subscription, copy ISR + value in acc_number + # In this case we have the partner set + bank_acc.partner_id = self.partner + self.assertEqual( + bank_acc.acc_number, + "ISR {} Azure Interior".format(CH_SUBSCRIPTION), + ) + self.assertEqual(bank_acc.l10n_ch_postal, CH_SUBSCRIPTION) + + def test_onchange_post_bank_isr_in_acc_number(self): + """On entering ISR in acc_number + + Check acc_number is rewritten + and ISR subscription number is copied in l10n_ch_postal + + """ + bank_acc = self.new_form() + bank_acc.acc_number = CH_SUBSCRIPTION + bank_acc.bank_id = self.post_bank + + self.assertEqual(bank_acc.l10n_ch_postal, CH_SUBSCRIPTION) + self.assertEqual( + bank_acc.acc_number, + "ISR {} Azure Interior".format(CH_SUBSCRIPTION), + ) + + def test_name_search(self): + self.bank.bic = "BBAVBEBB" + result = self.env["res.bank"].name_search("BBAVBEBB") + self.assertEqual(result and result[0][0], self.bank.id) + self.bank.code = "CODE123" + result = self.env["res.bank"].name_search("CODE123") + self.assertEqual(result and result[0][0], self.bank.id) + self.bank.street = "Route de Neuchâtel" + result = self.env["res.bank"].name_search("Route de Neuchâtel") + self.assertEqual(result and result[0][0], self.bank.id) + self.bank.city = "Lausanne-Centre" + result = self.env["res.bank"].name_search("Lausanne-Centre") + self.assertEqual(result and result[0][0], self.bank.id) + + def test_multiple_postal_number_for_same_partner(self): + bank_acc = self.new_form() + bank_acc.acc_number = CH_SUBSCRIPTION + bank_acc.save() + bank_acc_2 = self.new_form() + bank_acc_2.acc_number = CH_SUBSCRIPTION + account2 = bank_acc_2.save() + + self.assertFalse(account2.bank_id) + self.assertEqual( + account2.acc_number, + "ISR {} Azure Interior #1".format(CH_SUBSCRIPTION), + ) + self.assertEqual(account2.acc_type, "bank") + + bank_acc_3 = self.new_form() + bank_acc_3.acc_number = CH_SUBSCRIPTION + account3 = bank_acc_3.save() + + # no bank matches + self.assertFalse(account3.bank_id) + self.assertEqual( + account3.acc_number, + "ISR {} Azure Interior #2".format(CH_SUBSCRIPTION), + ) + self.assertEqual(account3.acc_type, "bank") + account3.unlink() + # next acc_numbers properly generated + + # after deletion reuse same number + bank_acc_4 = self.new_form() + bank_acc_4.acc_number = CH_SUBSCRIPTION + account4 = bank_acc_4.save() + + self.assertEqual( + account4.acc_number, + "ISR {} Azure Interior #2".format(CH_SUBSCRIPTION), + ) + + def test_acc_name_generation(self): + # this test runs directly with object and onchange methods as Form + # class has constrains to flash required field as partner_id is + # once is set we can only replace on other partner but in view form + # we can make such actions + + # we test only proper name generation in different conditions + account = self.env["res.partner.bank"].new( + { + "acc_number": CH_SUBSCRIPTION, + "partner_id": False, + "l10n_ch_postal": False, + } + ) + # acc_number is ok in first + self.assertEqual(account.acc_number, CH_SUBSCRIPTION) + # but if some onchange trigger recompilation of name we flash any name + # only it's not iban type + account._update_acc_number() + self.assertFalse(account.acc_number) + # still no name + account.partner_id = self.partner + account._update_acc_number() + self.assertFalse(account.acc_number) + account.l10n_ch_postal = CH_SUBSCRIPTION + account._update_acc_number() + self.assertEqual( + account.acc_number, + "ISR {} Azure Interior".format(CH_SUBSCRIPTION), + ) + # remove partner name + account.partner_id = "" + account._update_acc_number() + self.assertEqual(account.acc_number, "ISR {}".format(CH_SUBSCRIPTION)) + # no changes for bank changes + account.bank_id = self.bank + account._update_acc_number() + self.assertEqual(account.acc_number, "ISR {}".format(CH_SUBSCRIPTION)) + # everything cleanup + account.l10n_ch_postal = "" + account._update_acc_number() + self.assertEqual(account.acc_number, "") diff --git a/l10n_ch_base_bank/tests/test_bank_type.py b/l10n_ch_base_bank/tests/test_bank_type.py new file mode 100644 index 000000000..03063bb4c --- /dev/null +++ b/l10n_ch_base_bank/tests/test_bank_type.py @@ -0,0 +1,43 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.tests import common + +CH_POSTAL = "10-8060-7" +CH_SUBSCRIPTION = "01-162-8" + + +class TestBankType(common.TransactionCase): + def test_is_bank_account_with_isr_issuer(self): + bank = self.env["res.bank"].create( + {"name": "BCV", "bic": "BCVLCH2LXXX", "clearing": "234234"} + ) + bank_account = self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "bank_id": bank.id, + "acc_number": "ISR 01-1234-1", + "l10n_ch_postal": CH_SUBSCRIPTION, + } + ) + self.assertEqual(bank_account.acc_type, "bank") + + def test_is_postal_account(self): + bank = self.env["res.bank"].create( + {"name": "BCV", "bic": "BCVLCH2LXXX", "clearing": "234234"} + ) + bank_account = self.env["res.partner.bank"].create( + { + "partner_id": self.partner.id, + "bank_id": bank.id, + "acc_number": CH_POSTAL, + "l10n_ch_postal": CH_POSTAL, + } + ) + self.assertEqual(bank_account.acc_type, "postal") + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref("base.main_company") + cls.partner = cls.env.ref("base.main_partner") diff --git a/l10n_ch_base_bank/tests/test_create_invoice.py b/l10n_ch_base_bank/tests/test_create_invoice.py new file mode 100644 index 000000000..7268fc5a3 --- /dev/null +++ b/l10n_ch_base_bank/tests/test_create_invoice.py @@ -0,0 +1,104 @@ +# Copyright 2012-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import exceptions +from odoo.tests.common import Form, TransactionCase + + +class TestCreateMove(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref("base.main_company") + cls.partner = cls.env.ref("base.res_partner_12") + bank = cls.env["res.bank"].create( + {"name": "BCV", "bic": "BBRUBEBB", "clearing": "234234"} + ) + cls.bank_account = cls.env["res.partner.bank"].create( + { + "partner_id": cls.company.partner_id.id, + "bank_id": bank.id, + "acc_number": "ISR", + "l10n_ch_isr_subscription_chf": "01-162-8", + "sequence": 1, + } + ) + cls.journal = cls.env["account.journal"].create( + { + "name": "Test Sale Journal", + "company_id": cls.company.id, + "type": "sale", + "code": "SALE123", + } + ) + + def new_form(self, with_bank_account=True): + if with_bank_account: + self.journal.bank_account_id = self.bank_account + inv = Form( + self.env["account.move"].with_context( + default_move_type="out_invoice", + default_journal_id=self.journal.id, + ) + ) + inv.partner_id = self.partner + return inv + + def test_emit_move_with_isr_ref(self): + inv_form = self.new_form() + move = inv_form.save() + self.assertFalse(move._has_isr_ref()) + + inv_form.ref = "132000000000000000000000014" + inv_form.save() + self.assertTrue(move._has_isr_ref()) + + def test_emit_move_with_isr_ref_15_pos(self): + inv_form = self.new_form() + move = inv_form.save() + + self.assertFalse(move._has_isr_ref()) + + move.ref = "132000000000004" + # We consider such ref to be unstructured + # and we shouldn't generate such refs + self.assertFalse(move._has_isr_ref()) + + # and save + inv_form.save() + + def test_emit_move_with_non_isr_ref(self): + inv_form = self.new_form() + move = inv_form.save() + + self.assertFalse(move._has_isr_ref()) + + move.ref = "Not a ISR ref with 27 chars" + self.assertFalse(move._has_isr_ref()) + + def test_emit_move_with_missing_isr_ref(self): + inv_form = self.new_form() + inv_form.save() + inv_form.ref = False + # and save + move = inv_form.save() + + self.assertFalse(move._has_isr_ref()) + + def test_emit_move_with_isr_ref_missing_subscr_num(self): + inv_form = self.new_form(with_bank_account=False) + move = inv_form.save() + self.assertFalse(move._has_isr_ref()) + inv_form.partner_bank_id = self.env["res.partner.bank"] + with self.assertRaises(exceptions.ValidationError): + inv_form.ref = "132000000000000000000000014" + inv_form.save() + + def test_emit_move_with_isr_ref_subscr_num_wrong_currency(self): + inv_form = self.new_form() + move = inv_form.save() + self.assertFalse(move._has_isr_ref()) + move.currency_id = self.env.ref("base.EUR") + with self.assertRaises(exceptions.ValidationError): + inv_form.ref = "132000000000000000000000014" + inv_form.save() diff --git a/l10n_ch_base_bank/tests/test_search_invoice.py b/l10n_ch_base_bank/tests/test_search_invoice.py new file mode 100644 index 000000000..63b0865a5 --- /dev/null +++ b/l10n_ch_base_bank/tests/test_search_invoice.py @@ -0,0 +1,117 @@ +# Copyright 2017 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.tests import common, tagged +from odoo.tests.common import Form + + +@tagged("post_install", "-at_install") +class TestSearchmove(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref("base.main_company") + cls.partner = cls.env.ref("base.res_partner_12") + bank = cls.env["res.bank"].create( + {"name": "BCV", "bic": "BBRUBEBB", "clearing": "234234"} + ) + cls.env["res.partner.bank"].create( + { + "partner_id": cls.company.partner_id.id, + "bank_id": bank.id, + "acc_number": "ISR", + "l10n_ch_isr_subscription_chf": "01-162-8", + "sequence": 1, + } + ) + cls.journal = cls.env["account.journal"].create( + { + "name": "Test Journal", + "company_id": cls.company.id, + "type": "sale", + "code": "SALE123", + "bank_id": bank.id, + "bank_acc_number": "10-8060-7", + } + ) + + def new_form(self): + inv = Form( + self.env["account.move"].with_context( + default_move_type="out_invoice", + default_journal_id=self.journal.id, + ), + ) + inv.partner_id = self.partner + return inv + + def assert_find_ref(self, ref, operator, value): + inv_form = self.new_form() + inv_form.ref = ref + + invoice = inv_form.save() + + found = self.env["account.move"].search([("ref", operator, value)]) + self.assertEqual(invoice, found) + + def assert_not_find_ref(self, ref, operator, value): + inv_form = self.new_form() + inv_form.ref = ref + inv_form.save() + + found = self.env["account.move"].search([("ref", operator, value)]) + self.assertFalse(found) + + def test_search_equal_strict(self): + self.assert_find_ref( + "27 29990 00000 00001 70400 25019", "=", "27 29990 00000 00001 70400 25019" + ) + + def test_search_equal_whitespace_right(self): + self.assert_not_find_ref( + "272999000000000017040025019", "=", "27 29990 00000 00001 70400 25019" + ) + + def test_search_equal_whitespace_left(self): + self.assert_not_find_ref( + "27 29990 00000 00001 70400 25019", "=", "272999000000000017040025019" + ) + + def test_search_like_whitespace_right(self): + self.assert_find_ref("272999000000000017040025019", "like", "1 70400 25") + + def test_search_like_whitespace_left(self): + self.assert_find_ref("27 29990 00000 00001 70400 25019", "like", "17040025") + + def test_search_like_whitespace_both(self): + self.assert_find_ref("27 29990 00000 00001 70400 25019", "like", "17 040025 01") + + def test_search_eqlike_whitespace_raw(self): + self.assert_not_find_ref( + "27 29990 00000 00001 70400 25019", "=like", "17 040025 01" + ) + + def test_search_eqlike_whitespace_wildcards(self): + self.assert_find_ref( + "27 29990 00000 00001 70400 25019", "=like", "%17 040025 01%" + ) + + def test_search_different(self): + self.assert_not_find_ref("27 29990 00000 00001 70400 25019", "like", "4273473") + + def test_search_other_field(self): + inv_form = self.new_form() + inv_form.ref = "27 29990 00000 00001 70400 25019" + move = inv_form.save() + + found = self.env["account.move"].search([("partner_id", "=", self.partner.id)]) + self.assertIn(move, found) + + def test_search_unary_operator(self): + inv_form = self.new_form() + inv_form.ref = "27 29990 00000 00001 70400 25019" + move = inv_form.save() + + found = self.env["account.move"].search([("ref", "like", "2999000000")]) + self.assertEqual(move, found) diff --git a/l10n_ch_base_bank/views/bank.xml b/l10n_ch_base_bank/views/bank.xml new file mode 100644 index 000000000..5b44bb181 --- /dev/null +++ b/l10n_ch_base_bank/views/bank.xml @@ -0,0 +1,59 @@ + + + + res.bank.search + res.bank + + + + + + + + + + + + + add custom fields on bank + res.bank + + + + + + + + + + + {'required': [('country_code', '=', 'CH')]} + + + {'required': [('country_code', '=', 'CH')]} + + + + + add custom fields on bank list + res.bank + + + + + + + + + + + diff --git a/setup/l10n_ch_base_bank/odoo/addons/l10n_ch_base_bank b/setup/l10n_ch_base_bank/odoo/addons/l10n_ch_base_bank new file mode 120000 index 000000000..8c57ba30b --- /dev/null +++ b/setup/l10n_ch_base_bank/odoo/addons/l10n_ch_base_bank @@ -0,0 +1 @@ +../../../../l10n_ch_base_bank \ No newline at end of file diff --git a/setup/l10n_ch_base_bank/setup.py b/setup/l10n_ch_base_bank/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/l10n_ch_base_bank/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)