Merge PR #739 into 17.0

Signed-off-by pedrobaeza
This commit is contained in:
OCA-git-bot
2024-11-19 16:45:32 +00:00
22 changed files with 2432 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
===================================
Online Bank Statements: MyPonto.com
===================================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4761a86432e267dd6dc91976fd25d4ea5ae91d06c8f1bf8a50c24c1916268d8e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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_ponto
: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_ponto
: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 MyPonto.com.
**Table of contents**
.. contents::
:local:
Configuration
=============
To configure online bank statements provider:
1. Go to *Invoicing > Configuration > Bank Accounts*
2. Open bank account to configure and edit it
3. Set *Bank Feeds* to *Online*
4. Select *MyPonto.com* as online bank statements provider in *Online
Bank Statements (OCA)* section
5. Save the bank account
6. Click on provider and configure provider-specific settings.
or, alternatively:
1. Go to *Invoicing > Overview*
2. Open settings of the corresponding journal account
3. Switch to *Bank Account* tab
4. Set *Bank Feeds* to *Online*
5. Select *MyPonto.com* as online bank statements provider in *Online
Bank Statements (OCA)* section
6. Save the bank account
7. Click on provider and configure provider-specific settings.
To obtain *Login* and *Key*:
1. Open `MyPonto.com <https://myponto.com/>`__.
Check also ``account_bank_statement_import_online`` configuration
instructions for more information.
Usage
=====
To pull historical bank statements:
1. Go to *Invoicing > Configuration > Bank Accounts*
2. Select specific bank accounts
3. Launch *Actions > Online Bank Statements Pull Wizard*
4. Configure date interval and click *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 <https://github.com/OCA/bank-statement-import/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 <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_statement_import_online_ponto%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
-------
* Florent de Labarre
* Therp BV
Contributors
------------
- Florent de Labarre
- `Tecnativa <https://www.tecnativa.com>`__:
- Pedro M. Baeza
- João Marques
- `Therp BV <https://therp.nl>`__:
- Ronald Portier <ronald@therp.nl>
- `Tesseratech <https://tesseratech.es>`__:
- Christian Doñate
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 <https://github.com/OCA/bank-statement-import/tree/17.0/account_statement_import_online_ponto>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import models

View File

@@ -0,0 +1,17 @@
# Copyright 2020 Florent de Labarre.
# Copyright 2020 Tecnativa - João Marques.
# Copyright 2022-2023 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Online Bank Statements: MyPonto.com",
"version": "17.0.1.1.1",
"category": "Account",
"website": "https://github.com/OCA/bank-statement-import",
"author": "Florent de Labarre, Therp BV, Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"depends": ["account_statement_import_online"],
"data": [
"views/online_bank_statement_provider.xml",
],
}

View File

@@ -0,0 +1,166 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_statement_import_online_ponto
#
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_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "%d transactions present in response data"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__execution_date
msgid "Execution Date"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request on %(url)s"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request to %(url)s with headers %(headers)s and params %(params)s"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "HTTP answer code %(response_code)s from Ponto"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_ponto_interface
msgid "Interface to all interactions with Ponto API"
msgstr ""
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Login"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "No lines were retrieved from Ponto"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "No transactions where found in data %(data)s"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_online_bank_statement_provider
msgid "Online Bank Statement Provider"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "POST request on %(url)s"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Please fill login and key."
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : no token"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : wrong configuration, account {account} not found in {data}"
msgstr ""
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Ponto Config"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid "Ponto Date Field"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_last_identifier
msgid "Ponto Last Identifier"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto obtain all new statement data for journal %s"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Ponto obtain statement data for journal %(journal)s from %(date_since)s to "
"%(date_until)s"
msgstr ""
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Secret Key"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,help:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid ""
"Select the Ponto date field that will be used for the Odoo bank statement "
"line date."
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Server returned status code {response_code}: {response_text}"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/tests/test_account_statement_import_online_ponto.py:0
#, python-format
msgid "Statement contains transactions: %s"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__value_date
msgid "Value Date"
msgstr ""

View File

@@ -0,0 +1,126 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_statement_import_online_ponto
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2022-01-26 18:52+0000\n"
"Last-Translator: Jaume Planas <jaume.planas@minorisa.net>\n"
"Language-Team: none\n"
"Language: ca\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.3.2\n"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"%s \n"
"\n"
" %s"
msgstr ""
"%s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__display_name
msgid "Display Name"
msgstr "Nom"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Error during Create Synchronisation %s \n"
"\n"
" %s"
msgstr ""
"Error al crear sincronització %s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Error during get transaction.\n"
"\n"
"%s \n"
"\n"
" %s"
msgstr ""
"Error durant la transacció GET.\n"
"\n"
"%s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__id
msgid "ID"
msgstr "ID"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider____last_update
msgid "Last Modified on"
msgstr "Última modificació el"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Login"
msgstr "Inicia sessió"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_online_bank_statement_provider
msgid "Online Bank Statement Provider"
msgstr "Proveïdor en línia d'extractes bancaris"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Please fill login and key."
msgstr "Ompliu l'inici de sessió i la clau."
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto : no token"
msgstr "Ponto: cap token"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto : wrong configuration, unknow account %s"
msgstr "Ponto: configuració errònia, compte %s desconegut"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_last_identifier
msgid "Ponto Last Identifier"
msgstr "Ponto Últim identificador"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_token
msgid "Ponto Token"
msgstr "Token Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_token_expiration
msgid "Ponto Token Expiration"
msgstr "Caducitat token Ponto"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Reset Last identifier."
msgstr "Restabliment últim identificador."
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Secret Key"
msgstr "Clau secreta"

View File

