diff --git a/account_statement_import_online_gocardless/README.rst b/account_statement_import_online_gocardless/README.rst new file mode 100644 index 00000000..15847fab --- /dev/null +++ b/account_statement_import_online_gocardless/README.rst @@ -0,0 +1,166 @@ +================================== +Online Bank Statements: GoCardless +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:86c3a6944d510b258d44f2a74e4e9e433cb0e4f9745ca156414b7a5c0d83efb1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fbank--statement--import-lightgray.png?logo=github + :target: https://github.com/OCA/bank-statement-import/tree/17.0/account_statement_import_online_gocardless + :alt: OCA/bank-statement-import +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/bank-statement-import-17-0/bank-statement-import-17-0-account_statement_import_online_gocardless + :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/bank-statement-import&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module provides online bank statements from GoCardless Bank Account +Data, which provides a free API for connecting and getting transactions +for bank accounts. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +On the GoCardless website +------------------------- + +1. Go to + `https://bankaccountdata.gocardless.com `__, + and create or login into your "GoCardLess Bank Account Data" account. +2. Go to Developers > User secrets option on the left. +3. Click on the "+ Create new" button on the bottom part. +4. Put a name to the user secret (eg. Odoo), and optionally limit it to + certain IPs using CIDR subnet notation. +5. Copy or download the secret ID and key for later use. The second one + won't be available anymore, so make sure you don't forget this step. + +On Odoo +------- + +To configure online bank statements provider: + +1. Add your user to the "Full Accounting Settings" group. + +2. Go to *Invoicing > Configuration > Accounting > Journals*. + +3. Select the journal representing your bank account (or create it). + +4. The bank account number should be properly introduced. + +5. Set *Bank Feeds* to *Online (OCA)*. + +6. Select *GoCardless* as online bank statements provider in *Online + Bank Statements (OCA)* section. + +7. Save the journal + +8. Click on the created provider. + +9. Put your secret ID and secret key on the existing fields. + +10. Click on the button "Select Bank Account Identifier". + + |image_01| + +11. A new window will appear for selecting the bank entity. + + |image_02| + +12. Select it, and you will be redirected to the selected entity for + introducing your bank credentials to allow the connection. + +13. If the process is completed, and the bank account linked to the + journal is accessible, you'll be again redirected to the online + provider form, and everything will be linked and ready to start the + transaction pulling. A message is logged about it on the chatter. + +14. If not, an error message will be logged either in the chatter. + +.. |image_01| image:: https://raw.githubusercontent.com/OCA/bank-statement-import/17.0/account_statement_import_online_gocardless/static/img/gocardless_configuration.gif +.. |image_02| image:: https://raw.githubusercontent.com/OCA/bank-statement-import/17.0/account_statement_import_online_gocardless/static/img/gocardless_bank_selection.gif + +Usage +===== + +To pull historical bank statements: + +1. Go to *Invoicing > Configuration > Accounting > Journals*. +2. Select the journal representing your bank account. +3. Launch *Actions > Online Bank Statements Pull Wizard* +4. Configure date interval and click on *Pull*. + +If historical data is not needed, then just simply wait for the +scheduled activity "Pull Online Bank Statements" to be executed for +getting new transactions. + +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 +------- + +* ForgeFlow +* Tecnativa + +Contributors +------------ + +- `ForgeFlow `__: + + - Christopher Ormaza + - Jordi Ballester + +- `Tecnativa `__: + + - Pedro M. Baeza + +- `Alusage `__: + + - Nicolas JEUDY + <`https://github.com/njeudy `__> + +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/bank-statement-import `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_statement_import_online_gocardless/__init__.py b/account_statement_import_online_gocardless/__init__.py new file mode 100644 index 00000000..2c33cb2a --- /dev/null +++ b/account_statement_import_online_gocardless/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import controllers +from . import models +from . import wizards diff --git a/account_statement_import_online_gocardless/__manifest__.py b/account_statement_import_online_gocardless/__manifest__.py new file mode 100644 index 00000000..145d04b8 --- /dev/null +++ b/account_statement_import_online_gocardless/__manifest__.py @@ -0,0 +1,30 @@ +# Copyright 2022 ForgeFlow S.L. +# Copyright 2023-2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Online Bank Statements: GoCardless", + "version": "17.0.1.0.0", + "category": "Account", + "website": "https://github.com/OCA/bank-statement-import", + "author": "ForgeFlow, Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": [ + "account_statement_import_online", + ], + "data": [ + "security/ir.model.access.csv", + "view/online_bank_statement_provider.xml", + "wizards/online_bank_statement_provider_existing_views.xml", + ], + "assets": { + "web.assets_backend": [ + "account_statement_import_online_gocardless/static/src/" + "lib/gocardless-ui/selector.css", + "account_statement_import_online_gocardless/static/src/" + "js/select_bank_widget.esm.js", + "account_statement_import_online_gocardless/static/src/" + "xml/select_bank_widget.xml", + ], + }, +} diff --git a/account_statement_import_online_gocardless/controllers/__init__.py b/account_statement_import_online_gocardless/controllers/__init__.py new file mode 100644 index 00000000..12a7e529 --- /dev/null +++ b/account_statement_import_online_gocardless/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/account_statement_import_online_gocardless/controllers/main.py b/account_statement_import_online_gocardless/controllers/main.py new file mode 100644 index 00000000..83335796 --- /dev/null +++ b/account_statement_import_online_gocardless/controllers/main.py @@ -0,0 +1,35 @@ +# Copyright 2022 ForgeFlow S.L. +# Copyright 2023 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import werkzeug +from werkzeug.urls import url_encode + +from odoo import http +from odoo.http import request + + +class GocardlessController(http.Controller): + @http.route("/gocardless/response", type="http", auth="public", csrf=False) + def gocardless_response(self, **post): + Provider = request.env["online.bank.statement.provider"].sudo() + current_provider = Provider.search( + [("gocardless_requisition_ref", "=", post["ref"])] + ) + params = { + "action": request.env.ref( + "account_statement_import_online.online_bank_statement_provider_action" + ).id, + "model": "online.bank.statement.provider", + } + if current_provider: + current_provider._gocardless_finish_requisition() + params.update( + { + "view_type": "form", + "id": current_provider.id, + } + ) + else: + params["view_type"] = "list" + return werkzeug.utils.redirect("/web#" + url_encode(params), 303) diff --git a/account_statement_import_online_gocardless/i18n/account_statement_import_online_gocardless.pot b/account_statement_import_online_gocardless/i18n/account_statement_import_online_gocardless.pot new file mode 100644 index 00000000..a26ffa9d --- /dev/null +++ b/account_statement_import_online_gocardless/i18n/account_statement_import_online_gocardless.pot @@ -0,0 +1,233 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_statement_import_online_gocardless +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.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: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +" There's already another journal from the " +"same bank institution linked with GoCardless. Do you want to reuse the " +"existing credentials or create new ones?" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Available countries:" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_uid +msgid "Created by" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_date +msgid "Created on" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__display_name +msgid "Display Name" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Existing link" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "GoCardless" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_account_id +msgid "Gocardless Account" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_institution_id +msgid "Gocardless Institution" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_expiration +msgid "Gocardless Refresh Expiration" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_token +msgid "Gocardless Refresh Token" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_id +msgid "Gocardless Requisition" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_expiration +msgid "Gocardless Requisition Expiration" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_ref +msgid "Gocardless Requisition Ref" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token +msgid "Gocardless Token" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token_expiration +msgid "Gocardless Token Expiration" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__id +msgid "ID" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Incorrect country code or country not supported." +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing____last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_date +msgid "Last Updated on" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "New link" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider +msgid "Online Bank Statement Provider" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__other_provider_id +msgid "Other Provider" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__provider_id +msgid "Provider" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "Reuse existing" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret ID" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret Key" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Select Bank Account Identifier" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Select Bank of your Account" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Select Country to Filter" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +"Some banks only allow one credentials, while others work better with " +"separate ones, so it's a matter of trying." +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "To continue configure bank account on journal %s" +msgstr "" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider_existing +msgid "Wizard for reusing existing GoCardless provider" +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"You should renew the authorization process with your bank institution for " +"GoCardless." +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Your account number %(iban_number)s is successfully attached." +msgstr "" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"Your account number %(iban_number)s it's not in the IBAN account numbers " +"found %(accounts_iban)s, please check" +msgstr "" diff --git a/account_statement_import_online_gocardless/i18n/es.po b/account_statement_import_online_gocardless/i18n/es.po new file mode 100644 index 00000000..5379d5b8 --- /dev/null +++ b/account_statement_import_online_gocardless/i18n/es.po @@ -0,0 +1,246 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_statement_import_online_gocardless +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-22 18:19+0000\n" +"PO-Revision-Date: \n" +"Last-Translator: MayteGLC \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0.1\n" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +" There's already another journal from the " +"same bank institution linked with GoCardless. Do you want to reuse the " +"existing credentials or create new ones?" +msgstr "" +" Ya existe otro diario de la misma " +"institución bancaria enlazado con GoCardless. ¿Quiere reutilizar las " +"credenciales existentes o crear unas nuevas?" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Available countries:" +msgstr "Países disponibles:" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Existing link" +msgstr "Enlace existente" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "GoCardless" +msgstr "GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_account_id +msgid "Gocardless Account" +msgstr "ID de la cuenta Gocardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_institution_id +msgid "Gocardless Institution" +msgstr "Banco conectado" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_expiration +msgid "Gocardless Refresh Expiration" +msgstr "Actualizar fecha de caducidad" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_token +msgid "Gocardless Refresh Token" +msgstr "Actualizar Token" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_id +msgid "Gocardless Requisition" +msgstr "ID de la conexión Gocardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_expiration +msgid "Gocardless Requisition Expiration" +msgstr "Caducidad de la sincronización" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_ref +msgid "Gocardless Requisition Ref" +msgstr "Gocardless Requisición Ref" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token +msgid "Gocardless Token" +msgstr "Token" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token_expiration +msgid "Gocardless Token Expiration" +msgstr "Caducdad del token" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__id +msgid "ID" +msgstr "Identificador" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Incorrect country code or country not supported." +msgstr "Código de país incorrecto o país no admitido." + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_uid +msgid "Last Updated by" +msgstr "Última modificación por" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_date +msgid "Last Updated on" +msgstr "Última modificación el" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "New link" +msgstr "Nuevo enlace" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider +msgid "Online Bank Statement Provider" +msgstr "Proveedor de Extractos Bancarios en Línea" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__other_provider_id +msgid "Other Provider" +msgstr "Otro proveedor" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__provider_id +msgid "Provider" +msgstr "Proveedor" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "Reuse existing" +msgstr "Reutilizar existente" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Search..." +msgstr "Búsqueda..." + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret ID" +msgstr "ID Secreto" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret Key" +msgstr "Clave secreta" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Select Bank Account Identifier" +msgstr "Validar identificador de banco" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Select Bank of your Account" +msgstr "Seleccione el Banco de su Cuenta" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Select Country to Filter" +msgstr "Seleccione el País a Filtrar" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +"Some banks only allow one credentials, while others work better with " +"separate ones, so it's a matter of trying." +msgstr "" +"Algunos bancos solo permiten unas credenciales, mientras otros funcionan " +"mejor con credenciales separadas, así que es una cuestión de probar ambas " +"opciones." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "To continue configure bank account on journal %s" +msgstr "Para seguir configurando la cuenta bancaria en el diario %s" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider_existing +msgid "Wizard for reusing existing GoCardless provider" +msgstr "Asistente para reutilizar un proveedor de GoCardless existente" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"You should renew the authorization process with your bank institution for " +"GoCardless." +msgstr "" +"Debe renovar el proceso de autorización con su entidad bancaria para " +"GoCardless." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Your account number %(iban_number)s is successfully attached." +msgstr "Su número de cuenta %(iban_number)s se ha adjuntado correctamente." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"Your account number %(iban_number)s it's not in the IBAN account numbers " +"found %(accounts_iban)s, please check" +msgstr "" +"Su número de cuenta %(iban_number)s no está en los números de cuenta IBAN " +"encontrados %(accounts_iban)s, por favor compruébelo" diff --git a/account_statement_import_online_gocardless/i18n/it.po b/account_statement_import_online_gocardless/i18n/it.po new file mode 100644 index 00000000..af95d537 --- /dev/null +++ b/account_statement_import_online_gocardless/i18n/it.po @@ -0,0 +1,245 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_statement_import_online_gocardless +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-11-28 23:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\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 5.6.2\n" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +" There's already another journal from the " +"same bank institution linked with GoCardless. Do you want to reuse the " +"existing credentials or create new ones?" +msgstr "" +" Esiste già un altro registro dello stesso " +"istituto bancario collegato a GoCardless. Si vuole riutilizzare le " +"credenziali esistenti o crearne di nuove?" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Available countries:" +msgstr "Nazioni disponibili:" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Existing link" +msgstr "Link esistente" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "GoCardless" +msgstr "GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_account_id +msgid "Gocardless Account" +msgstr "Conto GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_institution_id +msgid "Gocardless Institution" +msgstr "Istituto GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_expiration +msgid "Gocardless Refresh Expiration" +msgstr "Scadenza aggiornamento GoCadrless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_refresh_token +msgid "Gocardless Refresh Token" +msgstr "Token rinnovo GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_id +msgid "Gocardless Requisition" +msgstr "Richiesta GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_expiration +msgid "Gocardless Requisition Expiration" +msgstr "Scadenza richiesta GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_requisition_ref +msgid "Gocardless Requisition Ref" +msgstr "Rif. richiesta GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token +msgid "Gocardless Token" +msgstr "Token GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider__gocardless_token_expiration +msgid "Gocardless Token Expiration" +msgstr "Scadenza token GoCardless" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__id +msgid "ID" +msgstr "ID" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Incorrect country code or country not supported." +msgstr "Codice nazione errato o nazione non supportata." + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "New link" +msgstr "Nuovo link" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider +msgid "Online Bank Statement Provider" +msgstr "Fornitore estratto conto bancario online" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__other_provider_id +msgid "Other Provider" +msgstr "Altro fornitore" + +#. module: account_statement_import_online_gocardless +#: model:ir.model.fields,field_description:account_statement_import_online_gocardless.field_online_bank_statement_provider_existing__provider_id +msgid "Provider" +msgstr "Fornitore" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "Reuse existing" +msgstr "Riusare esistente" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Search..." +msgstr "Cerca..." + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret ID" +msgstr "ID segreto" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Secret Key" +msgstr "Chiave segreta" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.online_bank_statement_provider_form +msgid "Select Bank Account Identifier" +msgstr "Seleziona identificatore conto bancario" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Select Bank of your Account" +msgstr "Selezionare la banca del proprio conto" + +#. module: account_statement_import_online_gocardless +#. odoo-javascript +#: code:addons/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml:0 +#, python-format +msgid "Select Country to Filter" +msgstr "Selezionare la nazione da filtrare" + +#. module: account_statement_import_online_gocardless +#: model_terms:ir.ui.view,arch_db:account_statement_import_online_gocardless.view_online_bank_statement_provider_existing_form +msgid "" +"Some banks only allow one credentials, while others work better with " +"separate ones, so it's a matter of trying." +msgstr "" +"Alcune banche consentono solo una credenziale, mentre altre funzionano " +"meglio con credenziali separate, quindi è solo questione di tentativi." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "To continue configure bank account on journal %s" +msgstr "Per procedere configurare conto bancario nel registro %s" + +#. module: account_statement_import_online_gocardless +#: model:ir.model,name:account_statement_import_online_gocardless.model_online_bank_statement_provider_existing +msgid "Wizard for reusing existing GoCardless provider" +msgstr "Procedura guidata per riutilizzare il fornitore GoCardless esistente" + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"You should renew the authorization process with your bank institution for " +"GoCardless." +msgstr "" +"Bisogna rinnovare il processo di autorizzazione per GoCardless con il " +"proprio istituto bancario." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "Your account number %(iban_number)s is successfully attached." +msgstr "Il numero di conto %(iban_number)s è allegato correttamente." + +#. module: account_statement_import_online_gocardless +#. odoo-python +#: code:addons/account_statement_import_online_gocardless/models/online_bank_statement_provider.py:0 +#, python-format +msgid "" +"Your account number %(iban_number)s it's not in the IBAN account numbers " +"found %(accounts_iban)s, please check" +msgstr "" +"Il numero di conto %(iban_number)s non è nel conto IBAN %(accounts_iban)s " +"trovato , controllare" diff --git a/account_statement_import_online_gocardless/models/__init__.py b/account_statement_import_online_gocardless/models/__init__.py new file mode 100644 index 00000000..03e38c99 --- /dev/null +++ b/account_statement_import_online_gocardless/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import online_bank_statement_provider diff --git a/account_statement_import_online_gocardless/models/online_bank_statement_provider.py b/account_statement_import_online_gocardless/models/online_bank_statement_provider.py new file mode 100644 index 00000000..ee5f6605 --- /dev/null +++ b/account_statement_import_online_gocardless/models/online_bank_statement_provider.py @@ -0,0 +1,423 @@ +# Copyright 2022 ForgeFlow S.L. +# Copyright 2023-2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import json +from datetime import datetime +from uuid import uuid4 + +import requests +from dateutil.relativedelta import relativedelta +from werkzeug.urls import url_join + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF + +GOCARDLESS_API = "https://bankaccountdata.gocardless.com/api/v2/" +REQUESTS_TIMEOUT = 60 + + +class OnlineBankStatementProvider(models.Model): + _inherit = "online.bank.statement.provider" + + gocardless_token = fields.Char(readonly=True) + gocardless_token_expiration = fields.Datetime(readonly=True) + gocardless_refresh_token = fields.Char(readonly=True) + gocardless_refresh_expiration = fields.Datetime(readonly=True) + gocardless_requisition_ref = fields.Char(readonly=True) + gocardless_requisition_id = fields.Char(readonly=True) + gocardless_requisition_expiration = fields.Datetime(readonly=True) + gocardless_institution_id = fields.Char() + gocardless_account_id = fields.Char() + gocardless_country_id = fields.Many2one( + "res.country", + compute="_compute_gocardless_country_id", + store=True, + readonly=False, + ) + + @api.depends("journal_id", "company_id") + def _compute_gocardless_country_id(self): + for provider in self: + provider.gocardless_country_id = ( + provider.journal_id.bank_account_id.company_id + or provider.journal_id.company_id + ).country_id + + def gocardless_reset_requisition(self): + self.write( + { + "gocardless_requisition_id": False, + "gocardless_requisition_ref": False, + "gocardless_requisition_expiration": False, + } + ) + + @api.model + def _get_available_services(self): + """Include the new service GoCardless in the online providers.""" + return super()._get_available_services() + [ + ("gocardless", "GoCardless"), + ] + + def _gocardless_get_headers(self, basic=False): + """Generic method for providing the needed request headers.""" + self.ensure_one() + headers = { + "accept": "application/json", + "Content-Type": "application/json", + } + if not basic: + headers["Authorization"] = f"Bearer {self._gocardless_get_token()}" + return headers + + def _gocardless_request( + self, endpoint, request_type="get", params=None, data=None, basic_auth=False + ): + content = {} + url = url_join(GOCARDLESS_API, endpoint) + "/" + response = getattr(requests, request_type)( + url, + data=data, + params=params, + headers=self._gocardless_get_headers(basic=basic_auth), + timeout=REQUESTS_TIMEOUT, + ) + if response.status_code in [200, 201]: + content = json.loads(response.text) + return response, content + + def _gocardless_get_token(self): + """Resolve and return the corresponding GoCardless token for doing the requests. + If there's still no token, it's requested. If it exists, but it's expired and + the refresh token isn't, a refresh is requested. + """ + self.ensure_one() + now = fields.Datetime.now() + if not self.gocardless_token or now > self.gocardless_token_expiration: + # Refresh token + if ( + self.gocardless_refresh_token + and now > self.gocardless_refresh_expiration + ): + endpoint = "token/refresh" + else: + endpoint = "token/new" + _response, data = self._gocardless_request( + endpoint, + request_type="post", + data=json.dumps( + {"secret_id": self.username, "secret_key": self.password} + ), + basic_auth=True, + ) + expiration_date = now + relativedelta(seconds=data.get("access_expires", 0)) + vals = { + "gocardless_token": data.get("access", False), + "gocardless_token_expiration": expiration_date, + } + if data.get("refresh"): + vals["gocardless_refresh_token"] = data["refresh"] + vals["gocardless_refresh_expiration"] = now + relativedelta( + seconds=data["refresh_expires"] + ) + self.sudo().write(vals) + return self.gocardless_token + + def action_select_gocardless_bank(self): + if not self.journal_id.bank_account_id: + raise UserError( + _("To continue configure bank account on journal %s") + % (self.journal_id.display_name) + ) + # Check if there's another existing provider for the same bank institution, + # and ask for reusing it for this bank account, as some banks don't allow + # several requisitions from the same source (GoCardless). + other = self.search( + [ + ("service", "=", "gocardless"), + ("gocardless_requisition_id", "!=", False), + ("journal_id.bank_id", "=", self.journal_id.bank_id.id), + ("id", "!=", self.id), + ], + limit=1, + ) + if other: + wizard = self.env["online.bank.statement.provider.existing"].create( + { + "provider_id": self.id, + "other_provider_id": other.id, + } + ) + return { + "type": "ir.actions.act_window", + "res_model": wizard._name, + "res_id": wizard.id, + "name": _("Existing link"), + "view_mode": "form", + "target": "new", + } + return self._gocardless_select_bank_institution() + + def _gocardless_select_bank_institution(self): + """Ask for the GoCardless bank instituion and continue full linkage.""" + country = self.gocardless_country_id + response, data = self._gocardless_request( + "institutions", params={"country": country.code} + ) + if response.status_code == 400: + raise UserError(_("Incorrect country code or country not supported.")) + institutions = data + # Prepare data for being showed in the JS widget + ctx = self.env.context.copy() + ctx.update( + { + "dialog_size": "medium", + "country": country.code, + "country_name": country.name, + "provider_id": self.id, + "institutions": institutions, + "country_names": [{"code": country.code, "name": country.name}], + } + ) + return { + "type": "ir.actions.client", + "tag": "online_sync_institution_selector_gocardless", + "name": _("Select Bank of your Account"), + "params": {}, + "target": "new", + "context": ctx, + } + + def action_check_gocardless_agreement(self): + self.ensure_one() + self.gocardless_requisition_ref = str(uuid4()) + base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url") + redirect_url = url_join(base_url, "gocardless/response") + _response, data = self._gocardless_request( + "requisitions", + request_type="post", + data=json.dumps( + { + "redirect": redirect_url, + "institution_id": self.gocardless_institution_id, + "reference": self.gocardless_requisition_ref, + } + ), + ) + if data: + requisition_data = data + self.gocardless_requisition_id = requisition_data["id"] + # JS code expects here to return a plain link or nothing + return requisition_data["link"] + + def _gocardless_request_requisition(self): + _response, data = self._gocardless_request( + f"requisitions/{self.gocardless_requisition_id}" + ) + return data + + def _gocardless_request_account(self, account_id): + _response, data = self._gocardless_request(f"accounts/{account_id}") + return data + + def _gocardless_request_agreement(self, agreement_id): + _response, data = self._gocardless_request(f"agreements/enduser/{agreement_id}") + return data + + def _gocardless_finish_requisition(self, dry=False): + """Once the requisiton to the bank institution has been made, and this is called + from the controller assigned to the redirect URL, we check that the IBAN account + of the linked journal is included in the accessible bank accounts, and if so, + we set the rest of the needed data. + + A message in the chatter is logged both for sucessful or failed operation (this + last one only if not in dry mode). + + :param: dry: If true, this is called as previous step before starting the whole + process, so no fail message is logged in chatter in this case. + """ + self.ensure_one() + requisition_data = self._gocardless_request_requisition() + accounts = requisition_data.get("accounts", []) + found_account = False + accounts_iban = [] + for account_id in accounts: + account_data = self._gocardless_request_account(account_id) + if account_data: + accounts_iban.append(account_data["iban"]) + if ( + self.journal_id.bank_account_id.sanitized_acc_number + == account_data["iban"].upper() + ): + found_account = True + self.gocardless_account_id = account_data["id"] + break + if found_account: + agreement_data = self._gocardless_request_agreement( + requisition_data["agreement"] + ) + self.gocardless_requisition_expiration = datetime.strptime( + agreement_data["accepted"], "%Y-%m-%dT%H:%M:%S.%fZ" + ) + relativedelta(days=agreement_data["access_valid_for_days"]) + self.sudo().message_post( + body=_("Your account number %(iban_number)s is successfully attached.") + % {"iban_number": self.journal_id.bank_account_id.display_name} + ) + return True + elif not dry: + self.sudo().write( + { + "gocardless_requisition_expiration": False, + "gocardless_requisition_id": False, + "gocardless_requisition_ref": False, + } + ) + self.sudo().message_post( + body=_( + "Your account number %(iban_number)s it's not in the IBAN " + "account numbers found %(accounts_iban)s, please check" + ) + % { + "iban_number": self.journal_id.bank_account_id.display_name, + "accounts_iban": " / ".join(accounts_iban), + } + ) + return False + + def _obtain_statement_data(self, date_since, date_until): + """Generic online cron overrided for acting when the sync is for GoCardless.""" + self.ensure_one() + if self.service == "gocardless": + return self._gocardless_obtain_statement_data(date_since, date_until) + return super()._obtain_statement_data(date_since, date_until) + + def _gocardless_request_transactions(self, date_since, date_until): + """Method for requesting GoCardless transactions. + Isolated for being mocked in tests. + """ + # We can't query dates in the future in GoCardless + now = fields.Datetime.now() + if now > date_since and now < date_until: + date_until = now + _response, data = self._gocardless_request( + f"accounts/{self.gocardless_account_id}/transactions", + params={ + "date_from": date_since.strftime(DF), + "date_to": date_until.strftime(DF), + }, + ) + return data + + def _gocardless_obtain_statement_data(self, date_since, date_until): + """Called from the cron or the manual pull wizard to obtain transactions for + the given period. + """ + self.ensure_one() + if not self.gocardless_account_id: + return + currency_model = self.env["res.currency"] + if self.gocardless_requisition_expiration <= fields.Datetime.now(): + self.sudo().message_post( + body=_( + "You should renew the authorization process with your bank " + "institution for GoCardless." + ) + ) + return [], {} + own_acc_number = self.journal_id.bank_account_id.sanitized_acc_number + transactions = self._gocardless_request_transactions(date_since, date_until) + res = [] + sequence = 0 + currencies_cache = {} + for tr in transactions.get("transactions", {}).get("booked", []): + # Reference: https://developer.gocardless.com/bank-account-data/transactions + string_date = tr.get("bookingDate") or tr.get("valueDate") + # CHECK ME: if there's not date string, is transaction still valid? + if not string_date: + continue + current_date = fields.Date.from_string(string_date) + sequence += 1 + amount = float(tr.get("transactionAmount", {}).get("amount", 0.0)) + currency_code = tr.get("transactionAmount", {}).get( + "currency", self.journal_id.currency_id.name + ) + currency = currencies_cache.get(currency_code) + if not currency: + currency = currency_model.search([("name", "=", currency_code)]) + currencies_cache[currency_code] = currency + amount_currency = amount + if ( + currency + and self.journal_id.currency_id + and currency != self.journal_id.currency_id + ): + amount_currency = currency._convert( + amount, + self.journal_id.currency_id, + self.journal_id.company_id, + current_date, + ) + if amount_currency >= 0: + partner_name = tr.get("debtorName", False) + else: + partner_name = tr.get("creditorName", False) + account_number = tr.get("debtorAccount", {}).get("iban") or tr.get( + "creditorAccount", {} + ).get("iban", False) + if account_number == own_acc_number: + account_number = False # Discard own bank account number + if "remittanceInformationUnstructured" in tr: + payment_ref = tr["remittanceInformationUnstructured"] + elif "remittanceInformationUnstructuredArray" in tr: + payment_ref = " ".join(tr["remittanceInformationUnstructuredArray"]) + else: + payment_ref = partner_name + res.append( + { + "sequence": sequence, + "date": current_date, + "ref": partner_name or "/", + "payment_ref": payment_ref, + "unique_import_id": ( + tr.get("entryReference") + or tr.get("transactionId") + or tr.get("internalTransactionId") + ), + "amount": amount_currency, + "account_number": account_number, + "partner_name": partner_name, + "transaction_type": tr.get("bankTransactionCode", ""), + "narration": self._gocardless_get_note(tr), + } + ) + return res, {} + + def _gocardless_get_note(self, tr): + """Override to get different notes.""" + note_elements = [ + "additionalInformation", + "balanceAfterTransaction", + "bankTransactionCode", + "bookingDate", + "checkId", + "creditorAccount", + "creditorAgent", + "creditorId", + "creditorName", + "currencyExchange", + "debtorAccount", + "debtorAgent", + "debtorName", + "entryReference", + "mandateId", + "proprietaryBank", + "remittanceInformation Unstructured", + "transactionAmount", + "transactionId", + "ultimateCreditor", + "ultimateDebtor", + "valueDate", + ] + notes = [str(tr[element]) for element in note_elements if tr.get(element)] + return "\n".join(notes) diff --git a/account_statement_import_online_gocardless/pyproject.toml b/account_statement_import_online_gocardless/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/account_statement_import_online_gocardless/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_statement_import_online_gocardless/readme/CONFIGURE.md b/account_statement_import_online_gocardless/readme/CONFIGURE.md new file mode 100644 index 00000000..32e37549 --- /dev/null +++ b/account_statement_import_online_gocardless/readme/CONFIGURE.md @@ -0,0 +1,51 @@ +## On the GoCardless website + +1. Go to , and create or login + into your "GoCardLess Bank Account Data" account. +2. Go to Developers \> User secrets option on the left. +3. Click on the "+ Create new" button on the bottom part. +4. Put a name to the user secret (eg. Odoo), and optionally limit it to + certain IPs using CIDR subnet notation. +5. Copy or download the secret ID and key for later use. The second one + won't be available anymore, so make sure you don't forget this step. + +## On Odoo + +To configure online bank statements provider: + +1. Add your user to the "Full Accounting Settings" group. + +2. Go to *Invoicing \> Configuration \> Accounting \> Journals*. + +3. Select the journal representing your bank account (or create it). + +4. The bank account number should be properly introduced. + +5. Set *Bank Feeds* to *Online (OCA)*. + +6. Select *GoCardless* as online bank statements provider in *Online + Bank Statements (OCA)* section. + +7. Save the journal + +8. Click on the created provider. + +9. Put your secret ID and secret key on the existing fields. + +10. Click on the button "Select Bank Account Identifier". + + ![image_01](../static/img/gocardless_configuration.gif) + +11. A new window will appear for selecting the bank entity. + + ![image_02](../static/img/gocardless_bank_selection.gif) + +12. Select it, and you will be redirected to the selected entity for + introducing your bank credentials to allow the connection. + +13. If the process is completed, and the bank account linked to the + journal is accessible, you'll be again redirected to the online + provider form, and everything will be linked and ready to start the + transaction pulling. A message is logged about it on the chatter. + +14. If not, an error message will be logged either in the chatter. diff --git a/account_statement_import_online_gocardless/readme/CONTRIBUTORS.md b/account_statement_import_online_gocardless/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..5d233fd8 --- /dev/null +++ b/account_statement_import_online_gocardless/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ + - [ForgeFlow](https://www.forgeflow.com): + - Christopher Ormaza + - Jordi Ballester + - [Tecnativa](https://www.tecnativa.com): + - Pedro M. Baeza + - [Alusage](https://nicolas.alusage.fr): + - Nicolas JEUDY \<\> diff --git a/account_statement_import_online_gocardless/readme/DESCRIPTION.md b/account_statement_import_online_gocardless/readme/DESCRIPTION.md new file mode 100644 index 00000000..d170cdb3 --- /dev/null +++ b/account_statement_import_online_gocardless/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module provides online bank statements from GoCardless Bank Account +Data, which provides a free API for connecting and getting transactions +for bank accounts. diff --git a/account_statement_import_online_gocardless/readme/USAGE.md b/account_statement_import_online_gocardless/readme/USAGE.md new file mode 100644 index 00000000..97f15506 --- /dev/null +++ b/account_statement_import_online_gocardless/readme/USAGE.md @@ -0,0 +1,10 @@ +To pull historical bank statements: + +1. Go to *Invoicing \> Configuration \> Accounting \> Journals*. +2. Select the journal representing your bank account. +3. Launch *Actions \> Online Bank Statements Pull Wizard* +4. Configure date interval and click on *Pull*. + +If historical data is not needed, then just simply wait for the +scheduled activity "Pull Online Bank Statements" to be executed for +getting new transactions. diff --git a/account_statement_import_online_gocardless/security/ir.model.access.csv b/account_statement_import_online_gocardless/security/ir.model.access.csv new file mode 100644 index 00000000..794573f3 --- /dev/null +++ b/account_statement_import_online_gocardless/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_online_bank_statement_provider_existing,access_online_bank_statement_provider_existing,model_online_bank_statement_provider_existing,account.group_account_user,1,1,1,0 diff --git a/account_statement_import_online_gocardless/static/description/icon.png b/account_statement_import_online_gocardless/static/description/icon.png new file mode 100644 index 00000000..2efb75c0 Binary files /dev/null and b/account_statement_import_online_gocardless/static/description/icon.png differ diff --git a/account_statement_import_online_gocardless/static/description/index.html b/account_statement_import_online_gocardless/static/description/index.html new file mode 100644 index 00000000..f0d73481 --- /dev/null +++ b/account_statement_import_online_gocardless/static/description/index.html @@ -0,0 +1,516 @@ + + + + + +Online Bank Statements: GoCardless + + + +
+

