diff --git a/account_invoice_download_scaleway/README.rst b/account_invoice_download_scaleway/README.rst new file mode 100644 index 0000000000..699c91e7b6 --- /dev/null +++ b/account_invoice_download_scaleway/README.rst @@ -0,0 +1 @@ +will be auto-generated from readme subdir diff --git a/account_invoice_download_scaleway/__init__.py b/account_invoice_download_scaleway/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/account_invoice_download_scaleway/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_invoice_download_scaleway/__manifest__.py b/account_invoice_download_scaleway/__manifest__.py new file mode 100644 index 0000000000..79f0c856eb --- /dev/null +++ b/account_invoice_download_scaleway/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2023 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Account Invoice Download Scaleway", + "version": "14.0.1.0.0", + "category": "Accounting", + "license": "AGPL-3", + "summary": "Get Scaleway Invoices via the API", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/edi", + "depends": ["account_invoice_download"], + "data": [ + "views/account_invoice_download_config.xml", + ], + "demo": ["demo/scaleway.xml"], + "installable": True, + "application": True, +} diff --git a/account_invoice_download_scaleway/demo/scaleway.xml b/account_invoice_download_scaleway/demo/scaleway.xml new file mode 100644 index 0000000000..d1e6d9827a --- /dev/null +++ b/account_invoice_download_scaleway/demo/scaleway.xml @@ -0,0 +1,17 @@ + + + + + Scaleway SAS + + 1 + 8 rue de la Ville-l'Évêque + 75008 + Paris + + +33 1 84 13 00 00 + www.scaleway.com + FR35433115904 + + + diff --git a/account_invoice_download_scaleway/models/__init__.py b/account_invoice_download_scaleway/models/__init__.py new file mode 100644 index 0000000000..695eb4d41b --- /dev/null +++ b/account_invoice_download_scaleway/models/__init__.py @@ -0,0 +1 @@ +from . import account_invoice_download_config diff --git a/account_invoice_download_scaleway/models/account_invoice_download_config.py b/account_invoice_download_scaleway/models/account_invoice_download_config.py new file mode 100644 index 0000000000..973f68b115 --- /dev/null +++ b/account_invoice_download_scaleway/models/account_invoice_download_config.py @@ -0,0 +1,127 @@ +# Copyright 2023 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +import requests +from dateutil.relativedelta import relativedelta + +from odoo import _, fields, models +from odoo.exceptions import UserError + +logger = logging.getLogger(__name__) +URL_BASE = "https://api.scaleway.com/billing/v2alpha1" + + +class AccountInvoiceDownloadConfig(models.Model): + _inherit = "account.invoice.download.config" + + backend = fields.Selection( + selection_add=[("scaleway", "Scaleway")], ondelete={"scaleway": "set null"} + ) + scaleway_secret_key = fields.Char(string="Scaleway Secret Key") + + def prepare_credentials(self): + credentials = super().prepare_credentials() + if self.backend == "scaleway": + credentials = {"secret_key": self.scaleway_secret_key} + return credentials + + def credentials_stored(self): + if self.backend == "scaleway": + if self.scaleway_secret_key: + return True + else: + raise UserError(_("You must set the Scaleway Secret key.")) + return super().credentials_stored() + + def download(self, credentials, logs): + if self.backend == "scaleway": + return self.scaleway_download(credentials, logs) + return super().download(credentials, logs) + + def _scaleway_invoice_attach_pdf(self, parsed_inv, invoice_id, headers): + logger.info( + "Starting to download PDF of Scaleway invoice %s dated %s", + parsed_inv["invoice_number"], + parsed_inv["date"], + ) + pdf_invoice_url = "%s/invoices/%s/download" % (URL_BASE, invoice_id) + logger.debug("Scaleway invoice download url: %s", pdf_invoice_url) + rpdf = requests.get(pdf_invoice_url, headers=headers) + logger.info("Scaleway invoice PDF download HTTP code: %s", rpdf.status_code) + if rpdf.status_code == 200: + rpdf_json = rpdf.json() + logger.info( + "Successfull download of the PDF of the Scaleway invoice %s", + parsed_inv["invoice_number"], + ) + filename = rpdf_json["name"] + parsed_inv["attachments"] = {filename: rpdf_json["content"]} + else: + logger.warning( + "Could not download the PDF of the Scaleway invoice %s. HTTP error %d", + parsed_inv["invoice_number"], + rpdf.status_code, + ) + + def scaleway_download(self, credentials, logs): + invoices = [] + logger.info("Start to download Scaleway invoices with config %s", self.name) + headers = { + "Content-type": "application/json", + "X-Auth-Token": credentials["secret_key"], + } + params = {"page_size": 50} + if self.download_start_date: + params["started_after"] = "%sT00:00:00Z" % self.download_start_date + list_url = "%s/invoices" % URL_BASE + logger.info("Starting Scaleway API query on %s", list_url) + logger.debug("URL params=%s", params) + try: + res_ilist = requests.get(list_url, headers=headers, params=params) + except Exception as e: + logs["msg"].append( + _("Cannot connect to the Scaleway API. Error message: '%s'.") % str(e) + ) + logs["result"] = "failure" + return [] + ilist_json = res_ilist.json() + logger.debug("Result of invoice list: %s", ilist_json) + for inv in ilist_json.get("invoices", []): + if not inv.get("number"): + logger.info( + "Skipping scaleway invoice ID %s because it is a draft invoice", + inv.get("id"), + ) + continue + untaxed = inv["total_untaxed"] + currency_code = untaxed["currency_code"] + amount_untaxed_str = "%s.%s" % (untaxed["units"], untaxed["nanos"]) + total = inv["total_taxed"] + assert total["currency_code"] == currency_code + amount_total_str = "%s.%s" % (total["units"], total["nanos"]) + parsed_inv = { + "invoice_number": inv["number"], + "currency": {"iso": currency_code}, + "date": inv["issued_date"][:10], + "date_due": inv["due_date"][:10], + "amount_untaxed": float(amount_untaxed_str), + "amount_total": float(amount_total_str), + } + if inv.get("invoice_type") == "periodic" and inv.get("start_date"): + start_date_str = inv["start_date"][:10] + start_date_dt = fields.Date.from_string(start_date_str) + end_date_dt = start_date_dt + relativedelta(months=1, days=-1) + parsed_inv.update( + { + "date_start": start_date_dt, + "date_end": end_date_dt, + } + ) + self._scaleway_invoice_attach_pdf(parsed_inv, inv["id"], headers) + + logger.debug("Final parsed_inv=%s", parsed_inv) + invoices.append(parsed_inv) + return invoices diff --git a/account_invoice_download_scaleway/readme/CONFIGURE.rst b/account_invoice_download_scaleway/readme/CONFIGURE.rst new file mode 100644 index 0000000000..c566f4741d --- /dev/null +++ b/account_invoice_download_scaleway/readme/CONFIGURE.rst @@ -0,0 +1,7 @@ +First, you need to create an API Key. For that, login to your Scaleway account. On the top right, click on your organization and then click on *API Keys*. + +Go to the *Applications* tab, create a new application called *odoo* (for example). Once created, on the new *odoo* application, click on the three horizontal dots and select *Overview*: add the application to the group *Billing Administrators*. + +Then, go to the *API keys* tab, and create a new API key linked to the application *odoo*. Write down the secret key in a safe place. Your Scaleway API key is now ready! + +In Odoo, go to the menu *Invoicing > Configuration > Import Vendor Bills > Download Bills* and create a new entry. Select *Scaleway* as *Backend* and set the Scaleway Secret Key. diff --git a/account_invoice_download_scaleway/readme/CONTRIBUTORS.rst b/account_invoice_download_scaleway/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..ff65d68ce6 --- /dev/null +++ b/account_invoice_download_scaleway/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/account_invoice_download_scaleway/readme/DESCRIPTION.rst b/account_invoice_download_scaleway/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..83535d36ae --- /dev/null +++ b/account_invoice_download_scaleway/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module adds a **Scaleway** backend to the **account_invoice_download** module. It allows you to auto-download `Scaleway `_ invoices via the `Scaleway Billing API `_. diff --git a/account_invoice_download_scaleway/readme/USAGE.rst b/account_invoice_download_scaleway/readme/USAGE.rst new file mode 100644 index 0000000000..8b94f6b902 --- /dev/null +++ b/account_invoice_download_scaleway/readme/USAGE.rst @@ -0,0 +1 @@ +Refer to the usage instructions of the module **account\_invoice\_download**. diff --git a/account_invoice_download_scaleway/views/account_invoice_download_config.xml b/account_invoice_download_scaleway/views/account_invoice_download_config.xml new file mode 100644 index 0000000000..c458137185 --- /dev/null +++ b/account_invoice_download_scaleway/views/account_invoice_download_config.xml @@ -0,0 +1,28 @@ + + + + + + scaleway.account.invoice.download.config.form + account.invoice.download.config + + + + + + + + + + diff --git a/setup/account_invoice_download_scaleway/odoo/addons/account_invoice_download_scaleway b/setup/account_invoice_download_scaleway/odoo/addons/account_invoice_download_scaleway new file mode 120000 index 0000000000..3a4ae05547 --- /dev/null +++ b/setup/account_invoice_download_scaleway/odoo/addons/account_invoice_download_scaleway @@ -0,0 +1 @@ +../../../../account_invoice_download_scaleway \ No newline at end of file diff --git a/setup/account_invoice_download_scaleway/setup.py b/setup/account_invoice_download_scaleway/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/account_invoice_download_scaleway/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)