@@ -0,0 +1,175 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_statement_import_online_ponto
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-11-01 21:38+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\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: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "%d transactions present in response data"
msgstr "%d transacciones presentes en los datos de respuesta"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__execution_date
msgid "Execution Date"
msgstr "Fecha de Ejecución"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request on %(url)s"
msgstr "Solicitud GET en %(url)s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request to %(url)s with headers %(headers)s and params %(params)s"
msgstr ""
"Solicitud GET a %(url)s con cabeceras %(headers)s y parámetros %(params)s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "HTTP answer code %(response_code)s from Ponto"
msgstr "Código de respuesta HTTP %(response_code)s de Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_ponto_interface
msgid "Interface to all interactions with Ponto API"
msgstr "Interfaz para todas las interacciones con la API Ponto"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Login"
msgstr "Inicio de sesión"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "No lines were retrieved from Ponto"
msgstr "No se recuperaron líneas del Ponto"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "No transactions where found in data %(data)s"
msgstr "No se han encontrado transacciones en los datos %(data)s"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_online_bank_statement_provider
msgid "Online Bank Statement Provider"
msgstr "Proveedor de Extractos Bancarios en Línea"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "POST request on %(url)s"
msgstr "Petición POST en %(url)s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Please fill login and key."
msgstr "Por favor, rellene login y clave."
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : no token"
msgstr "Ponto: sin ficha"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : wrong configuration, account {account} not found in {data}"
msgstr "Ponto : configuración errónea, cuenta {account} no encontrada en {data}"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Ponto Config"
msgstr "Config Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid "Ponto Date Field"
msgstr "Ponto Fecha Campo"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_last_identifier
msgid "Ponto Last Identifier"
msgstr "Ponto Último Identificador"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto obtain all new statement data for journal %s"
msgstr "Ponto obtener todos los datos de los nuevos extractos para el diario %s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Ponto obtain statement data for journal %(journal)s from %(date_since)s to "
"%(date_until)s"
msgstr ""
"Ponto obtiene los datos del extracto del diario %(journal)s desde "
"%(date_since)s hasta %(date_until)s"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Secret Key"
msgstr "Clave Secreta"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,help:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid ""
"Select the Ponto date field that will be used for the Odoo bank statement "
"line date."
msgstr ""
"Seleccione el campo de fecha Ponto que se utilizará para la fecha de la "
"línea del extracto bancario de Odoo."
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Server returned status code {response_code}: {response_text}"
msgstr ""
"El servidor ha devuelto el código de estado {response_code}: {response_text}"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/tests/test_account_statement_import_online_ponto.py:0
#, python-format
msgid "Statement contains transactions: %s"
msgstr "El extracto contiene transacciones: %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__value_date
msgid "Value Date"
msgstr "Fecha Valor"

View File

@@ -0,0 +1,126 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_statement_import_online_ponto
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-05-03 16:35+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\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 4.17\n"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"%s \n"
"\n"
" %s"
msgstr ""
"%s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Error during Create Synchronisation %s \n"
"\n"
" %s"
msgstr ""
"Errore nella creazione della sincronizzazione %s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Error during get transaction.\n"
"\n"
"%s \n"
"\n"
" %s"
msgstr ""
"Errore nell'ottenere la transizione.\n"
"\n"
"%s \n"
"\n"
" %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__id
msgid "ID"
msgstr "ID"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Login"
msgstr "Login"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_online_bank_statement_provider
msgid "Online Bank Statement Provider"
msgstr "Fornitore estratto conto bancario online"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Please fill login and key."
msgstr "Fornire login e chiave."
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto : no token"
msgstr "Ponto : nessun token"
#. module: account_statement_import_online_ponto
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto : wrong configuration, unknow account %s"
msgstr "Ponto: configurazione errata, account %s sconosciuto"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_last_identifier
msgid "Ponto Last Identifier"
msgstr "Ultimo identificatore Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_token
msgid "Ponto Token"
msgstr "Token Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_token_expiration
msgid "Ponto Token Expiration"
msgstr "Scadenza token Ponto"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Reset Last identifier."
msgstr "Resetta ultimo identificatore."
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Secret Key"
msgstr "Chiave segreta"

View File

