diff --git a/account_bank_statement_import_adyen/models/account_bank_statement_import.py b/account_bank_statement_import_adyen/models/account_bank_statement_import.py index 0ba9b7ba..4df68c57 100644 --- a/account_bank_statement_import_adyen/models/account_bank_statement_import.py +++ b/account_bank_statement_import_adyen/models/account_bank_statement_import.py @@ -16,8 +16,18 @@ class AccountBankStatementImport(models.TransientModel): def _parse_file(self, data_file): """Parse an Adyen xlsx file and map merchant account strings to journals.""" try: - return self.import_adyen_xlsx(data_file) + try: + return self._parse_adyen_file(data_file) + except Exception as exc: + if self.env.context.get("account_bank_statement_import_adyen", False): + raise + _logger.info("Adyen parser error", exc_info=True) + raise ValueError("Not an adyen settlements file: %s" % exc) except ValueError: + _logger.debug( + _("Statement file was not a Adyen settlement details file."), + exc_info=True, + ) return super()._parse_file(data_file) def _find_additional_data(self, currency_code, account_number): @@ -40,25 +50,25 @@ class AccountBankStatementImport(models.TransientModel): return super()._find_additional_data(currency_code, account_number) @api.model - def balance(self, row): + def _balance(self, row): return -(float(row[15]) if row[15] else 0.0) + sum( float(row[i]) if row[i] else 0.0 for i in (16, 17, 18, 19, 20) ) @api.model - def import_adyen_transaction(self, statement, statement_id, row): + def _import_adyen_transaction(self, statement, statement_id, row): transaction_id = str(len(statement["transactions"])).zfill(4) transaction = dict( unique_import_id=statement_id + transaction_id, date=fields.Date.from_string(row[6]), - amount=self.balance(row), + amount=self._balance(row), note="{} {} {} {}".format(row[2], row[3], row[4], row[21]), name="%s" % (row[3] or row[4] or row[9]), ) statement["transactions"].append(transaction) @api.model - def parse_adyen_file(self, data_file): + def _parse_adyen_file(self, data_file): statements = [] statement = None headers = False @@ -70,6 +80,9 @@ class AccountBankStatementImport(models.TransientModel): import_model = self.env["base_import.import"] importer = import_model.create( {"file": data_file, "file_name": "Ayden settlemnt details"} + import_model = self.env["base_import.import"] + importer = import_model.create( + {"file": data_file, "file_name": "Ayden settlement details"} ) rows = importer._read_file({}) @@ -105,10 +118,10 @@ class AccountBankStatementImport(models.TransientModel): row[8] = row[8].strip() if row[8] == "MerchantPayout": - payout -= self.balance(row) + payout -= self._balance(row) else: - balance += self.balance(row) - self.import_adyen_transaction(statement, statement_id, row) + balance += self._balance(row) + self._import_adyen_transaction(statement, statement_id, row) fees += sum(float(row[i]) if row[i] else 0.0 for i in (17, 18, 19, 20)) if not headers: diff --git a/account_bank_statement_import_adyen/tests/test_import_adyen.py b/account_bank_statement_import_adyen/tests/test_import_adyen.py index 1fc5418f..ca75591a 100644 --- a/account_bank_statement_import_adyen/tests/test_import_adyen.py +++ b/account_bank_statement_import_adyen/tests/test_import_adyen.py @@ -23,9 +23,6 @@ class TestImportAdyen(SavepointCase): "currency_id": cls.env.ref("base.USD").id, } ) - # Enable reconcilation on the default journal account to trigger - # the functionality from account_bank_statement_clearing_account - cls.journal.default_debit_account_id.reconcile = True def test_01_import_adyen(self): """ Test that the Adyen statement can be imported and that the @@ -68,7 +65,9 @@ class TestImportAdyen(SavepointCase): import_wizard = self.env["account.bank.statement.import"].create( {"attachment_ids": [(0, 0, {"name": "test file", "datas": data_file})]} ) - import_wizard.import_file() + import_wizard.with_context( + {"account_bank_statement_import_adyen": True} + ).import_file() # statement name is account number + '-' + date of last line: statements = self.env["account.bank.statement"].search( [("name", "=", statement_name)] diff --git a/account_bank_statement_import_online_adyen/README.rst b/account_bank_statement_import_online_adyen/README.rst new file mode 100644 index 00000000..32b36ef1 --- /dev/null +++ b/account_bank_statement_import_online_adyen/README.rst @@ -0,0 +1,118 @@ +============================================ +Online Bank Statements: Adyen payment report +============================================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/13.0/account_bank_statement_import_online_adyen + :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-13-0/bank-statement-import-13-0-account_bank_statement_import_online_adyen + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/174/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module automates the download and import of Adyen payment reports. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure online bank statements provider: + +#. Go to *Invoicing > Configuration > Bank Accounts* +#. Open bank account to configure and edit it +#. Set *Bank Feeds* to *Online* +#. Select *Adyen* as online bank statements provider in + *Online Bank Statements (OCA)* section +#. Save the bank account +#. Click on provider and configure provider-specific settings. + +or, alternatively: + +#. Go to *Invoicing > Overview* +#. Open settings of the corresponding journal account +#. Switch to *Bank Account* tab +#. Set *Bank Feeds* to *Online* +#. Select *Adyen* as online bank statements provider in + *Online Bank Statements (OCA)* section +#. Save the bank account +#. Click on provider and configure provider-specific settings. + +To obtain *Login* and *Key*: + +#. Open `Adyen website `_. + +Check also ``account_bank_statement_import_online`` configuration instructions +for more information. + +Usage +===== + +To pull historical bank statements: + +#. Go to *Invoicing > Configuration > Bank Accounts* +#. Select specific bank accounts +#. Launch *Actions > Online Bank Statements Pull Wizard* +#. 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 `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Ronald Portier (Therp BV) + +Contributors +~~~~~~~~~~~~ + +* Ronald Portier - Therp BV + +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_bank_statement_import_online_adyen/__init__.py b/account_bank_statement_import_online_adyen/__init__.py new file mode 100644 index 00000000..ad8c8648 --- /dev/null +++ b/account_bank_statement_import_online_adyen/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import models +from .tests import online_bank_statement_provider_dummy diff --git a/account_bank_statement_import_online_adyen/__manifest__.py b/account_bank_statement_import_online_adyen/__manifest__.py new file mode 100644 index 00000000..52ae345b --- /dev/null +++ b/account_bank_statement_import_online_adyen/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2021 - Therp BV . +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Online Bank Statements: Adyen payment report", + "version": "13.0.1.0.0", + "category": "Account", + "website": "https://github.com/OCA/bank-statement-import", + "author": "Ronald Portier (Therp BV), Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": [ + "account_bank_statement_import_adyen", + "account_bank_statement_import_online", + ], + "data": ["views/online_bank_statement_provider.xml"], +} diff --git a/account_bank_statement_import_online_adyen/models/__init__.py b/account_bank_statement_import_online_adyen/models/__init__.py new file mode 100644 index 00000000..56bd827c --- /dev/null +++ b/account_bank_statement_import_online_adyen/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import account_journal +from . import online_bank_statement_provider diff --git a/account_bank_statement_import_online_adyen/models/account_journal.py b/account_bank_statement_import_online_adyen/models/account_journal.py new file mode 100644 index 00000000..fb7572a3 --- /dev/null +++ b/account_bank_statement_import_online_adyen/models/account_journal.py @@ -0,0 +1,30 @@ +# Copyright 2021 Therp BV . +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, models + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + def write(self, vals): + """Do not reset a provider to file_import, if that will delete provider.""" + # TODO: In the future place this in super account_bank_statement_import_online. + for this in self: + is_online = this.bank_statements_source == "online" + if is_online and vals.get("bank_statements_source", "online") != "online": + vals.pop("bank_statements_source") + super(AccountJournal, this).write(vals) + return True + + @api.model + def _selection_online_bank_statement_provider(self): + res = super()._selection_online_bank_statement_provider() + res.append(("dummy_adyen", "Dummy Adyen")) + return res + + @api.model + def values_online_bank_statement_provider(self): + res = super().values_online_bank_statement_provider() + if self.user_has_groups("base.group_no_one"): + res += [("dummy_adyen", "Dummy Adyen")] + return res diff --git a/account_bank_statement_import_online_adyen/models/online_bank_statement_provider.py b/account_bank_statement_import_online_adyen/models/online_bank_statement_provider.py new file mode 100644 index 00000000..62a9babd --- /dev/null +++ b/account_bank_statement_import_online_adyen/models/online_bank_statement_provider.py @@ -0,0 +1,100 @@ +# Copyright 2021 Therp BV . +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging +from html import escape + +import requests + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + + +class OnlineBankStatementProvider(models.Model): + _inherit = "online.bank.statement.provider" + + download_file_name = fields.Char() + next_batch_number = fields.Integer() + + @api.model + def _selection_service(self): + res = super()._selection_service() + res.append(("dummy_adyen", "Dummy Adyen")) + return res + + @api.model + def _get_available_services(self): + return super()._get_available_services() + [("adyen", "Adyen payment report")] + + def _pull(self, date_since, date_until): # noqa: C901 + """Split between adyen providers and others.""" + adyen_providers = self.filtered(lambda r: r.service in ("adyen", "dummy_adyen")) + other_providers = self.filtered( + lambda r: r.service not in ("adyen", "dummy_adyen") + ) + if other_providers: + super(OnlineBankStatementProvider, other_providers)._pull( + date_since, date_until + ) + for provider in adyen_providers: + # TODO: incrementing batch number + is_scheduled = self.env.context.get("scheduled") + try: + data_file = self._adyen_get_settlement_details_file() + import_wizard = self.env["account.bank.statement.import"].create( + { + "attachment_ids": [ + (0, 0, {"name": "test file", "datas": data_file}) + ] + } + ) + import_wizard.with_context( + {"account_bank_statement_import_adyen": True} + ).import_file() + except BaseException as e: + if is_scheduled: + _logger.warning( + 'Online Bank Statement Provider "%s" failed to' + " obtain statement data" % (provider.name,), + exc_info=True, + ) + provider.message_post( + body=_( + "Failed to obtain statement data for period " + ": %s. See server logs for more details." + ) + % (escape(str(e)) or _("N/A"),), + subject=_("Issue with Online Bank Statement Provider"), + ) + break + raise + if is_scheduled: + provider._schedule_next_run() + + def _adyen_get_settlement_details_file(self): + """Retrieve daily generated settlement details file. + + The file could be retrieved with wget using: + $ wget \ + --http-user='[YourReportUser]@Company.[YourCompanyAccount]' \ + --http-password='[YourReportUserPassword]' \ + --quiet --no-check-certificate \ + https://ca-test.adyen.com/reports/download/MerchantAccount/ + + [YourMerchantAccount]/[ReportFileName]" + """ + batch_number = self.next_batch_number + download_file_name = self.download_file_name % batch_number + URL = "/".join( + [self.api_base, self.journal_id.adyen_merchant_account, download_file_name] + ) + response = requests.get(URL, auth=(self.username, self.password)) + if response.status_code == 200: + return response.content + else: + raise UserError(_("%s \n\n %s") % (response.status_code, response.text)) + + def _schedule_next_run(self): + """Set next run date and autoincrement batch number.""" + super()._schedule_next_run() + self.next_batch_number += 1 diff --git a/account_bank_statement_import_online_adyen/readme/CONFIGURE.rst b/account_bank_statement_import_online_adyen/readme/CONFIGURE.rst new file mode 100644 index 00000000..da06dd2c --- /dev/null +++ b/account_bank_statement_import_online_adyen/readme/CONFIGURE.rst @@ -0,0 +1,27 @@ +To configure online bank statements provider: + +#. Go to *Invoicing > Configuration > Bank Accounts* +#. Open bank account to configure and edit it +#. Set *Bank Feeds* to *Online* +#. Select *Adyen* as online bank statements provider in + *Online Bank Statements (OCA)* section +#. Save the bank account +#. Click on provider and configure provider-specific settings. + +or, alternatively: + +#. Go to *Invoicing > Overview* +#. Open settings of the corresponding journal account +#. Switch to *Bank Account* tab +#. Set *Bank Feeds* to *Online* +#. Select *Adyen* as online bank statements provider in + *Online Bank Statements (OCA)* section +#. Save the bank account +#. Click on provider and configure provider-specific settings. + +To obtain *Login* and *Key*: + +#. Open `Adyen website `_. + +Check also ``account_bank_statement_import_online`` configuration instructions +for more information. diff --git a/account_bank_statement_import_online_adyen/readme/CONTRIBUTORS.rst b/account_bank_statement_import_online_adyen/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..6ee4d1d6 --- /dev/null +++ b/account_bank_statement_import_online_adyen/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Ronald Portier - Therp BV diff --git a/account_bank_statement_import_online_adyen/readme/DESCRIPTION.rst b/account_bank_statement_import_online_adyen/readme/DESCRIPTION.rst new file mode 100644 index 00000000..fc01c0c4 --- /dev/null +++ b/account_bank_statement_import_online_adyen/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module automates the download and import of Adyen payment reports. diff --git a/account_bank_statement_import_online_adyen/readme/USAGE.rst b/account_bank_statement_import_online_adyen/readme/USAGE.rst new file mode 100644 index 00000000..2785a201 --- /dev/null +++ b/account_bank_statement_import_online_adyen/readme/USAGE.rst @@ -0,0 +1,10 @@ +To pull historical bank statements: + +#. Go to *Invoicing > Configuration > Bank Accounts* +#. Select specific bank accounts +#. Launch *Actions > Online Bank Statements Pull Wizard* +#. 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. diff --git a/account_bank_statement_import_online_adyen/static/description/icon.png b/account_bank_statement_import_online_adyen/static/description/icon.png new file mode 100644 index 00000000..09847ed7 Binary files /dev/null and b/account_bank_statement_import_online_adyen/static/description/icon.png differ diff --git a/account_bank_statement_import_online_adyen/static/description/index.html b/account_bank_statement_import_online_adyen/static/description/index.html new file mode 100644 index 00000000..beccd682 --- /dev/null +++ b/account_bank_statement_import_online_adyen/static/description/index.html @@ -0,0 +1,464 @@ + + + + + + +Online Bank Statements: Adyen payment report + + + +
+

