diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..b73abb6 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,33 @@ +name: Deploy Sphinx Documentation + +on: [push] +permissions: + contents: write +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + pip install sphinx sphinx-rtd-theme + pip install -e . + + - name: Build documentation + run: | + make -C docs html + touch docs/build/html/.nojekyll + + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/build/html diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 0000000..f9dcc8e --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,48 @@ +name: Pylint + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + - name: pylint + run: | + pylint $(git ls-files '*.py') --fail-under=9.0 --output-format=json > pylint-report.json + + - name: Generate Pylint Score + id: pylint_score + run: | + SCORE=$(cat pylint-report.json | jq '[.[].score] | add / length' || echo 0) + echo "score=${SCORE:-0}" >> $GITHUB_ENV + + - name: Upload Pylint Report + uses: actions/upload-artifact@v4 + with: + name: pylint-report + path: pylint-report.json + + - name: Create Pylint Badge + run: | + SCORE=$(echo "${{ env.score }}" | awk '{print int($1)}') + COLOR="red" + if [ "$SCORE" -ge 8 ]; then COLOR="green"; elif [ "$SCORE" -ge 5 ]; then COLOR="yellow"; fi + curl -o pylint-badge.svg "https://img.shields.io/badge/Pylint-$SCORE%2F10-$COLOR" + + - name: Upload Pylint Badge + uses: actions/upload-artifact@v4 + with: + name: pylint-badge + path: pylint-badge.svg diff --git a/README.md b/README.md index 4da9bd6..d8157b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # SuperFaktura API client +![Pylint Score](https://github.com/eledio-helpers/superfaktura-client/actions/workflows/pylint.yml/badge.svg) + +[Online documentation](https://eledio-helpers.github.io/superfaktura-client) + Library for handling of SuperFaktura API. Environment variables: diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..dc1312a --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..dd44d06 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,34 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'SuperFaktura API client' +copyright = '2025, Richard Kubíček, Eledio s.r.o.' +author = 'Richard Kubíček' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.autosummary', +] + +templates_path = ['_templates'] +exclude_patterns = [] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..f27d38e --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,8 @@ +Welcome to SuperFaktura Client's documentation +============================================= + +.. toctree:: + :maxdepth: 2 + + superfaktura + installation diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..9e40894 --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,6 @@ +Installation +==================== + +To install SuperFaktura Client, run the following command:: + + pip install git+https://github.com/eledio-helpers/superfaktura-client diff --git a/docs/source/superfaktura.bank_account.rst b/docs/source/superfaktura.bank_account.rst new file mode 100644 index 0000000..bb92506 --- /dev/null +++ b/docs/source/superfaktura.bank_account.rst @@ -0,0 +1,7 @@ +superfaktura.bank\_account module +================================= + +.. automodule:: superfaktura.bank_account + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.client_contacts.rst b/docs/source/superfaktura.client_contacts.rst new file mode 100644 index 0000000..21d5795 --- /dev/null +++ b/docs/source/superfaktura.client_contacts.rst @@ -0,0 +1,7 @@ +superfaktura.client\_contacts module +==================================== + +.. automodule:: superfaktura.client_contacts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.enumerations.currency.rst b/docs/source/superfaktura.enumerations.currency.rst new file mode 100644 index 0000000..9417c05 --- /dev/null +++ b/docs/source/superfaktura.enumerations.currency.rst @@ -0,0 +1,7 @@ +superfaktura.enumerations.currency module +========================================= + +.. automodule:: superfaktura.enumerations.currency + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.enumerations.rst b/docs/source/superfaktura.enumerations.rst new file mode 100644 index 0000000..3fd5848 --- /dev/null +++ b/docs/source/superfaktura.enumerations.rst @@ -0,0 +1,21 @@ +superfaktura.enumerations package +================================= + +Submodules +---------- + +superfaktura.enumerations.currency module +----------------------------------------- + +.. automodule:: superfaktura.enumerations.currency + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: superfaktura.enumerations + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.invoice.rst b/docs/source/superfaktura.invoice.rst new file mode 100644 index 0000000..ce397d5 --- /dev/null +++ b/docs/source/superfaktura.invoice.rst @@ -0,0 +1,7 @@ +superfaktura.invoice module +=========================== + +.. automodule:: superfaktura.invoice + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.rst b/docs/source/superfaktura.rst new file mode 100644 index 0000000..5119b1b --- /dev/null +++ b/docs/source/superfaktura.rst @@ -0,0 +1,35 @@ +SuperFaktura API client +==================== + + +Bank account +--------------------------------- + +.. automodule:: superfaktura.bank_account + :members: + :undoc-members: + :show-inheritance: + +Client contacts +------------------------------------ + +.. automodule:: superfaktura.client_contacts + :members: + :undoc-members: + :show-inheritance: + +Invoice +--------------------------- + +.. automodule:: superfaktura.invoice + :members: + :undoc-members: + :show-inheritance: + +SuperFaktura API +------------------------------------- + +.. automodule:: superfaktura.superfaktura_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.superfaktura_api.rst b/docs/source/superfaktura.superfaktura_api.rst new file mode 100644 index 0000000..8c406bb --- /dev/null +++ b/docs/source/superfaktura.superfaktura_api.rst @@ -0,0 +1,7 @@ +superfaktura.superfaktura\_api module +===================================== + +.. automodule:: superfaktura.superfaktura_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.utils.country.rst b/docs/source/superfaktura.utils.country.rst new file mode 100644 index 0000000..675154a --- /dev/null +++ b/docs/source/superfaktura.utils.country.rst @@ -0,0 +1,7 @@ +superfaktura.utils.country module +================================= + +.. automodule:: superfaktura.utils.country + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.utils.data_types.rst b/docs/source/superfaktura.utils.data_types.rst new file mode 100644 index 0000000..b7899be --- /dev/null +++ b/docs/source/superfaktura.utils.data_types.rst @@ -0,0 +1,7 @@ +superfaktura.utils.data\_types module +===================================== + +.. automodule:: superfaktura.utils.data_types + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/superfaktura.utils.rst b/docs/source/superfaktura.utils.rst new file mode 100644 index 0000000..0fbefc7 --- /dev/null +++ b/docs/source/superfaktura.utils.rst @@ -0,0 +1,29 @@ +superfaktura.utils package +========================== + +Submodules +---------- + +superfaktura.utils.country module +--------------------------------- + +.. automodule:: superfaktura.utils.country + :members: + :undoc-members: + :show-inheritance: + +superfaktura.utils.data\_types module +------------------------------------- + +.. automodule:: superfaktura.utils.data_types + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: superfaktura.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/superfaktura/bank_account.py b/superfaktura/bank_account.py index 32ba57c..748ba85 100644 --- a/superfaktura/bank_account.py +++ b/superfaktura/bank_account.py @@ -1,3 +1,36 @@ +""" +Bank Account Module. + +This module provides classes and functions for working with bank accounts in the SuperFaktura API. +It allows for retrieving, creating, updating, and deleting bank accounts. + +Classes: + - BankAccountModel: Dataclass representing a bank account. + - BankAccount: Class for interacting with bank accounts. + +Exceptions: + - NoDefaultBankAccountException: Exception for when no default bank account is found. + +Functions: + - (none) + +Usage: + import superfaktura.bank_account + + # Create an instance of BankAccount + bank = superfaktura.bank_account.BankAccount() + + # Retrieve a list of bank accounts + accounts = bank.list() + + # Get the default bank account + default_account = bank.default() + + # Create or update a bank account + data = {"account": "1234567890", "bank_code": "1234567890", "default": True} + bank.post(data) +""" + from dataclasses import dataclass, asdict from typing import Optional @@ -5,11 +38,13 @@ from superfaktura.superfaktura_api import SuperFakturaAPI class NoDefaultBankAccountException(Exception): - pass + """Exception for when no default bank account is found.""" @dataclass class BankAccountModel: + """Dataclass representing a bank account.""" + account: Optional[str] bank_code: Optional[str] bank_name: Optional[str] @@ -20,6 +55,7 @@ class BankAccountModel: id: Optional[int] def as_dict(self) -> dict: + """Returns a dictionary representation of the BankAccountModel.""" data = asdict(self) for key in list(data.keys()): if data[key] is None: @@ -28,24 +64,42 @@ class BankAccountModel: @staticmethod def from_dict(data: dict) -> "BankAccountModel": + """Creates a BankAccountModel from a dictionary.""" return BankAccountModel( - **{ - k: v - for k, v in data.items() - if k in BankAccountModel.__dataclass_fields__ - } + **{k: v for k, v in data.items() if k in BankAccountModel.__annotations__} ) class BankAccount(SuperFakturaAPI): + """ + Bank Account Class. + + This class provides methods for interacting with bank accounts in the SuperFaktura API. + It allows for retrieving, creating, updating, and deleting bank accounts. + + Methods: + - list: Retrieves a list of bank accounts. + - default: Retrieves the default bank account. + - post: Creates or updates a bank account. + + Usage: + bank = BankAccount() + accounts = bank.list() + default_account = bank.default() + data = {"account": "1234567890", "bank_code": "1234567890", "default": True} + bank.post(data) + """ + def __init__(self): super().__init__() def list(self) -> dict: + """Retrieves a list of bank accounts.""" url = "bank_accounts/index" return self.get(url) def default(self) -> Optional[BankAccountModel]: + """Retrieves the default bank account.""" accounts = self.list()["BankAccounts"] for account in accounts: if account["BankAccount"]["default"]: diff --git a/superfaktura/client_contacts.py b/superfaktura/client_contacts.py index 89ae69c..a6a0c4b 100644 --- a/superfaktura/client_contacts.py +++ b/superfaktura/client_contacts.py @@ -1,3 +1,24 @@ +""" +Module for interacting with client contacts in SuperFaktura. + +This module provides classes and functions for working with client contacts, +including creating, reading, and updating contact information. + +Classes: + ClientException: Base class for client exceptions. + ClientContactModel: Dataclass representing a client contact. + +Functions: + (none) + +Variables: + (none) + +Notes: + This module uses the SuperFaktura API to interact with client contacts. + You must have a valid API key and credentials to use this module. +""" + import dataclasses import json from pprint import pprint @@ -7,11 +28,13 @@ from superfaktura.superfaktura_api import SuperFakturaAPI class ClientException(Exception): - pass + """Base class for client exceptions.""" @dataclasses.dataclass class ClientContactModel: + """Client contact model.""" + name: str address: Optional[str] = None bank_account: Optional[str] = None @@ -48,6 +71,7 @@ class ClientContactModel: id: Optional[int] = None def as_dict(self) -> dict: + """Returns a dictionary representation of the ClientContactModel.""" data = dataclasses.asdict(self) for key in list(data.keys()): if data[key] is None: @@ -56,32 +80,34 @@ class ClientContactModel: @staticmethod def from_dict(data: dict) -> "ClientContactModel": + """Creates a ClientContactModel from a dictionary.""" return ClientContactModel( - **{ - k: v - for k, v in data.items() - if k in ClientContactModel.__dataclass_fields__ - } + **{k: v for k, v in data.items() if k in ClientContactModel.__annotations__} ) class ClientContact(SuperFakturaAPI): + """Client contact class.""" + def __init__(self): super().__init__() def add_contact(self, contact: ClientContactModel) -> bool: + """Adds a new client contact.""" url = "clients/create" data = {"Client": contact.as_dict()} - resp = self.post(endpoint=url, data=json.dumps(data)) - if resp["error_message"] == "Client created": + response = self.post(endpoint=url, data=json.dumps(data)) + if response["error_message"] == "Client created": return True return False def list(self) -> dict: + """Lists all exists client contacts.""" url = "clients/index.json" return self.get(endpoint=url) def get_client(self, client_id: int) -> ClientContactModel: + """Gets a client contact by ID.""" url = f"clients/view/{client_id}" data = self.get(endpoint=url) if "Client" not in data: diff --git a/superfaktura/enumerations/currency.py b/superfaktura/enumerations/currency.py index c30387e..ca928f8 100644 --- a/superfaktura/enumerations/currency.py +++ b/superfaktura/enumerations/currency.py @@ -1,3 +1,30 @@ +""" +Currency Enumeration. + +This module provides an enumeration of currencies that can be used in the SuperFaktura API. + +Classes: + - Currencies: Enumeration of currencies. + +Usage: + from superfaktura.enumerations.currency import Currencies + currency = Currencies.CZK +""" + + class Currencies: + """ + Currency Enumeration. + + This enumeration represents the different currencies that can be used in the SuperFaktura API. + + Values: + - CZK: Czech Koruna + - EUR: Euro + + Usage: + currency = Currencies.CZK + """ + CZK = "CZK" EUR = "EUR" diff --git a/superfaktura/invoice.py b/superfaktura/invoice.py index a2b2d91..4e5ab62 100644 --- a/superfaktura/invoice.py +++ b/superfaktura/invoice.py @@ -1,3 +1,57 @@ +""" +Invoice Module. + +This module provides classes and functions for working with invoices in the SuperFaktura API. +It allows for retrieving, creating, updating, and deleting invoices. + +Classes: + - InvoiceModel: Dataclass representing an invoice. + - InvoiceItem: Dataclass representing an invoice item. + - Invoice: Class for interacting with invoices. + +Exceptions: + - NoDefaultBankAccountException: Exception for when no default bank account is found. + +Functions: + - (none) + +Usage: + import superfaktura.invoice + + # Create an instance of Invoice + invoice = superfaktura.invoice.Invoice() + + # Create an invoice + invoice.add( + invoice=superfaktura.invoice.InvoiceModel( + type=superfaktura.invoice.InvoiceType.PROFORMA, + name="Invoice 3", + due=superfaktura.invoice.Date("2025-02-01"), + invoice_currency=superfaktura.invoice.Currencies.CZK, + header_comment="We invoice you for services", + bank_accounts=[bank.default().as_dict()], + ), + items=[ + superfaktura.invoice.InvoiceItem(name="Services", unit_price=100, quantity=1, + unit="ks", tax=21), + superfaktura.invoice.InvoiceItem(name="SIM card", unit_price=50, quantity=1, + tax=21, unit="ks"), + superfaktura.invoice.InvoiceItem( + name="SIM card 2", unit_price=75, quantity=1, tax=21, unit="ks" + ), + ], + contact=superfaktura.client_contacts.ClientContactModel( + name="Richard Kubíček", + email="kubicekr@eledio.com", + phone="+420 123 456 789", + address="Jaroslava Foglara 861/1", + ico="123", + update=True, + country_id=57, + ), + ) +""" + from dataclasses import dataclass, asdict from typing import Optional, List import json @@ -11,6 +65,8 @@ from superfaktura.utils.data_types import Date, DateEncoder @dataclass class InvoiceModel: + """This dataclass represents an invoice in the SuperFaktura API.""" + add_rounding_item: Optional[int] = 0 already_paid: Optional[int] = None bank_accounts: Optional[List[dict]] = None @@ -51,6 +107,7 @@ class InvoiceModel: vat_transfer: Optional[int] = None def as_dict(self) -> dict: + """Returns a dictionary representation of the InvoiceModel.""" data = asdict(self) for key in list(data.keys()): if data[key] is None: @@ -66,6 +123,8 @@ class InvoiceModel: @dataclass class InvoiceItem: + """This dataclass represents an invoice item in the SuperFaktura API.""" + name: str unit_price: float description: Optional[str] = None @@ -80,6 +139,7 @@ class InvoiceItem: use_document_currency: Optional[int] = 0 def as_dict(self) -> dict: + """Returns a dictionary representation of the InvoiceItem.""" data = asdict(self) for key in list(data.keys()): if data[key] is None: @@ -88,22 +148,74 @@ class InvoiceItem: class InvoiceType: + """ " + Invoice Type Enumeration. + + This enumeration represents the different types of invoices that can be created. + + Usage: + invoice_type = InvoiceType.PROFORMA + """ + PROFORMA = "proforma" INVOICE = "regular" class Invoice(SuperFakturaAPI): + """ + Invoice Class. + + This class provides methods for interacting with invoices in the SuperFaktura API. + It allows for retrieving, creating, updating, and deleting invoices. + + Methods: + - add: Creates a new invoice. + - get: Retrieves an invoice by ID. + - list: Retrieves a list of invoices. + - update: Updates an existing invoice. + + Usage: + invoice = Invoice() + invoice.add( + invoice=InvoiceModel( + type=InvoiceType.PROFORMA, + name="Invoice 3", + due=Date("2025-02-01"), + invoice_currency=Currencies.CZK, + header_comment="We invoice you for services", + bank_accounts=[bank.default().as_dict()], + ), + items=[ + InvoiceItem(name="Services", unit_price=100, quantity=1, unit="ks", tax=21), + InvoiceItem(name="SIM card", unit_price=50, quantity=1, tax=21, unit="ks"), + InvoiceItem( + name="SIM card 2", unit_price=75, quantity=1, tax=21, unit="ks" + ), + ], + contact=ClientContactModel( + name="Richard Kubíček", + email="kubicekr@eledio.com", + phone="+420 123 456 789", + address="Jaroslava Foglara 861/1", + ico="123", + update=True, + country_id=57, + ), + ) + """ + def __init__(self): super().__init__() def add( self, - invoice: InvoiceModel, + invoice_model: InvoiceModel, items: List[InvoiceItem], contact: ClientContactModel, ): + """Creates a new invoice.""" data = { - "Invoice": invoice.as_dict(), + "Invoice": invoice_model.as_dict(), "InvoiceItem": [item.as_dict() for item in items], "Client": contact.as_dict(), } @@ -116,7 +228,7 @@ if __name__ == "__main__": invoice = Invoice() bank = BankAccount() invoice.add( - invoice=InvoiceModel( + invoice_model=InvoiceModel( type=InvoiceType.PROFORMA, name="Invoice 3", due=Date("2025-02-01"), diff --git a/superfaktura/superfaktura_api.py b/superfaktura/superfaktura_api.py index 09d059b..9070e42 100644 --- a/superfaktura/superfaktura_api.py +++ b/superfaktura/superfaktura_api.py @@ -1,18 +1,49 @@ +""" +SuperFaktura API Client. + +This module provides classes and functions for working with the SuperFaktura API. +It allows for reading, creating, updating, and deleting data in SuperFaktura. + +Classes: + - SuperFakturaAPI: The base class for working with the SuperFaktura API. + - SuperFakturaAPIException: An exception for errors when working with the SuperFaktura API. + - SuperFakturaAPIMissingCredentialsException: An exception for missing login credentials. + +Functions: + - get: Retrieves data from the SuperFaktura API. + - post: Creates or updates data in the SuperFaktura API. + +Usage: + import superfaktura.superfaktura_api + + # Create an instance of SuperFakturaAPI + api = superfaktura.superfaktura_api.SuperFakturaAPI() + + # Retrieve data from the SuperFaktura API + data = api.get('endpoint') + + # Create or update data in the SuperFaktura API + api.post('endpoint', data) +""" + +import os from typing import Dict import requests -import os from dotenv import load_dotenv # type: ignore class SuperFakturaAPIException(Exception): - pass + """Exception for errors when working with the SuperFaktura API.""" + class SuperFakturaAPIMissingCredentialsException(Exception): - pass + """Exception for missing login credentials.""" class SuperFakturaAPI: + """Base class for working with the SuperFaktura API.""" + def __init__(self) -> None: load_dotenv() _api_key = os.getenv("SUPERFAKTURA_API_KEY") @@ -20,28 +51,85 @@ class SuperFakturaAPI: _api_mail = os.getenv("SUPERFAKTURA_API_EMAIL") _api_company_id = os.getenv("SUPERFAKTURA_API_COMPANY_ID") if not _api_key or not self._api_url or not _api_mail or not _api_company_id: - raise SuperFakturaAPIMissingCredentialsException('Please ensure, that necessary credentials are set. Please see README.md') + raise SuperFakturaAPIMissingCredentialsException( + "Please ensure, that necessary " + "credentials are set. Please see" + " README.md" + ) self._auth_header = { - "Authorization": f"SFAPI email={_api_mail}&apikey={_api_key}&company_id={_api_company_id}" + "Authorization": f"SFAPI email={_api_mail}&apikey={_api_key}&company_id=" + f"{_api_company_id}" } - def get(self, endpoint: str) -> Dict: - url = f"{self._api_url}/{endpoint}" - req = requests.get(url=url, headers=self._auth_header) - if req.status_code == 200: - return req.json() - else: - raise SuperFakturaAPIException( - f"Get status code: {req.status_code}; {req.json()}" - ) + def get(self, endpoint: str, timeout: int = 5) -> Dict: + """ + Retrieves data from the SuperFaktura API. - def post(self, endpoint: str, data: str) -> Dict: + Retrieves data from the specified endpoint in the SuperFaktura API. + + Args: + endpoint (str): The API endpoint to retrieve data from (e.g. 'invoices', 'clients', + etc.). + timeout (int, optional): The timeout for the API request in seconds. Defaults to 5. + + Returns: + Dict: The retrieved data in JSON format. + + Raises: + SuperFakturaAPIException: If the API request fails or returns an error. + + Examples: + >>> api = SuperFakturaAPI() + >>> data = api.get('invoices') + >>> print(data) + + Notes: + The available endpoints can be found in the SuperFaktura API documentation. + """ url = f"{self._api_url}/{endpoint}" - req = requests.post(url=url, headers=self._auth_header, data={"data": data}) + req = requests.get(url=url, headers=self._auth_header, timeout=timeout) if req.status_code == 200: return req.json() - else: - raise SuperFakturaAPIException( - f"Post status code: {req.status_code}; {req.json()}" - ) + raise SuperFakturaAPIException( + f"Get status code: {req.status_code}; {req.json()}" + ) + + def post(self, endpoint: str, data: str, timeout: int = 5) -> Dict: + """ + Creates or updates data in the SuperFaktura API. + + Creates or updates data in the specified endpoint in the SuperFaktura API. + + Args: + endpoint (str): The API endpoint to create or update data in (e.g. 'invoices', + 'clients', etc.). + data (str): The data to be created or updated in JSON format. + timeout (int, optional): The timeout for the API request in seconds. Defaults + to 5. + + Returns: + Dict: The created or updated data in JSON format. + + Raises: + SuperFakturaAPIException: If the API request fails or returns an error. + + Examples: + >>> api = SuperFakturaAPI() + >>> data = '{"name": "Example Invoice", "amount": 100.0}' + >>> response = api.post('invoices', data) + >>> print(response) + + Notes: + The available endpoints can be found in the SuperFaktura API documentation. + The data should be a valid JSON string. + """ + url = f"{self._api_url}/{endpoint}" + req = requests.post( + url=url, headers=self._auth_header, data={"data": data}, timeout=timeout + ) + if req.status_code == 200: + return req.json() + raise SuperFakturaAPIException( + f"Post status code: {req.status_code}; {req.json()}" + ) diff --git a/superfaktura/utils/country.py b/superfaktura/utils/country.py index 5b0cd5c..87b2672 100644 --- a/superfaktura/utils/country.py +++ b/superfaktura/utils/country.py @@ -1,12 +1,33 @@ -from pprint import pprint +""" +Country Module. + +This module provides utilities for working with countries in the SuperFaktura API. + +Functions: + - country_list: Retrieves a list of countries. + +Usage: + from superfaktura.utils.country import country_list + countries = country_list() + print(countries) +""" from superfaktura.superfaktura_api import SuperFakturaAPI def country_list(): + """ + Retrieves a list of countries. + + This function returns a list of countries that can be used in the SuperFaktura API. + + Returns: + - list: A list of countries. + + Usage: + countries = country_list() + print(countries) + """ api = SuperFakturaAPI() url = "countries" return api.get(url) - - -pprint(country_list()) diff --git a/superfaktura/utils/data_types.py b/superfaktura/utils/data_types.py index af65e71..9e78956 100644 --- a/superfaktura/utils/data_types.py +++ b/superfaktura/utils/data_types.py @@ -1,3 +1,22 @@ +""" +Data Types Module. + +This module provides data types and utilities for working with dates and other data types +in the SuperFaktura API. + +Classes: + - Date: Represents a date in the format YYYY-MM-DD. + - DateTime: Represents a date and time in the format YYYY-MM-DD HH:MM:SS. + +Functions: + - (none) + +Usage: + from superfaktura.utils.data_types import Date, DateTime + date = Date("2022-01-01") + datetime = DateTime("2022-01-01 12:00:00") +""" + from datetime import datetime from typing import Optional @@ -5,6 +24,22 @@ import json class Date: + """ + Date Class. + + This class represents a date in the format YYYY-MM-DD. + + Attributes: + - date (str): The date in the format YYYY-MM-DD. + + Methods: + - __str__: Returns the date as a string. + + Usage: + date = Date("2022-01-01") + print(date) # Output: 2022-01-01 + """ + def __init__(self, date_str: Optional[str] = None): """ Creates a Date instance that supports typing and validation for the format YYYY-MM-DD. @@ -25,8 +60,10 @@ class Date: """ try: return datetime.strptime(date_str, "%Y-%m-%d") - except ValueError: - raise ValueError(f"Date must be in format YYYY-MM-DD, got: {date_str}") + except ValueError as exc: + raise ValueError( + f"Date must be in format YYYY-MM-DD, got: {date_str}" + ) from exc def __str__(self) -> str: """ @@ -56,6 +93,20 @@ class Date: class DateEncoder(json.JSONEncoder): + """ + Date Encoder Class. + + This class is a custom JSON encoder that converts Date objects to strings. + + Methods: + - default: Encodes a Date object as a string. + + Usage: + encoder = DateEncoder() + date = Date("2022-01-01") + json_string = json.dumps(date, cls=encoder) + """ + def default(self, o): if isinstance(o, Date): return o.to_json()