@@ -0,0 +1,175 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_statement_import_online_ponto
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-11-14 15:13+0000\n"
"Last-Translator: Thijs van Oers <thijsvanoers@yahoo.com>\n"
"Language-Team: none\n"
"Language: nl\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: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "%d transactions present in response data"
msgstr "%d transacties aanwezig in response data"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__execution_date
msgid "Execution Date"
msgstr "datum uitvoering"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request on %(url)s"
msgstr "Vraag request aan %(url)s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "GET request to %(url)s with headers %(headers)s and params %(params)s"
msgstr ""
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "HTTP answer code %(response_code)s from Ponto"
msgstr "HTTP antwoord code %(response_code)s vanuit Ponto"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_ponto_interface
msgid "Interface to all interactions with Ponto API"
msgstr "Interface naar alle interacties met de Ponto API"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Login"
msgstr "Inlog"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "No lines were retrieved from Ponto"
msgstr "Er zijn geen regels opgehaald vanuit Ponto"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "No transactions where found in data %(data)s"
msgstr "Geen transacties gevonden voor dagen %(data)s"
#. module: account_statement_import_online_ponto
#: model:ir.model,name:account_statement_import_online_ponto.model_online_bank_statement_provider
msgid "Online Bank Statement Provider"
msgstr "Online aanbieder bankafschriften"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "POST request on %(url)s"
msgstr "POST request op %(url)s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Please fill login and key."
msgstr "Vul uw login en key in."
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : no token"
msgstr "Ponto: geen token"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Ponto : wrong configuration, account {account} not found in {data}"
msgstr ""
"Ponto : verkeerde configuratie, rekening {account} niet gevonden in {data}"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Ponto Config"
msgstr "Ponto configuratie"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid "Ponto Date Field"
msgstr "Ponto datumveld"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,field_description:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_last_identifier
msgid "Ponto Last Identifier"
msgstr "Laatste identifier Ponto"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid "Ponto obtain all new statement data for journal %s"
msgstr "Ponto verkrijgt alle nieuwe afschrift informatie voor dagboek %s"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/online_bank_statement_provider_ponto.py:0
#, python-format
msgid ""
"Ponto obtain statement data for journal %(journal)s from %(date_since)s to "
"%(date_until)s"
msgstr ""
"Ponto verkrijgt afschrift informatie voor dagboek %(journal)s vanaf "
"%(date_since)s tot %(date_until)s"
#. module: account_statement_import_online_ponto
#: model_terms:ir.ui.view,arch_db:account_statement_import_online_ponto.online_bank_statement_provider_form
msgid "Secret Key"
msgstr ""
#. module: account_statement_import_online_ponto
#: model:ir.model.fields,help:account_statement_import_online_ponto.field_online_bank_statement_provider__ponto_date_field
msgid ""
"Select the Ponto date field that will be used for the Odoo bank statement "
"line date."
msgstr ""
"Selecteer het Ponto datumveld dat zal worden gebruikt voor de Odoo "
"bankafschriftregel datum."
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/models/ponto_interface.py:0
#, python-format
msgid "Server returned status code {response_code}: {response_text}"
msgstr ""
"De server gaf de volgende status code terug {response_code}: {response_text}"
#. module: account_statement_import_online_ponto
#. odoo-python
#: code:addons/account_statement_import_online_ponto/tests/test_account_statement_import_online_ponto.py:0
#, python-format
msgid "Statement contains transactions: %s"
msgstr "Afschrift bevat transacties: %s"
#. module: account_statement_import_online_ponto
#: model:ir.model.fields.selection,name:account_statement_import_online_ponto.selection__online_bank_statement_provider__ponto_date_field__value_date
msgid "Value Date"
msgstr "Datum waarde"

View File

@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import ponto_interface
from . import online_bank_statement_provider_ponto

View File