Online Bank Statements: Adyen payment report

+ + +

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

+

This module automates the download and import of Adyen payment reports.

+

Table of contents

+ +
+

Configuration

+

To configure online bank statements provider:

+
    +
  1. Go to Invoicing > Configuration > Bank Accounts
  2. +
  3. Open bank account to configure and edit it
  4. +
  5. Set Bank Feeds to Online
  6. +
  7. Select Adyen as online bank statements provider in +Online Bank Statements (OCA) section
  8. +
  9. Save the bank account
  10. +
  11. Click on provider and configure provider-specific settings.
  12. +
+

or, alternatively:

+
    +
  1. Go to Invoicing > Overview
  2. +
  3. Open settings of the corresponding journal account
  4. +
  5. Switch to Bank Account tab
  6. +
  7. Set Bank Feeds to Online
  8. +
  9. Select Adyen as online bank statements provider in +Online Bank Statements (OCA) section
  10. +
  11. Save the bank account
  12. +
  13. Click on provider and configure provider-specific settings.
  14. +
+

To obtain Login and Key:

+
    +
  1. Open Adyen website.
  2. +
+

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. +
  3. Select specific bank accounts
  4. +
  5. Launch Actions > Online Bank Statements Pull Wizard
  6. +
  7. Configure date interval and click 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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Ronald Portier (Therp BV)
  • +