Online Bank Statements: GoCardless

+ + +

Beta License: AGPL-3 OCA/bank-statement-import Translate me on Weblate Try me on Runboat

+

This module provides online bank statements from GoCardless Bank Account +Data, which provides a free API for connecting and getting transactions +for bank accounts.

+

Table of contents

+ +
+

Configuration

+
+

On the GoCardless website

+
    +
  1. Go to +https://bankaccountdata.gocardless.com, +and create or login into your “GoCardLess Bank Account Data” account.
  2. +
  3. Go to Developers > User secrets option on the left.
  4. +
  5. Click on the “+ Create new” button on the bottom part.
  6. +
  7. Put a name to the user secret (eg. Odoo), and optionally limit it to +certain IPs using CIDR subnet notation.
  8. +
  9. Copy or download the secret ID and key for later use. The second one +won’t be available anymore, so make sure you don’t forget this step.
  10. +
+
+
+

On Odoo

+

To configure online bank statements provider:

+
    +
  1. Add your user to the “Full Accounting Settings” group.

    +
  2. +
  3. Go to Invoicing > Configuration > Accounting > Journals.

    +
  4. +
  5. Select the journal representing your bank account (or create it).

    +
  6. +
  7. The bank account number should be properly introduced.

    +
  8. +
  9. Set Bank Feeds to Online (OCA).

    +
  10. +
  11. Select GoCardless as online bank statements provider in Online +Bank Statements (OCA) section.

    +
  12. +
  13. Save the journal

    +
  14. +
  15. Click on the created provider.

    +
  16. +
  17. Put your secret ID and secret key on the existing fields.

    +
  18. +
  19. Click on the button “Select Bank Account Identifier”.

    +

    image_01

    +
  20. +
  21. A new window will appear for selecting the bank entity.

    +

    image_02

    +
  22. +
  23. Select it, and you will be redirected to the selected entity for +introducing your bank credentials to allow the connection.

    +
  24. +
  25. If the process is completed, and the bank account linked to the +journal is accessible, you’ll be again redirected to the online +provider form, and everything will be linked and ready to start the +transaction pulling. A message is logged about it on the chatter.

    +
  26. +
  27. If not, an error message will be logged either in the chatter.

    +
  28. +