@@ -0,0 +1,225 @@
# Copyright 2020 Florent de Labarre
# Copyright 2022-2023 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import json
import logging
import re
from datetime import datetime, timedelta
from operator import itemgetter
import pytz
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
class OnlineBankStatementProvider(models.Model):
_inherit = "online.bank.statement.provider"
ponto_last_identifier = fields.Char(readonly=True)
ponto_date_field = fields.Selection(
[
("execution_date", "Execution Date"),
("value_date", "Value Date"),
],
default="execution_date",
help="Select the Ponto date field that will be used for "
"the Odoo bank statement line date.",
)
@api.model
def _get_available_services(self):
"""Each provider model must register its service."""
return super()._get_available_services() + [
("ponto", "MyPonto.com"),
]
def _pull(self, date_since, date_until):
"""For Ponto the pulling of data will not be grouped by statement.
Instead we will pull data from the last available backwards.
For a scheduled pull we will continue until we get to data
already retrieved or there is no more data available.
For a wizard pull we will discard data after date_until and
stop retrieving when either we get before date_since or there is
no more data available.
"""
# pylint: disable=missing-return
ponto_providers = self.filtered(lambda provider: provider.service == "ponto")
debug = self.env.context.get("account_statement_online_import_debug")
debug_data = []
data = super(OnlineBankStatementProvider, self - ponto_providers)._pull(
date_since, date_until
)
if debug:
debug_data += data
for provider in ponto_providers:
data = provider._ponto_pull(date_since, date_until)
if debug:
debug_data += data
return debug_data
def _ponto_pull(self, date_since, date_until):
"""Translate information from Ponto to Odoo bank statement lines."""
self.ensure_one()
is_scheduled = self.env.context.get("scheduled", False)
if is_scheduled:
_logger.debug(
_(
"Ponto obtain statement data for journal %(journal)s"
" from %(date_since)s to %(date_until)s"
),
dict(
journal=self.journal_id.name,
date_since=date_since,
date_until=date_until,
),
)
else:
_logger.debug(
_("Ponto obtain all new statement data for journal %s"),
self.journal_id.name,
)
lines = self._ponto_retrieve_data(date_since, date_until)
if not lines:
_logger.info(_("No lines were retrieved from Ponto"))
else:
# For scheduled runs, store latest identifier.
if is_scheduled:
self.ponto_last_identifier = lines[0].get("id")
self._ponto_store_lines(lines)
return lines
def _ponto_retrieve_data(self, date_since, date_until):
"""Fill buffer with data from Ponto.
We will retrieve data from the latest transactions present in Ponto
backwards, until we find data that has an execution date before date_since,
or until we get to a transaction that we already have.
Note: when reading data they are likely to be in descending order of
execution_date (not seen a guarantee for this in Ponto API). When using
value date, they may well be out of order. So we cannot simply stop
when we have found a transaction date before the date_since.
We will not read transactions more then a week before before date_since.
"""
date_stop = date_since - timedelta(days=7)
is_scheduled = self.env.context.get("scheduled", False)
lines = []
interface_model = self.env["ponto.interface"]
access_data = interface_model._login(self.username, self.password)
interface_model._set_access_account(access_data, self.account_number)
latest_identifier = False
transactions = interface_model._get_transactions(access_data, latest_identifier)
while transactions:
for line in transactions:
identifier = line.get("id")
transaction_datetime = self._ponto_get_transaction_datetime(line)
if is_scheduled:
# Handle all stop conditions for scheduled runs.
if identifier == self.ponto_last_identifier or (
not self.ponto_last_identifier
and transaction_datetime < date_stop
):
return lines
else:
# Handle stop conditions for non scheduled runs.
if transaction_datetime < date_stop:
return lines
if (
transaction_datetime < date_since
or transaction_datetime > date_until
):
continue
line["transaction_datetime"] = transaction_datetime
lines.append(line)
latest_identifier = transactions[-1].get("id")
transactions = interface_model._get_transactions(
access_data, latest_identifier
)
# We get here if we found no transactions before date_since,
# or not equal to stored last identifier.
return lines
def _ponto_store_lines(self, lines):
"""Store transactions retrieved from Ponto in statements."""
lines = sorted(lines, key=itemgetter("transaction_datetime"))
# Group statement lines by date per period (date range)
grouped_periods = {}
for line in lines:
date_since = line["transaction_datetime"]
statement_date_since = self._get_statement_date_since(date_since)
statement_date_until = (
statement_date_since + self._get_statement_date_step()
)
if (statement_date_since, statement_date_until) not in grouped_periods:
grouped_periods[(statement_date_since, statement_date_until)] = []
line.pop("transaction_datetime")
vals_line = self._ponto_get_transaction_vals(line)
grouped_periods[(statement_date_since, statement_date_until)].append(
vals_line
)
# For each period, create or update statement lines
for period, statement_lines in grouped_periods.items():
(date_since, date_until) = period
self._create_or_update_statement(
(statement_lines, {}), date_since, date_until
)
def _ponto_get_transaction_vals(self, transaction):
"""Translate information from Ponto to statement line vals."""
attributes = transaction.get("attributes", {})
ref_list = [
attributes.get(x)
for x in {
"description",
"counterpartName",
"counterpartReference",
}
if attributes.get(x)
]
ref = " ".join(ref_list)
date = self._ponto_get_transaction_datetime(transaction)
vals_line = {
"sequence": 1, # Sequence is not meaningfull for Ponto.
"date": date,
"ref": re.sub(" +", " ", ref) or "/",
"payment_ref": attributes.get("remittanceInformation", ref),
"unique_import_id": transaction["id"],
"amount": attributes["amount"],
"raw_data": json.dumps(transaction),
}
if attributes.get("counterpartReference"):
vals_line["account_number"] = attributes["counterpartReference"]
if attributes.get("counterpartName"):
vals_line["partner_name"] = attributes["counterpartName"]
return vals_line
def _ponto_get_transaction_datetime(self, transaction):
"""Get execution datetime for a transaction.
Odoo often names variables containing date and time just xxx_date or
date_xxx. We try to avoid this misleading naming by using datetime as
much for variables and fields of type datetime.
"""
attributes = transaction.get("attributes", {})
if self.ponto_date_field == "value_date":
datetime_str = attributes.get("valueDate")
else:
datetime_str = attributes.get("executionDate")
return self._ponto_datetime_from_string(datetime_str)
def _ponto_datetime_from_string(self, datetime_str):
"""Dates in Ponto are expressed in UTC, so we need to convert them
to supplied tz for proper classification.
"""
dt = datetime.strptime(datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ")
dt = dt.replace(tzinfo=pytz.utc).astimezone(pytz.timezone(self.tz or "utc"))
return dt.replace(tzinfo=None)

View File

@@ -0,0 +1,166 @@
# Copyright 2020 Florent de Labarre
# Copyright 2022 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
import json
import logging
import requests
from dateutil.relativedelta import relativedelta
from odoo import _, fields, models
from odoo.exceptions import UserError
from odoo.addons.base.models.res_bank import sanitize_account_number
_logger = logging.getLogger(__name__)
PONTO_ENDPOINT = "https://api.myponto.com"
class PontoInterface(models.AbstractModel):
_name = "ponto.interface"
_description = "Interface to all interactions with Ponto API"
def _login(self, username, password):
"""Ponto login returns an access dictionary for further requests."""
url = PONTO_ENDPOINT + "/oauth2/token"
if not (username and password):
raise UserError(_("Please fill login and key."))
login = ":".join([username, password])
login = base64.b64encode(login.encode("UTF-8")).decode("UTF-8")
login_headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
"Authorization": f"Basic {login}",
}
_logger.debug(_("POST request on %(url)s"), dict(url=url))
response = requests.post(
url,
params={"grant_type": "client_credentials"},
headers=login_headers,
timeout=60,
)
data = self._get_response_data(response)
access_token = data.get("access_token", False)
if not access_token:
raise UserError(_("Ponto : no token"))
token_expiration = fields.Datetime.now() + relativedelta(
seconds=data.get("expires_in", False)
)
return {
"username": username,
"password": password,
"access_token": access_token,
"token_expiration": token_expiration,
}
def _get_request_headers(self, access_data):
"""Get headers with authorization for further ponto requests."""
if access_data["token_expiration"] <= fields.Datetime.now():
updated_data = self._login(access_data["username"], access_data["password"])
access_data.update(updated_data)
return {
"Accept": "application/json",
"Authorization": "Bearer {access_token}".format(
access_token=access_data["access_token"]
),
}
def _set_access_account(self, access_data, account_number):
"""Set ponto account for bank account in access_data."""
url = PONTO_ENDPOINT + "/accounts"
_logger.debug(_("GET request on %(url)s"), dict(url=url))
response = requests.get(
url,
params={"limit": 100},
headers=self._get_request_headers(access_data),
timeout=60,
)
data = self._get_response_data(response)
for ponto_account in data.get("data", []):
ponto_iban = sanitize_account_number(
ponto_account.get("attributes", {}).get("reference", "")
)
if ponto_iban == account_number:
access_data["ponto_account"] = ponto_account.get("id")
return
# If we get here, we did not find Ponto account for bank account.
raise UserError(
_(
"Ponto : wrong configuration, account {account} not found in {data}"
).format(account=account_number, data=data)
)
def _get_transactions(self, access_data, last_identifier):
"""Get transactions from ponto, using last_identifier as pointer.
Note that Ponto has the transactions in descending order. The first
transaction, retrieved by not passing an identifier, is the latest
present in Ponto. If you read transactions 'after' a certain identifier
(Ponto id), you will get transactions with an earlier date.
"""
url = (
PONTO_ENDPOINT
+ "/accounts/"
+ access_data["ponto_account"]
+ "/transactions"
)
params = {"limit": 100}
if last_identifier:
params["after"] = last_identifier
data = self._get_request(access_data, url, params)
transactions = self._get_transactions_from_data(data)
return transactions
def _get_transactions_from_data(self, data):
"""Get all transactions that are in the ponto response data."""
transactions = data.get("data", [])
if not transactions:
_logger.debug(
_("No transactions where found in data %(data)s"),
dict(data=data),
)
else:
_logger.debug(
_("%d transactions present in response data"),
len(transactions),
)
return transactions
def _get_request(self, access_data, url, params):
"""Interact with Ponto to get next page of data."""
headers = self._get_request_headers(access_data)
_logger.debug(
_("GET request to %(url)s with headers %(headers)s and params %(params)s"),
dict(
url=url,
headers=headers,
params=params,
),
)
response = requests.get(
url,
params=params,
headers=headers,
timeout=(60, 300),
)
return self._get_response_data(response)
def _get_response_data(self, response):
"""Get response data for GET or POST request."""
_logger.debug(
_("HTTP answer code %(response_code)s from Ponto"),
dict(response_code=response.status_code),
)
if response.status_code not in (200, 201):
raise UserError(
_(
"Server returned status code {response_code}: {response_text}"
).format(
response_code=response.status_code,
response_text=response.text,
)
)
return json.loads(response.text)