+
+
+

Contributors

+
    +
  • Ronald Portier - Therp BV
  • +
+
+
+

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_bank_statement_import_online_adyen/tests/__init__.py b/account_bank_statement_import_online_adyen/tests/__init__.py new file mode 100644 index 00000000..e889bae2 --- /dev/null +++ b/account_bank_statement_import_online_adyen/tests/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import test_import_online diff --git a/account_bank_statement_import_online_adyen/tests/online_bank_statement_provider_dummy.py b/account_bank_statement_import_online_adyen/tests/online_bank_statement_provider_dummy.py new file mode 100644 index 00000000..9c42c0aa --- /dev/null +++ b/account_bank_statement_import_online_adyen/tests/online_bank_statement_provider_dummy.py @@ -0,0 +1,23 @@ +# Copyright 2021 Therp BV . +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import base64 + +from odoo import models +from odoo.modules.module import get_module_resource + + +class OnlineBankStatementProviderDummy(models.Model): + _inherit = "online.bank.statement.provider" + + def _adyen_get_settlement_details_file(self): + """Get file from disk, instead of from url.""" + if self.service != "dummy_adyen": + # Not a dummy, get the regular adyen method. + return super()._adyen_get_settlement_details_file() + testfile = get_module_resource( + "account_bank_statement_import_adyen", "test_files", self.download_file_name + ) + with open(testfile, "rb") as datafile: + data_file = datafile.read() + data_file = base64.b64encode(data_file) + return data_file diff --git a/account_bank_statement_import_online_adyen/tests/test_import_online.py b/account_bank_statement_import_online_adyen/tests/test_import_online.py new file mode 100644 index 00000000..71c0d765 --- /dev/null +++ b/account_bank_statement_import_online_adyen/tests/test_import_online.py @@ -0,0 +1,66 @@ +# Copyright 2021 Therp BV . +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from dateutil.relativedelta import relativedelta + +from odoo import fields + +from odoo.addons.account_bank_statement_import_adyen.tests.test_import_adyen import ( + TestImportAdyen, +) + + +class TestImportOnline(TestImportAdyen): + """Do the same tests as with the offline adyen import.""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.now = fields.Datetime.now() + cls.journal.write( + { + "bank_statements_source": "online", + "online_bank_statement_provider": "dummy_adyen", + } + ) + + def test_03_import_adyen_invalid(self): + """Override super test: online module test will return without statements.""" + with self.assertRaisesRegex(AssertionError, "account.bank.statement()"): + self._test_statement_import( + "adyen_test_invalid.xls", "invalid", + ) + + def _test_statement_import(self, file_name, statement_name): + """Test correct creation of single statement. + + Getting an adyen statement online should result in: + 1. A valid imported statement; + 2. An incremented batch number; + 3. The current date being set as the date_since in the provider. + """ + provider = self.journal.online_bank_statement_provider_id + provider.write( + { + "api_base": ( + "https://ca-test.adyen.com/reports/download/MerchantAccount" + ), + "download_file_name": file_name, + "interval_type": "days", + "interval_number": 1, + "service": "dummy_adyen", + "next_batch_number": 1, + } + ) + # Pull from yesterday, until today + yesterday = self.now - relativedelta(days=1) + provider.with_context(scheduled=True)._pull(yesterday, self.now) + # statement name is account number + '-' + date of last line: + statements = self.env["account.bank.statement"].search( + [("name", "=", statement_name)] + ) + self.assertTrue(statements) + self.assertEqual(len(statements), 1) + self.assertEqual(provider.next_batch_number, 2) + self.assertEqual(provider.last_successful_run, self.now) + self.assertTrue(provider.next_run > self.now) + return statements diff --git a/account_bank_statement_import_online_adyen/views/online_bank_statement_provider.xml b/account_bank_statement_import_online_adyen/views/online_bank_statement_provider.xml new file mode 100644 index 00000000..294c7769 --- /dev/null +++ b/account_bank_statement_import_online_adyen/views/online_bank_statement_provider.xml @@ -0,0 +1,28 @@ + + + + online.bank.statement.provider.form + online.bank.statement.provider + + + + + + + + + + + + + +