+
+
+
+

Usage

+

To pull historical bank statements:

+
    +
  1. Go to Invoicing > Configuration > Accounting > Journals.
  2. +
  3. Select the journal representing your bank account.
  4. +
  5. Launch Actions > Online Bank Statements Pull Wizard
  6. +
  7. Configure date interval and click on Pull.
  8. +
+

If historical data is not needed, then just simply wait for the +scheduled activity “Pull Online Bank Statements” to be executed for +getting new transactions.

+
+
+

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

+
    +
  • ForgeFlow
  • +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

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/bank-statement-import project on GitHub.

+

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

+
+
+
+ + diff --git a/account_statement_import_online_gocardless/static/img/gocardless_bank_selection.png b/account_statement_import_online_gocardless/static/img/gocardless_bank_selection.png new file mode 100644 index 00000000..a25b4ca4 Binary files /dev/null and b/account_statement_import_online_gocardless/static/img/gocardless_bank_selection.png differ diff --git a/account_statement_import_online_gocardless/static/img/gocardless_configuration.png b/account_statement_import_online_gocardless/static/img/gocardless_configuration.png new file mode 100644 index 00000000..5cea7391 Binary files /dev/null and b/account_statement_import_online_gocardless/static/img/gocardless_configuration.png differ diff --git a/account_statement_import_online_gocardless/static/src/js/select_bank_widget.esm.js b/account_statement_import_online_gocardless/static/src/js/select_bank_widget.esm.js new file mode 100644 index 00000000..cf70be76 --- /dev/null +++ b/account_statement_import_online_gocardless/static/src/js/select_bank_widget.esm.js @@ -0,0 +1,87 @@ +/** @odoo-module **/ +import {Component, useState} from "@odoo/owl"; +import {Dialog} from "@web/core/dialog/dialog"; +import {_t} from "@web/core/l10n/translation"; +import {registry} from "@web/core/registry"; + +export class GocardlessDialog extends Component { + setup() { + this.state = useState({ + searchString: "", + country: false, + institutions: this.props.context.institutions, + }); + } + onChangeCountry(event) { + var country = false; + if ( + event.target.selectedOptions.length && + event.target.selectedOptions[0].attributes.length + ) { + country = event.target.selectedOptions[0].value; + } + this.state.country = country; + this.state.institutions = this.get_institutions( + country, + this.state.searchString + ); + } + onInstitutionSearch(event) { + var searchString = event.target.value; + this.state.searchString = searchString; + this.state.institutions = this.get_institutions( + this.state.country, + searchString + ); + } + get_institutions(country, searchString) { + var institutions = this.props.context.institutions; + if (country) { + institutions.filter((institution) => + institution.countries.includes(country) + ); + } + return institutions.filter((institution) => + institution.name.toUpperCase().includes(searchString.toUpperCase()) + ); + } + + get country_names() { + return this.props.context.country_names; + } +} +GocardlessDialog.template = + "account_statement_import_online_gocardless.OnlineSyncSearchBankGoCardless"; +GocardlessDialog.components = {Dialog}; + +async function OnlineSyncAccountInstitutionSelector(env, action) { + env.services.dialog.add(GocardlessDialog, { + title: _t("Gocardless selection"), + context: action.context, + onClickInstitution: async function (institutionId) { + if (!institutionId) { + return; + } + await env.services.orm.write( + "online.bank.statement.provider", + [action.context.provider_id], + {gocardless_institution_id: institutionId} + ); + var redirect_url = await env.services.orm.call( + "online.bank.statement.provider", + "action_check_gocardless_agreement", + [[action.context.provider_id]] + ); + if (redirect_url !== undefined) { + window.location.replace(redirect_url); + } + }, + }); +} + +registry + .category("actions") + .add( + "online_sync_institution_selector_gocardless", + OnlineSyncAccountInstitutionSelector + ); diff --git a/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-Bold.ttf b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-Bold.ttf new file mode 100644 index 00000000..8645d734 Binary files /dev/null and b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-Bold.ttf differ diff --git a/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-SemiBold.ttf b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-SemiBold.ttf new file mode 100644 index 00000000..d6a0bf4a Binary files /dev/null and b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/fonts/HKGrotesk-SemiBold.ttf differ diff --git a/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/selector.css b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/selector.css new file mode 100644 index 00000000..15e0ffa5 --- /dev/null +++ b/account_statement_import_online_gocardless/static/src/lib/gocardless-ui/selector.css @@ -0,0 +1,209 @@ + +* { + box-sizing: border-box; +} + +@font-face { + font-family: "HK Grotesk"; + src: url('fonts/HKGrotesk-Bold.ttf') format("truetype"); +} + +.institution-content-wrapper { + margin: 0 auto; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 2rem; +} + +.institution-search-bx-body { + max-height: 52vh; + overflow-y: auto; +} + + +.institution-search-bx-body::-webkit-scrollbar-thumb { + background: #AEB0B0; + border-radius: 7px; +} + +.institution-search-bx-body::-webkit-scrollbar { + width: 6px; + background-color: #F1F1F1; + border-radius: 7px; +} + +#institution-modal-content { + width: 100%; + max-width: 40rem; + background-color: #fff; + padding: 4.5rem; + display: flex; + flex-direction: column; + box-shadow: 0px 1px 3px #00000029; + border-radius: 14px; + color: #1B2021; +} + +.institution-modal-header { + text-align: right; +} + +.institution-modal-header h2 { + text-align: left; + font-size: 2.5rem; + margin: 0; +} + +.institution-modal-footer { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + padding: 2rem; +} + +.institution-modal-footer > a { + line-height: 2.8rem; + text-decoration: none; + color: #808080; +} + +.institution-modal-footer > a:hover { + text-decoration: underline; +} + +.institution-modal-close { + color: #8D9090; + font-size: 2.6rem; + font-weight: bold; + cursor: pointer; + position: relative; + top: -20px; +} + +.institution-search-container { + position: relative; + bottom: 2.2rem; +} + +.institution-search-container input { + text-indent: 2.8rem; +} + +.institution-search-icon { + position: relative; + padding: 1rem; + height: 3.8rem; + top: 3.8rem; +} + +.institution-search-input { + width: 100%; + padding: 1rem; + border-radius: 9px; + color: #8C8E8F; + border: 1px solid #8c8e8f; + font-size: 1.6rem; + font-weight: 400; + outline-color: #70b1f7; +} + + +.institution-container { + display: flex; + flex-direction: column; +} + +.list-institution { + padding: 14px 0; + border-bottom: 1px solid #D7D8D8; +} + +.list-institution:last-child { + border: none; +} + +.list-institution a { + padding-right: 2.5rem; + display: flex; + flex-direction: row; + align-items: center; + text-decoration: none; +} + + +.list-institution span { + margin-left: 1.5rem; + font-size: 1.5rem; + font-weight: 600; + color: #1B2021; +} + +.list-institution:hover { + background-color: #F1F1F1; +} + +img.institution-logo { + width: 100%; + max-width: 3.5rem; + height: 3.5rem; + border-radius: 6px; +} + +.institution-company-logo { + max-width: 13rem; + height: 10rem; + margin: 2.5rem 0 7rem; +} + +@media screen and (max-width: 640px) { + + html { + font-size: 8px; + } + + #institution-modal-content { + height: 100%; + max-width: 100%; + border-radius: 0; + } + + #institution-modal-content, + .institution-company-logo { + margin: 0; + } + + .institution-company-logo { + position: absolute; + bottom: 0; + padding: 2.5rem; + } + + .institution-modal-close { + display: none; + } + + + .institution-modal-header { + margin-top: 3rem; + } + + .institution-modal-header h2 { + font-size: 3rem; + } + + .list-institution span { + font-size: 1.9rem; + } +} + +@media screen and (device-height: 568px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 2) { + + html { + font-size: 7px; + } + +} diff --git a/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml b/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml new file mode 100644 index 00000000..b9c6a680 --- /dev/null +++ b/account_statement_import_online_gocardless/static/src/xml/select_bank_widget.xml @@ -0,0 +1,75 @@ + + + +
+
+
+
+ +
+ + +
+
+ +
+
+
+ + + +
+
+
+
+
+
diff --git a/account_statement_import_online_gocardless/tests/__init__.py b/account_statement_import_online_gocardless/tests/__init__.py new file mode 100644 index 00000000..bf7367ab --- /dev/null +++ b/account_statement_import_online_gocardless/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_account_statement_import_online_gocardless diff --git a/account_statement_import_online_gocardless/tests/test_account_statement_import_online_gocardless.py b/account_statement_import_online_gocardless/tests/test_account_statement_import_online_gocardless.py new file mode 100644 index 00000000..2b514241 --- /dev/null +++ b/account_statement_import_online_gocardless/tests/test_account_statement_import_online_gocardless.py @@ -0,0 +1,141 @@ +# Copyright 2023 Tecnativa - Pedro M.Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from unittest import mock + +from dateutil.relativedelta import relativedelta + +from odoo import fields +from odoo.tests import common + +_module_ns = "odoo.addons.account_statement_import_online_gocardless" +_provider_class = ( + _module_ns + ".models.online_bank_statement_provider.OnlineBankStatementProvider" +) + + +class TestAccountBankAccountStatementImportOnlineGocardless(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.now = fields.Datetime.now() + cls.currency_eur = cls.env.ref("base.EUR") + cls.currency_eur.write({"active": True}) + bank_account = cls.env["res.partner.bank"].create( + { + "acc_number": "NL77ABNA0574908765", + "partner_id": cls.env.ref("base.main_partner").id, + "company_id": cls.env.ref("base.main_company").id, + "bank_id": cls.env.ref("base.res_bank_1").id, + } + ) + cls.journal = cls.env["account.journal"].create( + { + "name": "GoCardless Bank Test", + "type": "bank", + "code": "GCB", + "currency_id": cls.currency_eur.id, + "bank_statements_source": "online", + "online_bank_statement_provider": "gocardless", + "bank_account_id": bank_account.id, + } + ) + cls.provider = cls.journal.online_bank_statement_provider_id + cls.provider.write( + { + "statement_creation_mode": "monthly", + "gocardless_account_id": "SANDBOXFINANCE_SFIN0000", + "gocardless_requisition_expiration": cls.now + relativedelta(days=30), + } + ) + cls.return_value = { # GoCardless sample return + "transactions": { + "booked": [ + { + "transactionId": "2020103000624289-1", + "debtorName": "MON MOTHMA", + "debtorAccount": {"iban": "GL53SAFI055151515"}, + "transactionAmount": {"currency": "EUR", "amount": "45.00"}, + "bookingDate": "2020-10-30", + "valueDate": "2020-10-30", + "remittanceInformationUnstructured": ( + "For the support of Restoration of the Republic foundation" + ), + }, + { + "transactionId": "2020111101899195-1", + "transactionAmount": {"currency": "EUR", "amount": "-15.00"}, + "bankTransactionCode": "PMNT", + "bookingDate": "2020-11-11", + "valueDate": "2020-11-11", + "remittanceInformationUnstructured": "PAYMENT Alderaan Coffe", + }, + ], + "pending": [ + { + "transactionAmount": {"currency": "EUR", "amount": "-10.00"}, + "valueDate": "2020-11-03", + "remittanceInformationUnstructured": ( + "Reserved PAYMENT Emperor's Burgers" + ), + } + ], + } + } + cls.mock_transaction = lambda cls: mock.patch( + _provider_class + "._gocardless_request_transactions", + return_value=cls.return_value, + ) + cls.request_requisition_value = { + "accounts": ["ACCOUNT-ID-1"], + "agreement": "TEST-AGREEMENT-ID", + } + cls.mock_requisition = lambda cls: mock.patch( + _provider_class + "._gocardless_request_requisition", + return_value=cls.request_requisition_value, + ) + cls.request_account_value = { + "id": "ACCOUNT-ID-1", + "iban": "nl77abna0574908765", + } + cls.mock_account = lambda cls: mock.patch( + _provider_class + "._gocardless_request_account", + return_value=cls.request_account_value, + ) + cls.request_agreement_value = { + "id": "TEST-AGREEMENT-ID", + "accepted": cls.now.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + "access_valid_for_days": 30, + } + cls.mock_agreement = lambda cls: mock.patch( + _provider_class + "._gocardless_request_agreement", + return_value=cls.request_agreement_value, + ) + + def test_mocked_gocardless(self): + vals = { + "date_since": "2020-10-30", + "date_until": "2020-11-11", + } + wizard = ( + self.env["online.bank.statement.pull.wizard"] + .with_context( + active_model="account.journal", + active_id=self.journal.id, + ) + .create(vals) + ) + with self.mock_transaction(): + wizard.action_pull() + statements = self.env["account.bank.statement"].search( + [("journal_id", "=", self.journal.id)] + ) + self.assertEqual(len(statements), 2) + lines = statements.line_ids.sorted(lambda x: x.date) + self.assertEqual(len(lines), 2) + self.assertEqual(lines.mapped("amount"), [45.0, -15.0]) + + def test_provider_gocardless_finish_requisition(self): + with self.mock_requisition(), self.mock_account(), self.mock_agreement(): + res = self.provider._gocardless_finish_requisition(dry=True) + self.assertTrue(res, "Bank account not found!") diff --git a/account_statement_import_online_gocardless/view/online_bank_statement_provider.xml b/account_statement_import_online_gocardless/view/online_bank_statement_provider.xml new file mode 100644 index 00000000..602bfade --- /dev/null +++ b/account_statement_import_online_gocardless/view/online_bank_statement_provider.xml @@ -0,0 +1,54 @@ + + + + online.bank.statement.provider.form + online.bank.statement.provider + + + + + + + + + + + +