View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@@ -0,0 +1,27 @@
To configure online bank statements provider:
1. Go to *Invoicing \> Configuration \> Bank Accounts*
2. Open bank account to configure and edit it
3. Set *Bank Feeds* to *Online*
4. Select *MyPonto.com* as online bank statements provider in *Online
Bank Statements (OCA)* section
5. Save the bank account
6. Click on provider and configure provider-specific settings.
or, alternatively:
1. Go to *Invoicing \> Overview*
2. Open settings of the corresponding journal account
3. Switch to *Bank Account* tab
4. Set *Bank Feeds* to *Online*
5. Select *MyPonto.com* as online bank statements provider in *Online
Bank Statements (OCA)* section
6. Save the bank account
7. Click on provider and configure provider-specific settings.
To obtain *Login* and *Key*:
1. Open [MyPonto.com](https://myponto.com/).
Check also `account_bank_statement_import_online` configuration
instructions for more information.

View File

@@ -0,0 +1,8 @@
- Florent de Labarre
- [Tecnativa](https://www.tecnativa.com):
- Pedro M. Baeza
- João Marques
- [Therp BV](https://therp.nl):
- Ronald Portier \<<ronald@therp.nl>\>
- [Tesseratech](https://tesseratech.es):
- Christian Doñate

View File

@@ -0,0 +1 @@
This module provides online bank statements from MyPonto.com.

View File

@@ -0,0 +1,10 @@
To pull historical bank statements:
1. Go to *Invoicing \> Configuration \> Bank Accounts*
2. Select specific bank accounts
3. Launch *Actions \> Online Bank Statements Pull Wizard*
4. Configure date interval and click *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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,482 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Online Bank Statements: MyPonto.com</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="online-bank-statements-myponto-com">
<h1 class="title">Online Bank Statements: MyPonto.com</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4761a86432e267dd6dc91976fd25d4ea5ae91d06c8f1bf8a50c24c1916268d8e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/bank-statement-import/tree/17.0/account_statement_import_online_ponto"><img alt="OCA/bank-statement-import" src="https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/bank-statement-import-17-0/bank-statement-import-17-0-account_statement_import_online_ponto"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/bank-statement-import&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module provides online bank statements from MyPonto.com.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>To configure online bank statements provider:</p>
<ol class="arabic simple">
<li>Go to <em>Invoicing &gt; Configuration &gt; Bank Accounts</em></li>
<li>Open bank account to configure and edit it</li>
<li>Set <em>Bank Feeds</em> to <em>Online</em></li>
<li>Select <em>MyPonto.com</em> as online bank statements provider in <em>Online
Bank Statements (OCA)</em> section</li>
<li>Save the bank account</li>
<li>Click on provider and configure provider-specific settings.</li>
</ol>
<p>or, alternatively:</p>
<ol class="arabic simple">
<li>Go to <em>Invoicing &gt; Overview</em></li>
<li>Open settings of the corresponding journal account</li>
<li>Switch to <em>Bank Account</em> tab</li>
<li>Set <em>Bank Feeds</em> to <em>Online</em></li>
<li>Select <em>MyPonto.com</em> as online bank statements provider in <em>Online
Bank Statements (OCA)</em> section</li>
<li>Save the bank account</li>
<li>Click on provider and configure provider-specific settings.</li>
</ol>
<p>To obtain <em>Login</em> and <em>Key</em>:</p>
<ol class="arabic simple">
<li>Open <a class="reference external" href="https://myponto.com/">MyPonto.com</a>.</li>
</ol>
<p>Check also <tt class="docutils literal">account_bank_statement_import_online</tt> configuration
instructions for more information.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>To pull historical bank statements:</p>
<ol class="arabic simple">
<li>Go to <em>Invoicing &gt; Configuration &gt; Bank Accounts</em></li>
<li>Select specific bank accounts</li>
<li>Launch <em>Actions &gt; Online Bank Statements Pull Wizard</em></li>
<li>Configure date interval and click <em>Pull</em></li>
</ol>
<p>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.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/bank-statement-import/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_statement_import_online_ponto%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>Florent de Labarre</li>
<li>Therp BV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li>Florent de Labarre</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Pedro M. Baeza</li>
<li>João Marques</li>
</ul>
</li>
<li><a class="reference external" href="https://therp.nl">Therp BV</a>:<ul>
<li>Ronald Portier &lt;<a class="reference external" href="mailto:ronald&#64;therp.nl">ronald&#64;therp.nl</a>&gt;</li>
</ul>
</li>
<li><a class="reference external" href="https://tesseratech.es">Tesseratech</a>:<ul>
<li>Christian Doñate</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/17.0/account_statement_import_online_ponto">OCA/bank-statement-import</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import test_ponto_interface
from . import test_account_statement_import_online_ponto

View File

@@ -0,0 +1,458 @@
# Copyright 2020 Florent de Labarre
# Copyright 2022 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
from datetime import datetime
from unittest import mock
from odoo import _, fields
from odoo.tests import common
_logger = logging.getLogger(__name__)
_module_ns = "odoo.addons.account_statement_import_online_ponto"
_interface_class = _module_ns + ".models.ponto_interface" + ".PontoInterface"
# Transactions should be ordered by descending executionDate.
FOUR_TRANSACTIONS = [
# First transaction will be after date_until.
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "1552c32f-e63f-4ce6-a974-f270e6cd53a9",
"attributes": {
"valueDate": "2019-12-04T12:30:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Arresto Momentum",
"executionDate": "2019-12-04T10:25:00.000Z",
"description": "Wire transfer after execution",
"currency": "EUR",
"counterpartReference": "BE10325927501996",
"counterpartName": "Some other customer",
"amount": 8.95,
},
},
# Next transaction has valueDate before, executionDate after date_until.
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "701ab965-21c4-46ca-b157-306c0646e0e2",
"attributes": {
"valueDate": "2019-11-18T00:00:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Minima vitae totam!",
"executionDate": "2019-11-20T00:00:00.000Z",
"description": "Wire transfer",
"currency": "EUR",
"counterpartReference": "BE26089479973169",
"counterpartName": "Osinski Group",
"amount": 6.08,
},
},
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "9ac50483-16dc-4a82-aa60-df56077405cd",
"attributes": {
"valueDate": "2019-11-04T00:00:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Quia voluptatem blanditiis.",
"executionDate": "2019-11-06T00:00:00.000Z",
"description": "Wire transfer",
"currency": "EUR",
"counterpartReference": "BE97201830401438",
"counterpartName": "Stokes-Miller",
"amount": 5.48,
},
},
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "b21a6c65-1c52-4ba6-8cbc-127d2b2d85ff",
"attributes": {
"valueDate": "2019-11-04T00:00:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Laboriosam repelo?",
"executionDate": "2019-11-04T00:00:00.000Z",
"description": "Wire transfer",
"currency": "EUR",
"counterpartReference": "BE10325927501996",
"counterpartName": "Strosin-Veum",
"amount": 5.83,
},
},
]
EMPTY_TRANSACTIONS = []
EARLY_TRANSACTIONS = [
# First transaction in october 2019, month before other transactions.
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "1552c32f-e63f-4ce6-a974-f270e6cd5301",
"attributes": {
"valueDate": "2019-10-04T12:29:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Arresto Momentum",
"executionDate": "2019-10-04T10:24:00.000Z",
"description": "Wire transfer after execution",
"currency": "EUR",
"counterpartReference": "BE10325927501996",
"counterpartName": "Some other customer",
"amount": 4.25,
},
},
# Second transaction in september 2019.
{
"type": "transaction",
"relationships": {
"account": {
"links": {"related": "https://api.myponto.com/accounts/"},
"data": {
"type": "account",
"id": "fd3d5b1d-fca9-4310-a5c8-76f2a9dc7c75",
},
}
},
"id": "701ab965-21c4-46ca-b157-306c0646e002",
"attributes": {
"valueDate": "2019-09-18T01:00:00.000Z",
"remittanceInformationType": "unstructured",
"remittanceInformation": "Minima vitae totam!",
"executionDate": "2019-09-20T01:00:00.000Z",
"description": "Wire transfer",
"currency": "EUR",
"counterpartReference": "BE26089479973169",
"counterpartName": "Osinski Group",
"amount": 4.08,
},
},
]
transaction_amounts = [5.48, 5.83, 6.08, 8.95]
class TestAccountStatementImportOnlinePonto(common.TransactionCase):
post_install = True
def setUp(self):
super().setUp()
self.now = fields.Datetime.now()
self.currency_eur = self.env.ref("base.EUR")
self.currency_usd = self.env.ref("base.USD")
self.AccountJournal = self.env["account.journal"]
self.ResPartnerBank = self.env["res.partner.bank"]
self.OnlineBankStatementProvider = self.env["online.bank.statement.provider"]
self.AccountBankStatement = self.env["account.bank.statement"]
self.AccountBankStatementLine = self.env["account.bank.statement.line"]
self.AccountStatementPull = self.env["online.bank.statement.pull.wizard"]
self.currency_eur.write({"active": True})
self.bank_account = self.ResPartnerBank.create(
{
"acc_number": "FR0214508000302245362775K46",
"partner_id": self.env.user.company_id.partner_id.id,
}
)
self.journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"currency_id": self.currency_eur.id,
"bank_statements_source": "online",
"bank_account_id": self.bank_account.id,
}
)
self.provider = self.OnlineBankStatementProvider.create(
{
"name": "Ponto Provider",
"service": "ponto",
"journal_id": self.journal.id,
# To get all the moves in a month at once
"statement_creation_mode": "monthly",
}
)
self.mock_login = lambda: mock.patch(
_interface_class + "._login",
return_value={
"username": "test_user",
"password": "very_secret",
"access_token": "abcd1234",
"token_expiration": datetime(2099, 12, 31, 23, 59, 59),
},
)
self.mock_set_access_account = lambda: mock.patch(
_interface_class + "._set_access_account",
return_value=None,
)
# return list of transactions on first call, empty list on second call.
self.mock_get_transactions = lambda: mock.patch(
_interface_class + "._get_transactions",
side_effect=[
FOUR_TRANSACTIONS,
EMPTY_TRANSACTIONS,
],
)
# return two times list of transactions, empty list on third call.
self.mock_get_transactions_multi = lambda: mock.patch(
_interface_class + "._get_transactions",
side_effect=[
FOUR_TRANSACTIONS,
EARLY_TRANSACTIONS,
EMPTY_TRANSACTIONS,
],
)
def test_balance_start(self):
"""Test wether end balance of last statement, taken as start balance of new."""
statement_date = datetime(2019, 11, 1)
data = self._get_statement_line_data(statement_date)
self.provider.statement_creation_mode = "daily"
self.provider._create_or_update_statement(
data, statement_date, datetime(2019, 11, 2)
)
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
vals = {
"date_since": datetime(2019, 11, 4),
"date_until": datetime(2019, 11, 5),
}
wizard = self.AccountStatementPull.with_context(
active_model=self.provider._name,
active_id=self.provider.id,
).create(vals)
wizard.action_pull()
statements = self.AccountBankStatement.search(
[("journal_id", "=", self.journal.id)], order="name"
)
self.assertEqual(len(statements), 2)
new_statement = statements[1]
self.assertEqual(len(new_statement.line_ids), 1)
self.assertEqual(new_statement.balance_start, 100)
self.assertEqual(new_statement.balance_end, 105.83)
def test_ponto_execution_date(self):
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
# First base selection on execution date.
self.provider.ponto_date_field = "execution_date"
statement = self._get_statements_from_wizard() # Will get 1 statement
self._check_line_count(statement.line_ids, expected_count=2)
self._check_statement_amounts(statement, transaction_amounts[:2])
def test_ponto_value_date(self):
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
# First base selection on execution date.
self.provider.ponto_date_field = "value_date"
statement = self._get_statements_from_wizard() # Will get 1 statement
self._check_line_count(statement.line_ids, expected_count=3)
self._check_statement_amounts(statement, transaction_amounts[:3])
def test_ponto_get_transactions_multi(self):
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions_multi(),
): # noqa: B950
# First base selection on execution date.
self.provider.ponto_date_field = "execution_date"
# Expect statements for october and november.
statements = self._get_statements_from_wizard(
expected_statement_count=2, date_since=datetime(2019, 9, 25)
)
self._check_line_count(statements[0].line_ids, expected_count=1) # october
self._check_line_count(statements[1].line_ids, expected_count=2) # november
self._check_statement_amounts(statements[0], [4.25])
self._check_statement_amounts(
statements[1],
transaction_amounts[:2],
expected_balance_end=15.56, # Includes 4.25 from statement before.
)
def test_ponto_scheduled(self):
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
# Scheduled should get all transaction, ignoring date_until.
self.provider.ponto_last_identifier = False
date_since = datetime(2019, 11, 3)
date_until = datetime(2019, 11, 18)
self.provider.with_context(scheduled=True)._pull(date_since, date_until)
statements = self._get_statements_from_journal(expected_count=2)
self._check_line_count(statements[0].line_ids, expected_count=3)
self._check_statement_amounts(statements[0], transaction_amounts[:3])
self._check_line_count(statements[1].line_ids, expected_count=1)
# Expected balance_end will include amounts of previous statement.
self._check_statement_amounts(
statements[1], transaction_amounts[3:], expected_balance_end=26.34
)
def test_ponto_scheduled_from_identifier(self):
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
# Scheduled should get all transactions after last identifier.
self.provider.ponto_last_identifier = "9ac50483-16dc-4a82-aa60-df56077405cd"
date_since = datetime(2019, 11, 3)
date_until = datetime(2019, 11, 18)
self.provider.with_context(scheduled=True)._pull(date_since, date_until)
# First two transactions for statement 0 should have been ignored.
statements = self._get_statements_from_journal(expected_count=2)
self._check_line_count(statements[0].line_ids, expected_count=1)
self._check_statement_amounts(statements[0], transaction_amounts[2:3])
self._check_line_count(statements[1].line_ids, expected_count=1)
# Expected balance_end will include amounts of previous statement.
self._check_statement_amounts(
statements[1], transaction_amounts[3:], expected_balance_end=15.03
)
def _get_statements_from_wizard(self, expected_statement_count=1, date_since=None):
"""Run wizard to pull data and return statement."""
date_since = date_since if date_since else datetime(2019, 11, 3)
vals = {
"date_since": date_since,
"date_until": datetime(2019, 11, 18),
}
wizard = self.AccountStatementPull.with_context(
active_model=self.provider._name,
active_id=self.provider.id,
).create(vals)
wizard.action_pull()
return self._get_statements_from_journal(
expected_count=expected_statement_count
)
def _get_statements_from_journal(self, expected_count=0):
"""We only expect statements created by our tests."""
statements = self.AccountBankStatement.search(
[("journal_id", "=", self.journal.id)],
order="date asc",
)
self.assertEqual(len(statements), expected_count)
return statements
def _check_line_count(self, lines, expected_count=0):
"""Check wether lines contain expected number of transactions.
If count differs, show the unique id's of lines that are present.
"""
# If we do not get all lines, show lines we did get:
line_count = len(lines)
if line_count != expected_count:
_logger.info(
_("Statement contains transactions: %s"),
" ".join(lines.mapped("unique_import_id")),
)
self.assertEqual(line_count, expected_count)
def _check_statement_amounts(
self, statement, expected_amounts, expected_balance_end=0.0
):
"""Check wether amount in lines and end_balance as expected."""
sorted_amounts = sorted([round(line.amount, 2) for line in statement.line_ids])
sorted_expected_amounts = sorted(
[round(amount, 2) for amount in expected_amounts]
)
self.assertEqual(sorted_amounts, sorted_expected_amounts)
if not expected_balance_end:
expected_balance_end = sum(expected_amounts)
self.assertEqual(
round(statement.balance_end, 2), round(expected_balance_end, 2)
)
def _get_statement_line_data(self, statement_date):
return [
{
"payment_ref": "payment",
"amount": 100,
"date": statement_date,
"unique_import_id": str(statement_date),
"partner_name": "John Doe",
"account_number": "XX00 0000 0000 0000",
}
], {}
def test_wizard_action_debug(self):
"""Debug data is returned properly."""
statement_date = datetime(2019, 11, 1)
data = self._get_statement_line_data(statement_date)
self.provider.statement_creation_mode = "daily"
self.provider._create_or_update_statement(
data, statement_date, datetime(2019, 11, 2)
)
with (
self.mock_login(),
self.mock_set_access_account(),
self.mock_get_transactions(),
): # noqa: B950
vals = {
"date_since": datetime(2019, 11, 4),
"date_until": datetime(2019, 11, 5),
}
wizard = self.AccountStatementPull.with_context(
active_model=self.provider._name,
active_id=self.provider.id,
).create(vals)
action = wizard.action_debug()
debug_wizard = self.env[action["res_model"]].browse(action["res_id"])
self.assertIn("Laboriosam repelo", debug_wizard.data)

View File

@@ -0,0 +1,98 @@
# Copyright 2022 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import json
from unittest.mock import MagicMock, patch
from dateutil.relativedelta import relativedelta
from odoo import fields
from odoo.tests import common
from .test_account_statement_import_online_ponto import FOUR_TRANSACTIONS
class TestPontoInterface(common.TransactionCase):
post_install = True
@patch("requests.post")
def test_login(self, requests_post):
"""Check Ponto API login."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.text = json.dumps(
{
"access_token": "live_the_token",
"expires_in": 1799,
"scope": "ai",
"token_type": "bearer",
}
)
requests_post.return_value = mock_response
interface_model = self.env["ponto.interface"]
access_data = interface_model._login("uncle_john", "secret")
self.assertEqual(access_data["access_token"], "live_the_token")
self.assertIn("token_expiration", access_data)
@patch("requests.get")
def test_set_access_account(self, requests_get):
"""Test getting account data for Ponto access."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.text = json.dumps(
{
"data": [
{
"id": "wrong_id",
"attributes": {
"reference": "NL66ABNA123456789",
},
},
{
"id": "2ad3df83-be01-47cf-a6be-cf0de5cb4c99",
"attributes": {
"reference": "NL66RABO123456789",
},
},
],
}
)
requests_get.return_value = mock_response
# Start of actual test.
access_data = self._get_access_dict(include_account=False)
interface_model = self.env["ponto.interface"]
interface_model._set_access_account(access_data, "NL66RABO123456789")
self.assertIn("ponto_account", access_data)
self.assertEqual(
access_data["ponto_account"], "2ad3df83-be01-47cf-a6be-cf0de5cb4c99"
)
@patch("requests.get")
def test_get_transactions(self, requests_get):
"""Test getting transactions from Ponto."""
mock_response = MagicMock()
mock_response.status_code = 200
# Key "data" will contain a list of transactions.
mock_response.text = json.dumps({"data": FOUR_TRANSACTIONS})
requests_get.return_value = mock_response
# Start of actual test.
access_data = self._get_access_dict()
interface_model = self.env["ponto.interface"]
transactions = interface_model._get_transactions(access_data, False)
self.assertEqual(len(transactions), 4)
self.assertEqual(transactions[3]["id"], "b21a6c65-1c52-4ba6-8cbc-127d2b2d85ff")
self.assertEqual(
transactions[3]["attributes"]["counterpartReference"], "BE10325927501996"
)
def _get_access_dict(self, include_account=True):
"""Get access dict that caches login/account information."""
token_expiration = fields.Datetime.now() + relativedelta(seconds=1800)
access_data = {
"username": "uncle_john",
"password": "secret",
"access_token": "live_the_token",
"token_expiration": token_expiration,
}
if include_account:
access_data["ponto_account"] = "2ad3df83-be01-47cf-a6be-cf0de5cb4c99"
return access_data

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="online_bank_statement_provider_form">
<field name="name">online.bank.statement.provider.form</field>
<field name="model">online.bank.statement.provider</field>
<field
name="inherit_id"
ref="account_statement_import_online.online_bank_statement_provider_form"
/>
<field name="arch" type="xml">
<xpath expr="//group[@name='main']" position="inside">
<group
name="ponto"
string="Ponto Config"
invisible="service != 'ponto'"
>
<field name="username" string="Login" />
<field name="password" string="Secret Key" />
<field name="ponto_date_field" />
<field name="ponto_last_identifier" />
</group>
</xpath>
</field>
</record>
</odoo>