+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..c23ecac
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..08e67b3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,131 @@
+# bunq Java SDK
+Version 0.9.0 **BETA**
+
+## Installation
+In the root of your project, being in the correct virtual environment, run:
+```shell
+(bunq_sdk_python) $ pip install bunq_sdk && pip freeze > requirements.txt
+```
+
+## Usage
+
+### Creating an API context
+In order to start making calls with the bunq API, you must first register your API key and device,
+and create a session. In the SDKs, we group these actions and call it "creating an API context". The
+context can be created by using the following code snippet:
+
+```
+apiContext = context.ApiContext(ENVIRONMENT_TYPE, API_KEY,
+ DEVICE_DESCRIPTION);
+apiContext.save(API_CONTEXT_FILE_PATH);
+```
+
+#### Example
+See [`api_context_save_example.py`](./examples/api_context_save_example.py)
+
+The API context can then be saved with:
+
+#### Safety considerations
+The file storing the context details (i.e. `bunq.conf`) is a key to your account. Anyone having
+access to it is able to perform any Public API actions with your account. Therefore, we recommend
+choosing a truly safe place to store it.
+
+### Making API calls
+There is a class for each endpoint. Each class has functions for each supported action. These
+actions can be `create`, `get`, `update`, `delete` and `list`.
+
+Sometimes API calls have dependencies, for instance `MonetaryAccount`. Making changes to a monetary
+account always also needs a reference to a `User`. These dependencies are required as arguments when
+performing API calls. Take a look at [doc.bunq.com](https://doc.bunq.com) for the full
+documentation.
+
+#### Creating objects
+Creating objects through the API requires an `ApiContext`, a `requestMap` and identifiers of all
+dependencies (such as User ID required for accessing a Monetary Account). Optionally, custom headers
+can be passed to requests.
+
+
+```
+request_map = {
+ generated.Payment.FIELD_AMOUNT: object_.Amount(
+ _PAYMENT_AMOUNT,
+ _PAYMENT_CURRENCY
+ ),
+ generated.Payment.FIELD_COUNTERPARTY_ALIAS: object_.Pointer(
+ _COUNTERPARTY_POINTER_TYPE,
+ _COUNTERPARTY_EMAIL
+ ),
+ generated.Payment.FIELD_DESCRIPTION: _PAYMENT_DESCRIPTION,
+}
+
+payment_id = generated.Payment.create(
+ api_context,
+ request_map,
+ _USER_ITEM_ID,
+ _MONETARY_ACCOUNT_ITEM_ID
+)
+```
+
+##### Example
+See [`PaymentExample.py`](./examples/payment_example.py)
+
+#### Reading objects
+Reading objects through the API requires an `ApiContext`, identifiers of all dependencies (such as
+User ID required for accessing a Monetary Account), and the identifier of the object to read (ID or
+UUID) Optionally, custom headers can be passed to requests.
+
+This type of calls always returns a model.
+
+```
+monetary_account = generated.MonetaryAccountBank.get(
+ api_context,
+ _USER_ITEM_ID,
+ _MONETARY_ACCOUNT_ITEM_ID
+)
+```
+
+##### Example
+See [`MonetaryAccountExample.py`](./examples/monetary_account_example.py)
+
+#### Updating objects
+Updating objects through the API goes the same way as creating objects, except that also the object to update identifier
+(ID or UUID) is needed.
+
+```
+request_update_map = {
+ generated.RequestInquiry.FIELD_STATUS: _STATUS_REVOKED,
+}
+generated.RequestInquiry.update(
+ api_context,
+ request_update_map,
+ _USER_ITEM_ID,
+ _MONETARY_ACCOUNT_ITEM_ID,
+ request_id
+).to_json()
+```
+
+##### Example
+See [`RequestExample.py`](./examples/request_example.py)
+
+#### Deleting objects
+Deleting objects through the API requires an `ApiContext`, identifiers of all dependencies (such as User ID required for
+accessing a Monetary Account), and the identifier of the object to delete (ID or UUID) Optionally, custom headers can be
+passed to requests.
+
+```
+generated.CustomerStatementExport.delete(apiContext, userId, monetaryAccountId, customerStatementId);
+```
+
+##### Example
+See [`CustomerStatementExportExample.py`](./examples/customer_statement_export_example.py)
+
+#### Listing objects
+Listing objects through the API requires an `ApiContext` and identifiers of all dependencies (such as User ID required
+for accessing a Monetary Account). Optionally, custom headers can be passed to requests.
+
+```
+users = generated.User.list(api_context)
+```
+
+##### Example
+See [`UserListExample.py`](./examples/user_list_example.py)
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..899f24f
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.9.0
\ No newline at end of file
diff --git a/assets/attachment.jpg b/assets/attachment.jpg
new file mode 100644
index 0000000..8396e33
Binary files /dev/null and b/assets/attachment.jpg differ
diff --git a/bunq/__init__.py b/bunq/__init__.py
new file mode 100644
index 0000000..03b8034
--- /dev/null
+++ b/bunq/__init__.py
@@ -0,0 +1,3 @@
+from bunq.sdk.json import registry
+
+registry.initialize()
diff --git a/bunq/sdk/__init__.py b/bunq/sdk/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/bunq/sdk/client.py b/bunq/sdk/client.py
new file mode 100644
index 0000000..aedc2c1
--- /dev/null
+++ b/bunq/sdk/client.py
@@ -0,0 +1,254 @@
+import uuid
+
+# Due to compatibility requirements, we are importing a class here.
+try:
+ from json import JSONDecodeError
+except ImportError:
+ from simplejson import JSONDecodeError
+
+import requests
+
+from bunq.sdk.json import converter
+from bunq.sdk import security
+from bunq.sdk import context
+from bunq.sdk import exception
+
+
+class ApiClient(object):
+ """
+ :type _api_context: context.ApiContext
+ """
+
+ # Header constants
+ HEADER_ATTACHMENT_DESCRIPTION = 'X-Bunq-Attachment-Description'
+ HEADER_CONTENT_TYPE = 'Content-Type'
+ HEADER_CACHE_CONTROL = 'Cache-Control'
+ HEADER_USER_AGENT = 'User-Agent'
+ HEADER_LANGUAGE = 'X-Bunq-Language'
+ HEADER_REGION = 'X-Bunq-Region'
+ HEADER_REQUEST_ID = 'X-Bunq-Client-Request-Id'
+ HEADER_GEOLOCATION = 'X-Bunq-Geolocation'
+ HEADER_SIGNATURE = 'X-Bunq-Client-Signature'
+ HEADER_AUTHENTICATION = 'X-Bunq-Client-Authentication'
+
+ # Default header values
+ _USER_AGENT_BUNQ = 'bunq-sdk-python/0.9'
+ _GEOLOCATION_ZERO = '0 0 0 0 NL'
+ _LANGUAGE_EN_US = 'en_US'
+ _REGION_NL_NL = 'nl_NL'
+ _CACHE_CONTROL_NONE = 'no-cache'
+
+ # Request method names
+ _METHOD_POST = 'POST'
+ _METHOD_PUT = 'PUT'
+ _METHOD_GET = 'GET'
+ _METHOD_DELETE = 'DELETE'
+
+ # Status code for successful execution
+ _STATUS_CODE_OK = 200
+
+ # Fields for fetching errors
+ _FIELD_ERROR = 'Error'
+ _FIELD_ERROR_DESCRIPTION = 'error_description'
+
+ # Empty string
+ _STRING_EMPTY = ''
+
+ # Empty bytes
+ _BYTES_EMPTY = b''
+
+ def __init__(self, api_context):
+ self._api_context = api_context
+
+ def post(self, uri_relative, request_bytes, custom_headers):
+ """
+ :type uri_relative: str
+ :type request_bytes: bytes
+ :type custom_headers: dict[str, str]
+
+ :return: requests.Response
+ """
+
+ return self._request(
+ self._METHOD_POST,
+ uri_relative,
+ request_bytes,
+ custom_headers
+ )
+
+ def _request(self, method, uri_relative, request_bytes, custom_headers):
+ """
+ :type method: str
+ :type uri_relative: str
+ :type request_bytes: bytes
+ :type custom_headers: dict[str, str]
+
+ :return: requests.Response
+ """
+
+ self._api_context.ensure_session_active()
+ all_headers = self._get_all_headers(
+ method,
+ uri_relative,
+ request_bytes,
+ custom_headers
+ )
+
+ response = requests.request(
+ method,
+ self._get_uri_full(uri_relative),
+ data=request_bytes,
+ headers=all_headers
+ )
+
+ self._assert_response_success(response)
+
+ return response
+
+ def _get_all_headers(self, method, endpoint, request_bytes, custom_headers):
+ """
+ :type method: str
+ :type endpoint: str
+ :type request_bytes: bytes
+ :type custom_headers: dict[str, str]
+
+ :rtype: dict[str, str]
+ """
+
+ headers = self._get_default_headers()
+ headers.update(custom_headers)
+
+ if self._api_context.token is not None:
+ headers[self.HEADER_AUTHENTICATION] = self._api_context.token
+ headers[self.HEADER_SIGNATURE] = security.sign_request(
+ self._api_context.installation_context.private_key_client,
+ method,
+ endpoint,
+ request_bytes,
+ headers
+ )
+
+ return headers
+
+ @classmethod
+ def _get_default_headers(cls):
+ """
+ :rtype: dict[str, str]
+ """
+
+ return {
+ cls.HEADER_USER_AGENT: cls._USER_AGENT_BUNQ,
+ cls.HEADER_REQUEST_ID: cls._generate_random_request_id(),
+ cls.HEADER_GEOLOCATION: cls._GEOLOCATION_ZERO,
+ cls.HEADER_LANGUAGE: cls._LANGUAGE_EN_US,
+ cls.HEADER_REGION: cls._REGION_NL_NL,
+ cls.HEADER_CACHE_CONTROL: cls._CACHE_CONTROL_NONE,
+ }
+
+ @staticmethod
+ def _generate_random_request_id():
+ """
+ :rtype: str
+ """
+
+ return str(uuid.uuid4())
+
+ def _get_uri_full(self, uri_relative):
+ """
+ :type uri_relative: str
+
+ :rtype: str
+ """
+
+ return self._api_context.environment_type.uri_base + uri_relative
+
+ def _assert_response_success(self, response):
+ """
+ :type response: requests.Response
+
+ :rtype: None
+ :raise ApiException: When the response is not successful.
+ """
+
+ if response.status_code != self._STATUS_CODE_OK:
+ raise exception.ApiException(
+ response.status_code,
+ self._fetch_error_messages(response)
+ )
+
+ def _fetch_error_messages(self, response):
+ """
+ :type response: requests.Response
+
+ :rtype: list[str]
+ """
+
+ response_content_string = response.content.decode()
+
+ try:
+ error_dict = converter.json_to_class(dict, response_content_string)
+
+ return self._fetch_error_descriptions(error_dict)
+ except JSONDecodeError:
+ return [response_content_string]
+
+ def _fetch_error_descriptions(self, error_dict):
+ """
+ :type error_dict: dict[str, list[dict[str, str]]
+
+ :rtype: list[str]
+ """
+
+ error_descriptions = []
+
+ for error in error_dict[self._FIELD_ERROR]:
+ description = error[self._FIELD_ERROR_DESCRIPTION]
+ error_descriptions.append(description)
+
+ return error_descriptions
+
+ def put(self, uri_relative, request_bytes, custom_headers):
+ """
+ :type uri_relative: str
+ :type request_bytes: bytes
+ :type custom_headers: dict[str, str]
+
+ :rtype: requests.Response
+ """
+
+ return self._request(
+ self._METHOD_PUT,
+ uri_relative,
+ request_bytes,
+ custom_headers
+ )
+
+ def get(self, uri_relative, custom_headers):
+ """
+ :type uri_relative: str
+ :type custom_headers: dict[str, str]
+
+ :rtype: requests.Response
+ """
+
+ return self._request(
+ self._METHOD_GET,
+ uri_relative,
+ self._BYTES_EMPTY,
+ custom_headers
+ )
+
+ def delete(self, uri_relative, custom_headers):
+ """
+ :type uri_relative: str
+ :type custom_headers: dict[str, str]
+
+ :rtype: requests.Response
+ """
+
+ return self._request(
+ self._METHOD_DELETE,
+ uri_relative,
+ self._BYTES_EMPTY,
+ custom_headers
+ )
diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py
new file mode 100644
index 0000000..a3854bd
--- /dev/null
+++ b/bunq/sdk/context.py
@@ -0,0 +1,350 @@
+import datetime
+
+import aenum
+from Cryptodome.PublicKey import RSA
+
+from bunq.sdk import model
+from bunq.sdk import security
+from bunq.sdk.json import converter
+from bunq.sdk.model import generated
+
+
+class ApiEnvironmentType(aenum.AutoNumberEnum):
+ """
+ :type PRODUCTION: ApiEnvironmentType
+ :type SANDBOX: ApiEnvironmentType
+ :type uri_base: str
+ """
+
+ PRODUCTION = 'https://public.api.bunq.com/v1/'
+ SANDBOX = 'https://sandbox.public.api.bunq.com/v1/'
+
+ def __init__(self, uri_base):
+ """
+ :type uri_base: str
+ """
+
+ self._uri_base = uri_base
+
+ @property
+ def uri_base(self):
+ """
+ :rtype: str
+ """
+
+ return self._uri_base
+
+
+class ApiContext(object):
+ """
+ :type _environment_type: ApiEnvironmentType
+ :type _api_key: str
+ :type _session_context: SessionContext
+ :type _installation_context: InstallationContext
+ """
+
+ # File mode for saving and restoring the context
+ _FILE_MODE_WRITE = 'w'
+ _FILE_MODE_READ = 'r'
+
+ # Minimum time to session expiry not requiring session reset
+ _TIME_TO_SESSION_EXPIRY_MINIMUM_SECONDS = 30
+
+ # Dummy ID to pass to Session endpoint
+ _SESSION_ID_DUMMY = 0
+
+ # Default path to the file storing serialized API context
+ _PATH_API_CONTEXT_DEFAULT = 'bunq.conf'
+
+ def __init__(self, environment_type, api_key, device_description,
+ permitted_ips=None):
+ """
+ :type environment_type: ApiEnvironmentType
+ :type api_key: str
+ :type device_description: str
+ :type permitted_ips: list[str]|None
+ """
+
+ if permitted_ips is None:
+ permitted_ips = []
+
+ self._environment_type = environment_type
+ self._api_key = api_key
+ self._installation_context = None
+ self._session_context = None
+ self._initialize(device_description, permitted_ips)
+
+ def _initialize(self, device_description, permitted_ips):
+ """
+ :type device_description: str
+ :type permitted_ips: list[str]
+
+ :rtype: None
+ """
+
+ self._initialize_installation()
+ self._register_device(device_description, permitted_ips)
+ self._initialize_session()
+
+ def _initialize_installation(self):
+ """
+ :rtype: None
+ """
+
+ private_key_client = security.generate_rsa_private_key()
+ installation = model.Installation.create(
+ self,
+ security.public_key_to_string(private_key_client.publickey())
+ )
+ token = installation.token.token
+ public_key_server_string = \
+ installation.server_public_key.server_public_key
+ public_key_server = RSA.import_key(public_key_server_string)
+
+ self._installation_context = InstallationContext(
+ token,
+ private_key_client,
+ public_key_server
+ )
+
+ def _register_device(self, device_description,
+ permitted_ips):
+ """
+ :type device_description: str
+ :type permitted_ips: list[]
+
+ :rtype: None
+ """
+
+ model.DeviceServer.create(self, device_description, permitted_ips)
+
+ def _initialize_session(self):
+ """
+ :rtype: None
+ """
+
+ session_server = model.SessionServer.create(self)
+ token = session_server.token.token
+ expiry_time = self._get_expiry_timestamp(session_server)
+
+ self._session_context = SessionContext(token, expiry_time)
+
+ @classmethod
+ def _get_expiry_timestamp(cls, session_server):
+ """
+ :type session_server: model.SessionServer
+
+ :rtype: datetime.datetime
+ """
+
+ timeout_seconds = cls._get_session_timeout_seconds(session_server)
+ time_now = datetime.datetime.now()
+
+ return time_now + datetime.timedelta(seconds=timeout_seconds)
+
+ @classmethod
+ def _get_session_timeout_seconds(cls, session_server):
+ """
+ :type session_server: model.SessionServer
+
+ :rtype: int
+ """
+
+ if session_server.user_company is not None:
+ return session_server.user_company.session_timeout
+ else:
+ return session_server.user_person.session_timeout
+
+ def ensure_session_active(self):
+ if self.session_context is None:
+ return
+
+ time_now = datetime.datetime.now()
+ time_to_expiry = self.session_context.expiry_time - time_now
+ time_to_expiry_minimum = datetime.timedelta(
+ seconds=self._TIME_TO_SESSION_EXPIRY_MINIMUM_SECONDS
+ )
+
+ if time_to_expiry < time_to_expiry_minimum:
+ self.reset_session()
+
+ def reset_session(self):
+ """
+ Closes the current session and opens a new one.
+
+ :rtype: None
+ """
+
+ self._drop_session_context()
+ self._initialize_session()
+
+ def _drop_session_context(self):
+ """
+ :rtype: None
+ """
+
+ self._session_context = None
+
+ def close_session(self):
+ """
+ Closes the current session.
+
+ :rtype: None
+ """
+
+ self._delete_session()
+ self._drop_session_context()
+
+ def _delete_session(self):
+ """
+ :rtype: None
+ """
+
+ generated.Session.delete(self, self._SESSION_ID_DUMMY)
+
+ @property
+ def environment_type(self):
+ """
+ :rtype: ApiEnvironmentType
+ """
+
+ return self._environment_type
+
+ @property
+ def api_key(self):
+ """
+ :rtype: str
+ """
+
+ return self._api_key
+
+ @property
+ def token(self):
+ """
+ :rtype: str
+ """
+
+ if self._session_context is not None:
+ return self.session_context.token
+ elif self._installation_context is not None:
+ return self.installation_context.token
+ else:
+ return None
+
+ @property
+ def installation_context(self):
+ """
+ :rtype: InstallationContext
+ """
+
+ return self._installation_context
+
+ @property
+ def session_context(self):
+ """
+ :rtype: SessionContext
+ """
+
+ return self._session_context
+
+ def save(self, path=None):
+ """
+ :type path: str
+
+ :rtype: None
+ """
+
+ if path is None:
+ path = self._PATH_API_CONTEXT_DEFAULT
+
+ with open(path, self._FILE_MODE_WRITE) as file:
+ file.write(converter.class_to_json(self))
+
+ @classmethod
+ def restore(cls, path=None):
+ """
+ :type path: str
+
+ :rtype: ApiContext
+ """
+
+ if path is None:
+ path = cls._PATH_API_CONTEXT_DEFAULT
+
+ with open(path, cls._FILE_MODE_READ) as file:
+ return converter.json_to_class(ApiContext, file.read())
+
+
+class InstallationContext(object):
+ """
+ :type _token: str
+ :type _private_key_client: RSA.RsaKey
+ :type _public_key_server: RSA.RsaKey
+ """
+
+ def __init__(self, token, private_key_client, public_key_server):
+ """
+ :type token: str
+ :type private_key_client: RSA.RsaKey
+ :type public_key_server: RSA.RsaKey
+ """
+
+ self._token = token
+ self._private_key_client = private_key_client
+ self._public_key_server = public_key_server
+
+ @property
+ def token(self):
+ """
+ :rtype: str
+ """
+
+ return self._token
+
+ @property
+ def private_key_client(self):
+ """
+ :rtype: RSA.RsaKey
+ """
+
+ return self._private_key_client
+
+ @property
+ def public_key_server(self):
+ """
+ :rtype: RSA.RsaKey
+ """
+
+ return self._public_key_server
+
+
+class SessionContext(object):
+ """
+ :type _token: str
+ :type _expiry_time: datetime.datetime
+ """
+
+ def __init__(self, token, expiry_time):
+ """
+ :type token: str
+ :type expiry_time: datetime.datetime
+ """
+
+ self._token = token
+ self._expiry_time = expiry_time
+
+ @property
+ def token(self):
+ """
+ :rtype: str
+ """
+
+ return self._token
+
+ @property
+ def expiry_time(self):
+ """
+ :rtype: datetime.datetime
+ """
+
+ return self._expiry_time
diff --git a/bunq/sdk/exception.py b/bunq/sdk/exception.py
new file mode 100644
index 0000000..6161ec8
--- /dev/null
+++ b/bunq/sdk/exception.py
@@ -0,0 +1,54 @@
+class ApiException(Exception):
+ """
+ :type _response_code: int
+ """
+
+ # Constants for formatting messages
+ _FORMAT_RESPONSE_CODE_LINE = 'HTTP Response Code: {}'
+ _GLUE_ERROR_MESSAGES = '\n'
+
+ def __init__(self, response_code, messages):
+ """
+ :type response_code: int
+ :type messages: list[str]
+ """
+
+ super(ApiException, self).__init__(
+ self.generate_message_error(response_code, messages)
+ )
+ self._response_code = response_code
+
+ def generate_message_error(self, response_code, messages):
+ """
+ :type response_code: int
+ :type messages: list[str]
+
+ :rtype: str
+ """
+
+ line_response_code = self._FORMAT_RESPONSE_CODE_LINE \
+ .format(response_code)
+
+ return self.glue_messages([line_response_code] + messages)
+
+ def glue_messages(self, messages):
+ """
+ :type messages: list[str]
+
+ :rtype: str
+ """
+
+ return self._GLUE_ERROR_MESSAGES.join(messages)
+
+ @property
+ def response_code(self):
+ """
+ :rtype: int
+ """
+
+ return self._response_code
+
+
+class BunqException(Exception):
+ def __init__(self, message):
+ super(BunqException, self).__init__(message)
diff --git a/bunq/sdk/json/__init__.py b/bunq/sdk/json/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/bunq/sdk/json/adapters.py b/bunq/sdk/json/adapters.py
new file mode 100644
index 0000000..edbb111
--- /dev/null
+++ b/bunq/sdk/json/adapters.py
@@ -0,0 +1,442 @@
+import datetime
+
+from bunq.sdk import context
+from bunq.sdk import model
+from bunq.sdk import security
+from bunq.sdk.json import converter
+from bunq.sdk.model import generated
+from bunq.sdk.model.generated import object_
+
+
+class InstallationAdapter(converter.JsonAdapter):
+ # Id constants
+ _ATTRIBUTE_ID = '_id_'
+ _INDEX_ID = 0
+ _FIELD_ID = 'Id'
+
+ # Token constants
+ _ATTRIBUTE_TOKEN = '_token'
+ _INDEX_TOKEN = 1
+ _FIELD_TOKEN = 'Token'
+
+ # Server Public Key constants
+ _ATTRIBUTE_SERVER_PUBLIC_KEY = '_server_public_key'
+ _INDEX_SERVER_PUBLIC_KEY = 2
+ _FIELD_SERVER_PUBLIC_KEY = 'ServerPublicKey'
+
+ @classmethod
+ def deserialize(cls, target_class, array):
+ """
+ :type target_class: model.Installation|type
+ :type array: list
+
+ :rtype: model.Installation
+ """
+
+ installation = target_class.__new__(target_class)
+ server_public_key_wrapped = array[cls._INDEX_SERVER_PUBLIC_KEY]
+ installation.__dict__ = {
+ cls._ATTRIBUTE_ID: converter.deserialize(
+ model.Id,
+ array[cls._INDEX_ID][cls._FIELD_ID]
+ ),
+ cls._ATTRIBUTE_TOKEN: converter.deserialize(
+ model.SessionToken,
+ array[cls._INDEX_TOKEN][cls._FIELD_TOKEN]
+ ),
+ cls._ATTRIBUTE_SERVER_PUBLIC_KEY: converter.deserialize(
+ model.PublicKeyServer,
+ server_public_key_wrapped[cls._FIELD_SERVER_PUBLIC_KEY]
+ ),
+ }
+
+ return installation
+
+ @classmethod
+ def serialize(cls, installation):
+ """
+ :type installation: model.Installation
+
+ :rtype: list
+ """
+
+ return [
+ {cls._FIELD_ID: converter.serialize(installation.id_)},
+ {cls._FIELD_TOKEN: converter.serialize(installation.token)},
+ {
+ cls._FIELD_SERVER_PUBLIC_KEY: converter.serialize(
+ installation.server_public_key
+ ),
+ },
+ ]
+
+
+class SessionServerAdapter(converter.JsonAdapter):
+ # Id constants
+ _ATTRIBUTE_ID = '_id_'
+ _INDEX_ID = 0
+ _FIELD_ID = 'Id'
+
+ # Token constants
+ _ATTRIBUTE_TOKEN = '_token'
+ _INDEX_TOKEN = 1
+ _FIELD_TOKEN = 'Token'
+
+ # User constants
+ _INDEX_USER = 2
+
+ # UserCompany constants
+ _ATTRIBUTE_USER_COMPANY = '_user_company'
+ _FIELD_USER_COMPANY = 'UserCompany'
+
+ # UserPerson constants
+ _ATTRIBUTE_USER_PERSON = '_user_person'
+ _FIELD_USER_PERSON = 'UserPerson'
+
+ @classmethod
+ def deserialize(cls, target_class, array):
+ """
+ :type target_class: model.SessionServer|type
+ :type array: list
+
+ :rtype: model.SessionServer
+ """
+
+ session_server = target_class.__new__(target_class)
+ session_server.__dict__ = {
+ cls._ATTRIBUTE_ID: converter.deserialize(
+ model.Id,
+ array[cls._INDEX_ID][cls._FIELD_ID]
+ ),
+ cls._ATTRIBUTE_TOKEN: converter.deserialize(
+ model.SessionToken,
+ array[cls._INDEX_TOKEN][cls._FIELD_TOKEN]
+ ),
+ cls._ATTRIBUTE_USER_COMPANY: None,
+ cls._ATTRIBUTE_USER_PERSON: None,
+ }
+
+ user_dict_wrapped = array[cls._INDEX_USER]
+
+ if cls._FIELD_USER_COMPANY in user_dict_wrapped:
+ session_server.__dict__[cls._ATTRIBUTE_USER_COMPANY] = \
+ converter.deserialize(
+ generated.UserCompany,
+ user_dict_wrapped[cls._FIELD_USER_COMPANY]
+ )
+ elif cls._FIELD_USER_PERSON in user_dict_wrapped:
+ session_server.__dict__[cls._ATTRIBUTE_USER_PERSON] = \
+ converter.deserialize(
+ generated.UserPerson,
+ user_dict_wrapped[cls._FIELD_USER_PERSON]
+ )
+
+ return session_server
+
+ @classmethod
+ def serialize(cls, session_server):
+ """
+ :type session_server: model.SessionServer
+
+ :rtype: list
+ """
+
+ return [
+ {cls._FIELD_ID: converter.serialize(session_server.id_)},
+ {cls._FIELD_TOKEN: converter.serialize(session_server.token)},
+ {
+ cls._FIELD_USER_COMPANY:
+ converter.serialize(session_server.user_company),
+ },
+ {
+ cls._FIELD_USER_PERSON:
+ converter.serialize(session_server.user_person),
+ },
+ ]
+
+
+class InstallationContextAdapter(converter.JsonAdapter):
+ # Attribute/Field constants
+ _ATTRIBUTE_TOKEN = '_token'
+ _FIELD_TOKEN = 'token'
+
+ _ATTRIBUTE_PRIVATE_KEY_CLIENT = '_private_key_client'
+ _FIELD_PRIVATE_KEY_CLIENT = 'private_key_client'
+
+ _ATTRIBUTE_PUBLIC_KEY_CLIENT = '_public_key_client'
+ _FIELD_PUBLIC_KEY_CLIENT = 'public_key_client'
+
+ _ATTRIBUTE_PUBLIC_KEY_SERVER = '_public_key_server'
+ _FIELD_PUBLIC_KEY_SERVER = 'public_key_server'
+
+ @classmethod
+ def deserialize(cls, target_class, obj):
+ """
+ :type target_class: context.InstallationContext|type
+ :type obj: dict
+
+ :rtype: context.InstallationContext
+ """
+
+ installation_context = target_class.__new__(target_class)
+ private_key_client = security.rsa_key_from_string(
+ obj[cls._FIELD_PRIVATE_KEY_CLIENT]
+ )
+ public_key_client = security.rsa_key_from_string(
+ obj[cls._FIELD_PUBLIC_KEY_CLIENT]
+ )
+ public_key_server = security.rsa_key_from_string(
+ obj[cls._FIELD_PUBLIC_KEY_SERVER]
+ )
+ installation_context.__dict__ = {
+ cls._ATTRIBUTE_TOKEN: obj[cls._FIELD_TOKEN],
+ cls._ATTRIBUTE_PRIVATE_KEY_CLIENT: private_key_client,
+ cls._ATTRIBUTE_PUBLIC_KEY_CLIENT: public_key_client,
+ cls._ATTRIBUTE_PUBLIC_KEY_SERVER: public_key_server,
+ }
+
+ return installation_context
+
+ @classmethod
+ def serialize(cls, installation_context):
+ """
+ :type installation_context: context.InstallationContext
+
+ :rtype: dict
+ """
+
+ return {
+ cls._FIELD_TOKEN: installation_context.token,
+ cls._FIELD_PUBLIC_KEY_CLIENT: security.public_key_to_string(
+ installation_context.private_key_client.publickey()
+ ),
+ cls._FIELD_PRIVATE_KEY_CLIENT: security.private_key_to_string(
+ installation_context.private_key_client
+ ),
+ cls._FIELD_PUBLIC_KEY_SERVER: security.public_key_to_string(
+ installation_context.public_key_server
+ ),
+ }
+
+
+class ApiEnvironmentTypeAdapter(converter.JsonAdapter):
+ @classmethod
+ def deserialize(cls, target_class, name):
+ """
+ :type target_class: context.ApiEnvironmentType|type
+ :type name: str
+
+ :rtype: context.ApiEnvironmentType
+ """
+
+ _ = target_class
+
+ return context.ApiEnvironmentType[name]
+
+ @classmethod
+ def serialize(cls, api_environment_type):
+ """
+ :type api_environment_type: context.ApiEnvironmentType
+
+ :rtype: str
+ """
+
+ return api_environment_type.name
+
+
+class FloatAdapter(converter.JsonAdapter):
+ # Precision to round the floats to before outputting them
+ _PRECISION_FLOAT = 2
+
+ @classmethod
+ def deserialize(cls, target_class, string):
+ """
+ :type target_class: float|type
+ :type string: str
+
+ :rtype: float
+ """
+
+ _ = target_class
+
+ return float(string)
+
+ @classmethod
+ def serialize(cls, number):
+ """
+ :type number: float
+
+ :rtype: str
+ """
+
+ return str(round(number, cls._PRECISION_FLOAT))
+
+
+class GeolocationAdapter(converter.JsonAdapter):
+ # Field constants
+ _FIELD_LATITUDE = 'latitude'
+ _FIELD_LONGITUDE = 'longitude'
+ _FIELD_ALTITUDE = 'altitude'
+ _FIELD_RADIUS = 'radius'
+
+ @classmethod
+ def can_deserialize(cls):
+ """
+ :rtype: bool
+ """
+
+ return False
+
+ @classmethod
+ def deserialize(cls, target_class, obj):
+ """
+ :type target_class: float|type
+ :type obj: dict
+
+ :raise: NotImplementedError
+ """
+
+ _ = target_class, obj
+
+ raise NotImplementedError()
+
+ @classmethod
+ def serialize(cls, geolocation):
+ """
+ :type geolocation: object_.Geolocation
+
+ :rtype: dict
+ """
+
+ obj = {}
+
+ cls.add_if_not_none(obj, cls._FIELD_LATITUDE, geolocation.latitude)
+ cls.add_if_not_none(obj, cls._FIELD_LONGITUDE, geolocation.longitude)
+ cls.add_if_not_none(obj, cls._FIELD_ALTITUDE, geolocation.altitude)
+ cls.add_if_not_none(obj, cls._FIELD_RADIUS, geolocation.radius)
+
+ return obj
+
+ @classmethod
+ def add_if_not_none(cls, dict_, key, value):
+ """
+ :type dict_: dict[str, str]
+ :type key: str
+ :type value: float
+
+ :rtype: None
+ """
+
+ if value is not None:
+ dict_[key] = str(value)
+
+
+class MonetaryAccountReferenceAdapter(converter.JsonAdapter):
+ @classmethod
+ def deserialize(cls, target_class, obj):
+ """
+ :type target_class: object_.MonetaryAccountReference|type
+ :type obj: dict
+
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ label_monetary_account = converter.deserialize(
+ object_.LabelMonetaryAccount,
+ obj
+ )
+
+ return target_class.create_from_label_monetary_account(
+ label_monetary_account
+ )
+
+ @classmethod
+ def serialize(cls, monetary_account_reference):
+ """
+ :type monetary_account_reference: object_.MonetaryAccountReference
+
+ :rtype: dict
+ """
+
+ return converter.serialize(monetary_account_reference.pointer)
+
+
+class ShareDetailAdapter(converter.JsonAdapter):
+ # Attribute/Field constants
+ _ATTRIBUTE_PAYMENT = 'payment'
+ _FIELD_PAYMENT = 'ShareDetailPayment'
+
+ _ATTRIBUTE_READ_ONLY = 'read_only'
+ _FIELD_READ_ONLY = 'ShareDetailReadOnly'
+
+ _ATTRIBUTE_DRAFT_PAYMENT = 'draft_payment'
+ _FIELD_DRAFT_PAYMENT = 'ShareDetailDraftPayment'
+
+ @classmethod
+ def deserialize(cls, target_class, obj):
+ """
+ :type target_class: object_.ShareDetail|type
+ :type obj: dict
+
+ :rtype: object_.ShareDetail
+ """
+
+ share_detail = target_class.__new__(target_class)
+ share_detail.__dict__ = {
+ cls._ATTRIBUTE_PAYMENT: converter.deserialize(
+ object_.ShareDetailPayment,
+ obj[cls._FIELD_PAYMENT]
+ ),
+ cls._ATTRIBUTE_READ_ONLY: converter.deserialize(
+ object_.ShareDetailReadOnly,
+ obj[cls._FIELD_READ_ONLY]
+ ),
+ cls._ATTRIBUTE_DRAFT_PAYMENT: converter.deserialize(
+ object_.ShareDetailDraftPayment,
+ obj[cls._FIELD_DRAFT_PAYMENT]
+ ),
+ }
+
+ return share_detail
+
+ @classmethod
+ def serialize(cls, share_detail):
+ """
+ :type share_detail: object_.ShareDetail
+
+ :rtype: dict
+ """
+
+ return {
+ cls._FIELD_PAYMENT: converter.serialize(share_detail.payment),
+ cls._FIELD_READ_ONLY: converter.serialize(share_detail.read_only),
+ cls._FIELD_DRAFT_PAYMENT: converter.serialize(
+ share_detail.draft_payment
+ ),
+ }
+
+
+class DateTimeAdapter(converter.JsonAdapter):
+ # bunq timestamp format
+ _FORMAT_TIMESTAMP = '%Y-%m-%d %H:%M:%S.%f'
+
+ @classmethod
+ def deserialize(cls, target_class, string):
+ """
+ :type target_class: datetime.datetime|type
+ :type string: str
+
+ :rtype: datetime.datetime
+ """
+
+ return target_class.strptime(string, cls._FORMAT_TIMESTAMP)
+
+ @classmethod
+ def serialize(cls, timestamp):
+ """
+ :type timestamp: datetime.datetime
+
+ :rtype: dict
+ """
+
+ return timestamp.strftime(cls._FORMAT_TIMESTAMP)
diff --git a/bunq/sdk/json/converter.py b/bunq/sdk/json/converter.py
new file mode 100644
index 0000000..65e460a
--- /dev/null
+++ b/bunq/sdk/json/converter.py
@@ -0,0 +1,616 @@
+import inspect
+import json
+import re
+import sys
+import warnings
+
+from bunq.sdk import exception
+
+# Indentation size we use for the serialized JSON output
+_JSON_INDENT = 4
+
+
+class JsonAdapter(object):
+ # Error constants
+ _ERROR_COULD_NOT_FIND_CLASS = 'Could not find class: {}'
+
+ # Maps to store custom serializers and deserializers
+ _custom_serializers = {}
+ _custom_deserializers = {}
+
+ # Warning for when a key from raw object is unknown
+ _WARNING_KEY_UNKNOWN = '[bunq SDK beta] Key "{}" in "{}" is unknown.'
+
+ # Overlapping key names to be suffixed by and underscore
+ _KEYS_OVERLAPPING = {'id', 'type'}
+
+ # Suffix to strip from the keys during serialization
+ _SUFFIX_KEY_OVERLAPPING = '_'
+ _PREFIX_KEY_PROTECTED = '_'
+
+ # Constants to fetch param types from the docstrings
+ _PATTERN_PARAM_TYPES = ':type (_?{}): ([\w.]+)(?:\[([\w.]+)\])?'
+ _SUBMATCH_INDEX_NAME = 1
+ _SUBMATCH_INDEX_TYPE_MAIN = 2
+ _SUBMATCH_INDEX_TYPE_SUB = 3
+
+ # List of builtin type names
+ _TYPE_NAMES_BUILTIN = {'int', 'bool', 'float', 'str', 'list', 'dict',
+ 'bytes', 'unicode'}
+
+ # Delimiter between modules in class paths
+ _DELIMITER_MODULE = '.'
+
+ # List of byte-array type names
+ _TYPE_NAMES_BYTES = {'bytes', 'unicode'}
+
+ @classmethod
+ def register_custom_adapter(cls, target_class, adapter):
+ """
+ :type target_class: type
+ :type adapter: JsonAdapter|type
+
+ :rtype: None
+ """
+
+ class_name = target_class.__name__
+
+ if adapter.can_serialize():
+ cls._custom_serializers[class_name] = adapter
+
+ if adapter.can_deserialize():
+ cls._custom_deserializers[class_name] = adapter
+
+ @classmethod
+ def _get_serializer(cls, cls_for):
+ """
+ :type cls_for: type
+
+ :rtype: JsonAdapter
+ """
+
+ if cls_for.__name__ in cls._custom_serializers:
+ return cls._custom_serializers[cls_for.__name__]
+
+ return JsonAdapter
+
+ @classmethod
+ def _get_deserializer(cls, cls_for):
+ """
+ :type cls_for: type
+
+ :rtype: JsonAdapter
+ """
+
+ if cls_for.__name__ in cls._custom_deserializers:
+ return cls._custom_deserializers[cls_for.__name__]
+
+ return JsonAdapter
+
+ @classmethod
+ def can_deserialize(cls):
+ """
+ :rtype: bool
+ """
+
+ return True
+
+ @classmethod
+ def deserialize(cls, cls_target, obj_raw):
+ """
+ :type cls_target: T|type
+ :type obj_raw: int|str|bool|float|list|dict|None
+
+ :rtype: T
+ """
+
+ deserializer = cls._get_deserializer(cls_target)
+
+ if deserializer == cls:
+ return cls._deserialize_default(cls_target, obj_raw)
+ else:
+ return deserializer.deserialize(cls_target, obj_raw)
+
+ @classmethod
+ def _deserialize_default(cls, cls_target, obj_raw):
+ """
+ :type cls_target: T|type
+ :type obj_raw: int|str|bool|float|list|dict|None
+
+ :rtype: T
+ """
+
+ if cls._is_deserialized(cls_target, obj_raw):
+ return obj_raw
+ elif type(obj_raw) == dict:
+ return cls._deserialize_dict(cls_target, obj_raw)
+ else:
+ return cls_target(obj_raw)
+
+ @classmethod
+ def _is_deserialized(cls, cls_target, obj):
+ """
+ :type cls_target: type
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: bool
+ """
+
+ if cls_target is None:
+ return True
+
+ if cls_target in {list, dict}:
+ return True
+
+ if cls._is_bytes_type(cls_target):
+ return True
+
+ if obj is None:
+ return True
+
+ if type(obj) in {list, cls_target}:
+ return True
+
+ return False
+
+ @classmethod
+ def _deserialize_dict(cls, cls_target, dict_):
+ """
+ :type cls_target: T|type
+ :type dict_: dict
+
+ :rtype: T
+ """
+
+ instance = cls_target.__new__(cls_target, cls_target)
+ instance.__dict__ = cls._deserialize_dict_attributes(cls_target, dict_)
+
+ return instance
+
+ @classmethod
+ def _deserialize_dict_attributes(cls, cls_context, dict_):
+ """
+ :type cls_context: type
+ :type dict_: dict
+
+ :rtype: dict
+ """
+
+ dict_deserialized = {}
+
+ for key in dict_.keys():
+ key_deserialized = cls._deserialize_key(key)
+ value_specs = cls._get_value_specs(cls_context, key_deserialized)
+
+ if value_specs is not None:
+ dict_deserialized[value_specs.name] = cls._deserialize_value(
+ value_specs.types,
+ dict_[key]
+ )
+ else:
+ cls._warn_key_unknown(cls_context, key)
+
+ return dict_deserialized
+
+ @classmethod
+ def _warn_key_unknown(cls, cls_context, key):
+ """
+ :type cls_context: type
+ :type key: str
+
+ :rtype: None
+ """
+
+ context_name = cls_context.__name__
+ warnings.warn(cls._WARNING_KEY_UNKNOWN.format(key, context_name))
+
+ @classmethod
+ def _deserialize_key(cls, key):
+ """
+ :type key: str
+
+ :rtype: str
+ """
+
+ if key in cls._KEYS_OVERLAPPING:
+ return key + cls._SUFFIX_KEY_OVERLAPPING
+
+ return key
+
+ @classmethod
+ def _get_value_specs(cls, cls_in, attribute_name):
+ """
+ :type cls_in: type
+ :type attribute_name: str
+
+ :rtype: ValueSpecs
+ """
+
+ if cls_in in {dict, list}:
+ return ValueSpecs(None, ValueTypes(None, None))
+ else:
+ return cls._fetch_attribute_specs_from_doc(cls_in, attribute_name)
+
+ @classmethod
+ def _fetch_attribute_specs_from_doc(cls, cls_in, attribute_name):
+ """
+ :type cls_in: type
+ :type attribute_name: str
+
+ :rtype: ValueSpecs
+ """
+
+ pattern = cls._PATTERN_PARAM_TYPES.format(attribute_name)
+ match = re.search(pattern, cls_in.__doc__)
+
+ if match is not None:
+ return ValueSpecs(
+ cls._fetch_name(match),
+ ValueTypes(
+ cls._fetch_type_main(cls_in, match),
+ cls._fetch_type_sub(cls_in, match)
+ )
+ )
+ else:
+ return None
+
+ @classmethod
+ def _fetch_name(cls, match):
+ """
+ :type match: _sre.SRE_Match
+
+ :rtype: str
+ """
+
+ return match.group(cls._SUBMATCH_INDEX_NAME)
+
+ @classmethod
+ def _fetch_type_main(cls, cls_in, match):
+ """
+ :type cls_in: type
+ :type match: _sre.SRE_Match
+
+ :rtype: type
+ """
+
+ return cls._str_to_type(
+ cls_in,
+ match.group(cls._SUBMATCH_INDEX_TYPE_MAIN)
+ )
+
+ @classmethod
+ def _fetch_type_sub(cls, cls_in, match):
+ """
+ :type cls_in: type
+ :type match: _sre.SRE_Match
+
+ :rtype: type
+ """
+
+ if match.group(cls._SUBMATCH_INDEX_TYPE_SUB):
+ return cls._str_to_type(
+ cls_in,
+ match.group(cls._SUBMATCH_INDEX_TYPE_SUB)
+ )
+ else:
+ return None
+
+ @classmethod
+ def _str_to_type(cls, context_class, string):
+ """
+ :type context_class: type
+ :type string: str
+
+ :rtype: type
+ """
+
+ if string in cls._TYPE_NAMES_BUILTIN:
+ return eval(string)
+
+ module_ = sys.modules[context_class.__module__]
+
+ if hasattr(module_, string):
+ return getattr(module_, string)
+
+ return cls._str_to_type_from_member_module(module_, string)
+
+ @classmethod
+ def _str_to_type_from_member_module(cls, module_, string):
+ """
+ :type module_: module
+ :type string: str
+
+ :rtype: type
+ :raise: BunqException when could not find the class for the string.
+ """
+
+ module_name_short, class_name = string.split(cls._DELIMITER_MODULE)
+ members = inspect.getmembers(module_, inspect.ismodule)
+
+ for name, module_member in members:
+ if module_name_short == name:
+ return getattr(module_member, class_name)
+
+ error_message = cls._ERROR_COULD_NOT_FIND_CLASS.format(string)
+
+ raise exception.BunqException(error_message)
+
+ @classmethod
+ def _deserialize_value(cls, types, value):
+ """
+ :type types: ValueTypes
+ :type value: int|str|bool|float|bytes|unicode|list|dict
+
+ :rtype: int|str|bool|float|bytes|unicode|list|dict|object
+ """
+
+ if types.main == list and value is not None:
+ return cls._deserialize_list(types.sub, value)
+ else:
+ return cls.deserialize(types.main, value)
+
+ @classmethod
+ def _deserialize_list(cls, type_item, list_):
+ """
+ :type type_item: T|type
+ :type list_: list
+
+ :rtype: list[T]
+ """
+
+ list_deserialized = []
+
+ for item in list_:
+ item_deserialized = cls.deserialize(type_item, item)
+ list_deserialized.append(item_deserialized)
+
+ return list_deserialized
+
+ @classmethod
+ def can_serialize(cls):
+ """
+ :rtype: bool
+ """
+
+ return True
+
+ @classmethod
+ def serialize(cls, obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: int|str|bool|list|dict
+ """
+
+ serializer = cls._get_serializer(type(obj))
+
+ if serializer == cls:
+ return cls._serialize_default(obj)
+ else:
+ return serializer.serialize(obj)
+
+ @classmethod
+ def _serialize_default(cls, obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: int|str|bool|list|dict
+ """
+
+ if obj is None or cls._is_primitive(obj):
+ return obj
+ elif cls._is_bytes(obj):
+ return obj.decode()
+ elif type(obj) == list:
+ return cls._serialize_list(obj)
+ else:
+ dict_ = cls._get_obj_raw(obj)
+
+ return cls._serialize_dict(dict_)
+
+ @classmethod
+ def _is_primitive(cls, obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: bool
+ """
+
+ return cls._is_type_primitive(type(obj))
+
+ @classmethod
+ def _is_type_primitive(cls, type_):
+ """
+ :type type_: type
+
+ :rtype: bool
+ """
+
+ return type_ in {int, str, bool, float}
+
+ @classmethod
+ def _is_bytes(cls, obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: bool
+ """
+
+ return cls._is_bytes_type(type(obj))
+
+ @classmethod
+ def _is_bytes_type(cls, type_):
+ """
+ :type type_: type
+
+ :rtype: bool
+ """
+
+ return type_.__name__ in cls._TYPE_NAMES_BYTES
+
+ @classmethod
+ def _serialize_list(cls, list_):
+ """
+ :type list_: list
+
+ :rtype: list
+ """
+
+ list_serialized = []
+
+ for item in list_:
+ item_serialized = cls.serialize(item)
+ list_serialized.append(item_serialized)
+
+ return list_serialized
+
+ @classmethod
+ def _get_obj_raw(cls, obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: dict
+ """
+
+ return obj if type(obj) == dict else obj.__dict__
+
+ @classmethod
+ def _serialize_dict(cls, dict_):
+ """
+ :type dict_ dict
+
+ :rtype: dict
+ """
+
+ obj_serialized = {}
+
+ for key in dict_.keys():
+ item_serialized = cls.serialize(dict_[key])
+
+ if item_serialized is not None:
+ key = key.rstrip(cls._SUFFIX_KEY_OVERLAPPING)
+ key = key.lstrip(cls._PREFIX_KEY_PROTECTED)
+ obj_serialized[key] = item_serialized
+
+ return obj_serialized
+
+
+class ValueTypes(object):
+ """
+ :type _main: type|None
+ :type _sub: type|None
+ """
+
+ def __init__(self, main, sub):
+ """
+ :type main: type|None
+ :type sub: type|None
+ """
+
+ self._main = main
+ self._sub = sub
+
+ @property
+ def main(self):
+ """
+ :rtype: type|None
+ """
+
+ return self._main
+
+ @property
+ def sub(self):
+ """
+ :rtype: type|None
+ """
+
+ return self._sub
+
+
+class ValueSpecs(object):
+ """
+ :type _name: str|None
+ :type _types: ValueTypes|None
+ """
+
+ def __init__(self, name, types):
+ """
+ :type name: str|None
+ :type types: ValueTypes|None
+ """
+
+ self._name = name
+ self._types = types
+
+ @property
+ def name(self):
+ """
+ :rtype: str|None
+ """
+
+ return self._name
+
+ @property
+ def types(self):
+ """
+ :rtype: ValueTypes|None
+ """
+
+ return self._types
+
+
+def register_adapter(target_class, adapter):
+ """
+ :type target_class: type
+ :type adapter: JsonAdapter|type
+
+ :rtype: None
+ """
+
+ JsonAdapter.register_custom_adapter(target_class, adapter)
+
+
+def json_to_class(cls, json_str):
+ """
+ :type cls: T|type
+ :type json_str: str
+
+ :rtype: T
+ """
+
+ obj_raw = json.loads(json_str)
+
+ return deserialize(cls, obj_raw)
+
+
+def deserialize(cls, obj_raw):
+ """
+ :type cls: T|type
+ :type obj_raw: int|str|bool|float|list|dict|None
+
+ :rtype: T
+ """
+
+ return JsonAdapter.deserialize(cls, obj_raw)
+
+
+def class_to_json(obj):
+ """
+ :type obj: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: int|str|bool|list|dict
+ """
+
+ obj_raw = serialize(obj)
+
+ return json.dumps(obj_raw, indent=_JSON_INDENT, sort_keys=True)
+
+
+def serialize(obj_cls):
+ """
+ :type obj_cls: int|str|bool|float|bytes|unicode|list|dict|object
+
+ :rtype: int|str|bool|list|dict
+ """
+
+ return JsonAdapter.serialize(obj_cls)
diff --git a/bunq/sdk/json/registry.py b/bunq/sdk/json/registry.py
new file mode 100644
index 0000000..2883c4b
--- /dev/null
+++ b/bunq/sdk/json/registry.py
@@ -0,0 +1,38 @@
+import datetime
+
+from bunq.sdk import context
+from bunq.sdk import model
+from bunq.sdk.json import adapters
+from bunq.sdk.json import converter
+from bunq.sdk.model.generated import object_
+
+
+def initialize():
+ """
+ :rtype: None
+ """
+
+ converter.register_adapter(model.Installation, adapters.InstallationAdapter)
+ converter.register_adapter(
+ model.SessionServer,
+ adapters.SessionServerAdapter
+ )
+ converter.register_adapter(
+ context.InstallationContext,
+ adapters.InstallationContextAdapter
+ )
+ converter.register_adapter(
+ context.ApiEnvironmentType,
+ adapters.ApiEnvironmentTypeAdapter
+ )
+ converter.register_adapter(float, adapters.FloatAdapter)
+ converter.register_adapter(
+ object_.Geolocation,
+ adapters.GeolocationAdapter
+ )
+ converter.register_adapter(
+ object_.MonetaryAccountReference,
+ adapters.MonetaryAccountReferenceAdapter
+ )
+ converter.register_adapter(object_.ShareDetail, adapters.ShareDetailAdapter)
+ converter.register_adapter(datetime.datetime, adapters.DateTimeAdapter)
diff --git a/bunq/sdk/model/__init__.py b/bunq/sdk/model/__init__.py
new file mode 100644
index 0000000..ff4ffd1
--- /dev/null
+++ b/bunq/sdk/model/__init__.py
@@ -0,0 +1 @@
+from bunq.sdk.model.model import *
diff --git a/bunq/sdk/model/generated/__init__.py b/bunq/sdk/model/generated/__init__.py
new file mode 100644
index 0000000..faea808
--- /dev/null
+++ b/bunq/sdk/model/generated/__init__.py
@@ -0,0 +1 @@
+from bunq.sdk.model.generated.endpoint import *
diff --git a/bunq/sdk/model/generated/endpoint.py b/bunq/sdk/model/generated/endpoint.py
new file mode 100644
index 0000000..6882181
--- /dev/null
+++ b/bunq/sdk/model/generated/endpoint.py
@@ -0,0 +1,9894 @@
+# -*- coding: utf-8 -*-
+from bunq.sdk import client
+from bunq.sdk import context
+from bunq.sdk import model
+from bunq.sdk import security
+from bunq.sdk.json import converter
+from bunq.sdk.model.generated import object_
+
+
+class Invoice(model.BunqModel):
+ """
+ Used to view a bunq invoice.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _invoice_date: str
+ :type _invoice_number: str
+ :type _status: str
+ :type _group: list[object_.InvoiceItemGroup]
+ :type _total_vat_inclusive: object_.Amount
+ :type _total_vat_exclusive: object_.Amount
+ :type _total_vat: object_.Amount
+ :type _alias: object_.MonetaryAccountReference
+ :type _address: object_.Address
+ :type _counterparty_alias: object_.MonetaryAccountReference
+ :type _counterparty_address: object_.Address
+ :type _chamber_of_commerce_number: str
+ :type _vat_number: str
+ """
+
+ # Field constants.
+ FIELD_STATUS = "status"
+ FIELD_DESCRIPTION = "description"
+ FIELD_EXTERNAL_URL = "external_url"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/invoice"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/invoice/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "Invoice"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._invoice_date = None
+ self._invoice_number = None
+ self._status = None
+ self._group = None
+ self._total_vat_inclusive = None
+ self._total_vat_exclusive = None
+ self._total_vat = None
+ self._alias = None
+ self._address = None
+ self._counterparty_alias = None
+ self._counterparty_address = None
+ self._chamber_of_commerce_number = None
+ self._vat_number = None
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[Invoice]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, invoice_id,
+ custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type invoice_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Invoice
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ invoice_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def invoice_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._invoice_date
+
+ @property
+ def invoice_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._invoice_number
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def group(self):
+ """
+ :rtype: list[object_.InvoiceItemGroup]
+ """
+
+ return self._group
+
+ @property
+ def total_vat_inclusive(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat_inclusive
+
+ @property
+ def total_vat_exclusive(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat_exclusive
+
+ @property
+ def total_vat(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias
+
+ @property
+ def address(self):
+ """
+ :rtype: object_.Address
+ """
+
+ return self._address
+
+ @property
+ def counterparty_alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._counterparty_alias
+
+ @property
+ def counterparty_address(self):
+ """
+ :rtype: object_.Address
+ """
+
+ return self._counterparty_address
+
+ @property
+ def chamber_of_commerce_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._chamber_of_commerce_number
+
+ @property
+ def vat_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._vat_number
+
+
+class InvoiceByUser(model.BunqModel):
+ """
+ Used to list bunq invoices by user.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _invoice_date: str
+ :type _invoice_number: str
+ :type _status: str
+ :type _group: list[object_.InvoiceItemGroup]
+ :type _total_vat_inclusive: object_.Amount
+ :type _total_vat_exclusive: object_.Amount
+ :type _total_vat: object_.Amount
+ :type _alias: object_.MonetaryAccountReference
+ :type _address: object_.Address
+ :type _counterparty_alias: object_.MonetaryAccountReference
+ :type _counterparty_address: object_.Address
+ :type _chamber_of_commerce_number: str
+ :type _vat_number: str
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/invoice"
+ _ENDPOINT_URL_READ = "user/{}/invoice/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "Invoice"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._invoice_date = None
+ self._invoice_number = None
+ self._status = None
+ self._group = None
+ self._total_vat_inclusive = None
+ self._total_vat_exclusive = None
+ self._total_vat = None
+ self._alias = None
+ self._address = None
+ self._counterparty_alias = None
+ self._counterparty_address = None
+ self._chamber_of_commerce_number = None
+ self._vat_number = None
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[InvoiceByUser]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def get(cls, api_context, user_id, invoice_by_user_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type invoice_by_user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: InvoiceByUser
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ invoice_by_user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def invoice_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._invoice_date
+
+ @property
+ def invoice_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._invoice_number
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def group(self):
+ """
+ :rtype: list[object_.InvoiceItemGroup]
+ """
+
+ return self._group
+
+ @property
+ def total_vat_inclusive(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat_inclusive
+
+ @property
+ def total_vat_exclusive(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat_exclusive
+
+ @property
+ def total_vat(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._total_vat
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias
+
+ @property
+ def address(self):
+ """
+ :rtype: object_.Address
+ """
+
+ return self._address
+
+ @property
+ def counterparty_alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._counterparty_alias
+
+ @property
+ def counterparty_address(self):
+ """
+ :rtype: object_.Address
+ """
+
+ return self._counterparty_address
+
+ @property
+ def chamber_of_commerce_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._chamber_of_commerce_number
+
+ @property
+ def vat_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._vat_number
+
+
+class ChatConversation(model.BunqModel):
+ """
+ Manages user's conversations.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/chat-conversation"
+ _ENDPOINT_URL_READ = "user/{}/chat-conversation/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "ChatConversation"
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[ChatConversation]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def get(cls, api_context, user_id, chat_conversation_id,
+ custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type chat_conversation_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ChatConversation
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ chat_conversation_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+
+class ChatMessageAttachment(model.BunqModel):
+ """
+ Create new messages holding file attachments.
+
+ :type _id_: int
+ """
+
+ # Field constants.
+ FIELD_CLIENT_MESSAGE_UUID = "client_message_uuid"
+ FIELD_ATTACHMENT = "attachment"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/chat-conversation/{}/message-attachment"
+
+ # Object type.
+ _OBJECT_TYPE = "Id"
+
+ def __init__(self):
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, chat_conversation_id,
+ custom_headers=None):
+ """
+ Create a new message holding a file attachment to a specific
+ conversation.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type chat_conversation_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ chat_conversation_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class ChatMessageText(model.BunqModel):
+ """
+ Endpoint for the type of chat message that carries text.
+
+ :type _id_: int
+ """
+
+ # Field constants.
+ FIELD_CLIENT_MESSAGE_UUID = "client_message_uuid"
+ FIELD_TEXT = "text"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/chat-conversation/{}/message-text"
+
+ # Object type.
+ _OBJECT_TYPE = "Id"
+
+ def __init__(self):
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, chat_conversation_id,
+ custom_headers=None):
+ """
+ Add a new text message to a specific conversation.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type chat_conversation_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ chat_conversation_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class ChatMessage(model.BunqModel):
+ """
+ Endpoint for retrieving the messages that are part of a conversation.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _conversation_id: int
+ :type _ticket_id: int
+ :type _creator: object_.LabelUser
+ :type _displayed_sender: object_.LabelUser
+ :type _content: model.BunqModel
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/chat-conversation/{}/message"
+
+ # Object type.
+ _OBJECT_TYPE = "ChatMessage"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._conversation_id = None
+ self._ticket_id = None
+ self._creator = None
+ self._displayed_sender = None
+ self._content = None
+
+ @classmethod
+ def list(cls, api_context, user_id, chat_conversation_id,
+ custom_headers=None):
+ """
+ Get all the messages that are part of a specific conversation.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type chat_conversation_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[ChatMessage]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ chat_conversation_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def conversation_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._conversation_id
+
+ @property
+ def ticket_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._ticket_id
+
+ @property
+ def creator(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._creator
+
+ @property
+ def displayed_sender(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._displayed_sender
+
+ @property
+ def content(self):
+ """
+ :rtype: model.BunqModel
+ """
+
+ return self._content
+
+
+class AttachmentConversationContent(model.BunqModel):
+ """
+ Fetch the raw content of an attachment with given ID. The raw content is the
+ base64 of a file, without any JSON wrapping.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/chat-conversation/{}/attachment/{}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentConversationContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, chat_conversation_id, attachment_id,
+ custom_headers=None):
+ """
+ Get the raw content of a specific attachment.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type chat_conversation_id: int
+ :type attachment_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ chat_conversation_id,
+ attachment_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class AttachmentPublicContent(model.BunqModel):
+ """
+ Fetch the raw content of a public attachment with given ID. The raw content
+ is the binary representation of a file, without any JSON wrapping.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "attachment-public/{}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentPublicContent"
+
+ @classmethod
+ def list(cls, api_context, attachment_public_uuid, custom_headers=None):
+ """
+ Get the raw content of a specific attachment.
+
+ :type api_context: context.ApiContext
+ :type attachment_public_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(attachment_public_uuid)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class AttachmentTabContent(model.BunqModel):
+ """
+ Fetch the raw content of a tab attachment with given ID. The raw content is
+ the binary representation of a file, without any JSON wrapping.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/attachment-tab/{" \
+ "}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentTabContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, attachment_tab_id,
+ custom_headers=None):
+ """
+ Get the raw content of a specific attachment.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type attachment_tab_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ attachment_tab_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class TabAttachmentTabContent(model.BunqModel):
+ """
+ Fetch the raw content of a tab attachment with given ID. The raw content is
+ the binary representation of a file, without any JSON wrapping.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "tab/{}/attachment/{}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "TabAttachmentTabContent"
+
+ @classmethod
+ def list(cls, api_context, tab_uuid, attachment_id, custom_headers=None):
+ """
+ Get the raw content of a specific attachment.
+
+ :type api_context: context.ApiContext
+ :type tab_uuid: str
+ :type attachment_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(tab_uuid, attachment_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class AttachmentMonetaryAccount(model.BunqModel):
+ """
+ This call is used to upload an attachment that can be referenced to in
+ payment requests and payments sent from a specific monetary account.
+ Attachments supported are png, jpg and gif.
+
+ :type _attachment: object_.Attachment
+ :type _id_: int
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/attachment"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentMonetaryAccount"
+
+ def __init__(self):
+ self._attachment = None
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_bytes, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Create a new monetary account attachment. Create a POST request with a
+ payload that contains the binary representation of the file, without any
+ JSON wrapping. Make sure you define the MIME type (i.e. image/jpeg) in
+ the Content-Type header. You are required to provide a description of
+ the attachment using the X-Bunq-Attachment-Description header.
+
+ :type api_context: context.ApiContext
+ :type request_bytes: bytes
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @property
+ def attachment(self):
+ """
+ :rtype: object_.Attachment
+ """
+
+ return self._attachment
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class AttachmentPublic(model.BunqModel):
+ """
+ This call is used to upload an attachment that can be referenced to as an
+ avatar (through the Avatar endpoint) or in a tab sent. Attachments supported
+ are png, jpg and gif.
+
+ :type _uuid: str
+ :type _created: str
+ :type _updated: str
+ :type _attachment: object_.Attachment
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "attachment-public"
+ _ENDPOINT_URL_READ = "attachment-public/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentPublic"
+
+ def __init__(self):
+ self._uuid = None
+ self._created = None
+ self._updated = None
+ self._attachment = None
+
+ @classmethod
+ def create(cls, api_context, request_bytes, custom_headers=None):
+ """
+ Create a new public attachment. Create a POST request with a payload
+ that contains a binary representation of the file, without any JSON
+ wrapping. Make sure you define the MIME type (i.e. image/jpeg, or
+ image/png) in the Content-Type header. You are required to provide a
+ description of the attachment using the X-Bunq-Attachment-Description
+ header.
+
+ :type api_context: context.ApiContext
+ :type request_bytes: bytes
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_CREATE
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def get(cls, api_context, attachment_public_uuid, custom_headers=None):
+ """
+ Get a specific attachment's metadata through its UUID. The Content-Type
+ header of the response will describe the MIME type of the attachment
+ file.
+
+ :type api_context: context.ApiContext
+ :type attachment_public_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: AttachmentPublic
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(attachment_public_uuid)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def uuid(self):
+ """
+ :rtype: str
+ """
+
+ return self._uuid
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def attachment(self):
+ """
+ :rtype: object_.Attachment
+ """
+
+ return self._attachment
+
+
+class AttachmentTab(model.BunqModel):
+ """
+ This call is used to upload an attachment that will be accessible only
+ through tabs. This can be used for example to upload special promotions or
+ other attachments. Attachments supported are png, jpg and gif.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _attachment: object_.Attachment
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/attachment-tab"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/attachment-tab/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "AttachmentTab"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._attachment = None
+
+ @classmethod
+ def create(cls, api_context, request_bytes, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Upload a new attachment to use with a tab, and to read its metadata.
+ Create a POST request with a payload that contains the binary
+ representation of the file, without any JSON wrapping. Make sure you
+ define the MIME type (i.e. image/jpeg) in the Content-Type header. You
+ are required to provide a description of the attachment using the
+ X-Bunq-Attachment-Description header.
+
+ :type api_context: context.ApiContext
+ :type request_bytes: bytes
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, attachment_tab_id,
+ custom_headers=None):
+ """
+ Get a specific attachment. The header of the response contains the
+ content-type of the attachment.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type attachment_tab_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: AttachmentTab
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ attachment_tab_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def attachment(self):
+ """
+ :rtype: object_.Attachment
+ """
+
+ return self._attachment
+
+
+class TabAttachmentTab(model.BunqModel):
+ """
+ This call is used to view an attachment that is linked to a tab.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _attachment: object_.Attachment
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_READ = "tab/{}/attachment/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "TabAttachmentTab"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._attachment = None
+
+ @classmethod
+ def get(cls, api_context, tab_uuid, tab_attachment_tab_id,
+ custom_headers=None):
+ """
+ Get a specific attachment. The header of the response contains the
+ content-type of the attachment.
+
+ :type api_context: context.ApiContext
+ :type tab_uuid: str
+ :type tab_attachment_tab_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: TabAttachmentTab
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(tab_uuid,
+ tab_attachment_tab_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def attachment(self):
+ """
+ :rtype: object_.Attachment
+ """
+
+ return self._attachment
+
+
+class Avatar(model.BunqModel):
+ """
+ Avatars are public images used to represent you or your company. Avatars are
+ used to represent users, monetary accounts and cash registers. Avatars
+ cannot be deleted, only replaced. Avatars can be updated after uploading the
+ image you would like to use through AttachmentPublic. Using the
+ attachment_public_uuid which is returned you can update your Avatar. Avatars
+ used for cash registers and company accounts will be reviewed by bunq.
+
+ :type _uuid: str
+ :type _image: list[object_.Image]
+ """
+
+ # Field constants.
+ FIELD_ATTACHMENT_PUBLIC_UUID = "attachment_public_uuid"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "avatar"
+ _ENDPOINT_URL_READ = "avatar/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "Avatar"
+
+ def __init__(self):
+ self._uuid = None
+ self._image = None
+
+ @classmethod
+ def create(cls, api_context, request_map, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def get(cls, api_context, avatar_uuid, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type avatar_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Avatar
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(avatar_uuid)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def uuid(self):
+ """
+ :rtype: str
+ """
+
+ return self._uuid
+
+ @property
+ def image(self):
+ """
+ :rtype: list[object_.Image]
+ """
+
+ return self._image
+
+
+class CardDebit(model.BunqModel):
+ """
+ With bunq it is possible to order debit cards that can then be connected
+ with each one of the monetary accounts the user has access to (including
+ connected accounts).
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _second_line: str
+ :type _name_on_card: str
+ :type _status: str
+ :type _order_status: str
+ :type _expiry_date: str
+ :type _limit: list[object_.CardLimit]
+ :type _country_permission: list[object_.CardCountryPermission]
+ :type _alias: object_.LabelUser
+ """
+
+ # Field constants.
+ FIELD_SECOND_LINE = "second_line"
+ FIELD_NAME_ON_CARD = "name_on_card"
+ FIELD_PIN_CODE = "pin_code"
+ FIELD_ALIAS = "alias"
+ FIELD_TYPE = "type"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/card-debit"
+
+ # Object type.
+ _OBJECT_TYPE = "CardDebit"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._second_line = None
+ self._name_on_card = None
+ self._status = None
+ self._order_status = None
+ self._expiry_date = None
+ self._limit = None
+ self._country_permission = None
+ self._alias = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, custom_headers=None):
+ """
+ Create a new debit card request.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: CardDebit
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ request_bytes = security.encrypt(api_context, request_bytes,
+ custom_headers)
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def second_line(self):
+ """
+ :rtype: str
+ """
+
+ return self._second_line
+
+ @property
+ def name_on_card(self):
+ """
+ :rtype: str
+ """
+
+ return self._name_on_card
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def order_status(self):
+ """
+ :rtype: str
+ """
+
+ return self._order_status
+
+ @property
+ def expiry_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._expiry_date
+
+ @property
+ def limit(self):
+ """
+ :rtype: list[object_.CardLimit]
+ """
+
+ return self._limit
+
+ @property
+ def country_permission(self):
+ """
+ :rtype: list[object_.CardCountryPermission]
+ """
+
+ return self._country_permission
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._alias
+
+
+class CardName(model.BunqModel):
+ """
+ Endpoint for getting all the accepted card names for a user. As bunq do not
+ allow total freedom in choosing the name that is going to be printed on the
+ card, the following formats are accepted: Name Surname, N. Surname, N
+ Surname or Surname.
+
+ :type _possible_card_name_array: list[str]
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/card-name"
+
+ # Object type.
+ _OBJECT_TYPE = "CardUserNameArray"
+
+ def __init__(self):
+ self._possible_card_name_array = None
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ Return all the accepted card names for a specific user.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[CardName]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def possible_card_name_array(self):
+ """
+ :rtype: list[str]
+ """
+
+ return self._possible_card_name_array
+
+
+class Card(model.BunqModel):
+ """
+ Endpoint for retrieving details for the cards the user has access to.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _public_uuid: str
+ :type _second_line: str
+ :type _status: str
+ :type _order_status: str
+ :type _expiry_date: str
+ :type _name_on_card: str
+ :type _primary_account_number_four_digit: str
+ :type _limit: list[object_.CardLimit]
+ :type _mag_stripe_permission: object_.CardMagStripePermission
+ :type _country_permission: list[object_.CardCountryPermission]
+ :type _label_monetary_account_ordered: object_.MonetaryAccountReference
+ :type _label_monetary_account_current: object_.MonetaryAccountReference
+ """
+
+ # Field constants.
+ FIELD_PIN_CODE = "pin_code"
+ FIELD_ACTIVATION_CODE = "activation_code"
+ FIELD_STATUS = "status"
+ FIELD_LIMIT = "limit"
+ FIELD_MAG_STRIPE_PERMISSION = "mag_stripe_permission"
+ FIELD_COUNTRY_PERMISSION = "country_permission"
+ FIELD_MONETARY_ACCOUNT_CURRENT_ID = "monetary_account_current_id"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_UPDATE = "user/{}/card/{}"
+ _ENDPOINT_URL_READ = "user/{}/card/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/card"
+
+ # Object type.
+ _OBJECT_TYPE = "CardDebit"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._public_uuid = None
+ self._second_line = None
+ self._status = None
+ self._order_status = None
+ self._expiry_date = None
+ self._name_on_card = None
+ self._primary_account_number_four_digit = None
+ self._limit = None
+ self._mag_stripe_permission = None
+ self._country_permission = None
+ self._label_monetary_account_ordered = None
+ self._label_monetary_account_current = None
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, card_id,
+ custom_headers=None):
+ """
+ Update the card details. Allow to change pin code, status, limits,
+ country permissions and the monetary account connected to the card. When
+ the card has been received, it can be also activated through this
+ endpoint.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type card_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Card
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ request_bytes = security.encrypt(api_context, request_bytes,
+ custom_headers)
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id, card_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def get(cls, api_context, user_id, card_id, custom_headers=None):
+ """
+ Return the details of a specific card.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type card_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Card
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id, card_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ Return all the cards available to the user.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[Card]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def public_uuid(self):
+ """
+ :rtype: str
+ """
+
+ return self._public_uuid
+
+ @property
+ def second_line(self):
+ """
+ :rtype: str
+ """
+
+ return self._second_line
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def order_status(self):
+ """
+ :rtype: str
+ """
+
+ return self._order_status
+
+ @property
+ def expiry_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._expiry_date
+
+ @property
+ def name_on_card(self):
+ """
+ :rtype: str
+ """
+
+ return self._name_on_card
+
+ @property
+ def primary_account_number_four_digit(self):
+ """
+ :rtype: str
+ """
+
+ return self._primary_account_number_four_digit
+
+ @property
+ def limit(self):
+ """
+ :rtype: list[object_.CardLimit]
+ """
+
+ return self._limit
+
+ @property
+ def mag_stripe_permission(self):
+ """
+ :rtype: object_.CardMagStripePermission
+ """
+
+ return self._mag_stripe_permission
+
+ @property
+ def country_permission(self):
+ """
+ :rtype: list[object_.CardCountryPermission]
+ """
+
+ return self._country_permission
+
+ @property
+ def label_monetary_account_ordered(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._label_monetary_account_ordered
+
+ @property
+ def label_monetary_account_current(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._label_monetary_account_current
+
+
+class CashRegisterQrCodeContent(model.BunqModel):
+ """
+ Show the raw contents of a QR code. First you need to created a QR code
+ using ../cash-register/{id}/qr-code.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/qr-code/{}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "CashRegisterQrCodeContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ qr_code_id, custom_headers=None):
+ """
+ Show the raw contents of a QR code
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type qr_code_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ qr_code_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class CashRegisterQrCode(model.BunqModel):
+ """
+ Once your CashRegister has been activated you can create a QR code for it.
+ The visibility of a tab can be modified to be linked to this QR code. If a
+ user of the bunq app scans this QR code, the linked tab will be shown on his
+ device.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _status: str
+ :type _cash_register: CashRegister
+ :type _tab_object: Tab
+ """
+
+ # Field constants.
+ FIELD_STATUS = "status"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/qr-code"
+ _ENDPOINT_URL_UPDATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/qr-code/{}"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/qr-code/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/qr-code"
+
+ # Object type.
+ _OBJECT_TYPE = "TokenQrCashRegister"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._status = None
+ self._cash_register = None
+ self._tab_object = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, custom_headers=None):
+ """
+ Create a new QR code for this CashRegister. You can only have one ACTIVE
+ CashRegister QR code at the time.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, cash_register_qr_code_id, custom_headers=None):
+ """
+ Modify a QR code in a given CashRegister. You can only have one ACTIVE
+ CashRegister QR code at the time.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type cash_register_qr_code_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ cash_register_qr_code_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ cash_register_qr_code_id, custom_headers=None):
+ """
+ Get the information of a specific QR code. To get the RAW content of the
+ QR code use ../qr-code/{id}/content
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type cash_register_qr_code_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: CashRegisterQrCode
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ cash_register_qr_code_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ custom_headers=None):
+ """
+ Get a collection of QR code information from a given CashRegister
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[CashRegisterQrCode]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def cash_register(self):
+ """
+ :rtype: CashRegister
+ """
+
+ return self._cash_register
+
+ @property
+ def tab_object(self):
+ """
+ :rtype: Tab
+ """
+
+ return self._tab_object
+
+
+class CashRegister(model.BunqModel):
+ """
+ CashRegisters act as an point of sale. They have a specific name and avatar,
+ and optionally a location. A CashRegister is used to create Tabs. A
+ CashRegister can have an QR code that links to one of its Tabs.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _name: str
+ :type _status: str
+ :type _avatar: object_.Avatar
+ :type _location: object_.Geolocation
+ :type _notification_filters: list[object_.NotificationFilter]
+ :type _tab_text_waiting_screen: list[object_.TabTextWaitingScreen]
+ """
+
+ # Field constants.
+ FIELD_NAME = "name"
+ FIELD_STATUS = "status"
+ FIELD_AVATAR_UUID = "avatar_uuid"
+ FIELD_LOCATION = "location"
+ FIELD_NOTIFICATION_FILTERS = "notification_filters"
+ FIELD_TAB_TEXT_WAITING_SCREEN = "tab_text_waiting_screen"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/cash-register"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/cash-register/{}"
+ _ENDPOINT_URL_UPDATE = "user/{}/monetary-account/{}/cash-register/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register"
+
+ # Object type.
+ _OBJECT_TYPE = "CashRegister"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._name = None
+ self._status = None
+ self._avatar = None
+ self._location = None
+ self._notification_filters = None
+ self._tab_text_waiting_screen = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Create a new CashRegister. Only an UserCompany can create a
+ CashRegisters. They need to be created with status PENDING_APPROVAL, an
+ bunq admin has to approve your CashRegister before you can use it. In
+ the sandbox testing environment an CashRegister will be automatically
+ approved immediately after creation.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ custom_headers=None):
+ """
+ Get a specific CashRegister.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: CashRegister
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, custom_headers=None):
+ """
+ Modify or close an existing CashRegister. You must set the status back
+ to PENDING_APPROVAL if you modify the name, avatar or location of a
+ CashRegister. To close a cash register put its status to CLOSED.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Get a collection of CashRegister for a given user and monetary account.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[CashRegister]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def name(self):
+ """
+ :rtype: str
+ """
+
+ return self._name
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def avatar(self):
+ """
+ :rtype: object_.Avatar
+ """
+
+ return self._avatar
+
+ @property
+ def location(self):
+ """
+ :rtype: object_.Geolocation
+ """
+
+ return self._location
+
+ @property
+ def notification_filters(self):
+ """
+ :rtype: list[object_.NotificationFilter]
+ """
+
+ return self._notification_filters
+
+ @property
+ def tab_text_waiting_screen(self):
+ """
+ :rtype: list[object_.TabTextWaitingScreen]
+ """
+
+ return self._tab_text_waiting_screen
+
+
+class Tab(model.BunqModel):
+ """
+ Once your CashRegister has been activated you can use it to create Tabs. A
+ Tab is a template for a payment. In contrast to requests a Tab is not
+ pointed towards a specific user. Any user can pay the Tab as long as it is
+ made visible by you. The creation of a Tab happens with /tab-usage-single or
+ /tab-usage-multiple. A TabUsageSingle is a Tab that can be paid once. A
+ TabUsageMultiple is a Tab that can be paid multiple times by different
+ users.
+
+ :type _TabUsageSingle: TabUsageSingle
+ :type _TabUsageMultiple: TabUsageMultiple
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/cash-register/{}/tab/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register/{}/tab"
+
+ # Object type.
+ _OBJECT_TYPE = "Tab"
+
+ def __init__(self):
+ self._TabUsageSingle = None
+ self._TabUsageMultiple = None
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ tab_uuid, custom_headers=None):
+ """
+ Get a specific tab. This returns a TabUsageSingle or TabUsageMultiple.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Tab
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ cash_register_id, tab_uuid)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ custom_headers=None):
+ """
+ Get a collection of tabs.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[Tab]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text)
+
+ @property
+ def TabUsageSingle(self):
+ """
+ :rtype: TabUsageSingle
+ """
+
+ return self._TabUsageSingle
+
+ @property
+ def TabUsageMultiple(self):
+ """
+ :rtype: TabUsageMultiple
+ """
+
+ return self._TabUsageMultiple
+
+
+class TabUsageSingle(model.BunqModel):
+ """
+ TabUsageSingle is a Tab that can be paid once. The TabUsageSingle is created
+ with the status OPEN. Optionally you can add TabItems to the tab using
+ /tab/_/tab-item, TabItems don't affect the total amount of the Tab. However,
+ if you've created any TabItems for a Tab the sum of the amounts of these
+ items must be equal to the total_amount of the Tab when you change its
+ status to WAITING_FOR_PAYMENT. By setting the visibility object a
+ TabUsageSingle with the status OPEN or WAITING_FOR_PAYMENT can be made
+ visible to customers. As soon as a customer pays the TabUsageSingle its
+ status changes to PAID, and it can't be paid again.
+
+ :type _uuid: str
+ :type _created: str
+ :type _updated: str
+ :type _merchant_reference: str
+ :type _description: str
+ :type _status: str
+ :type _amount_total: object_.Amount
+ :type _amount_paid: object_.Amount
+ :type _qr_code_token: str
+ :type _tab_url: str
+ :type _visibility: object_.TabVisibility
+ :type _minimum_age: bool
+ :type _require_address: str
+ :type _redirect_url: str
+ :type _expiration: str
+ :type _alias: object_.MonetaryAccountReference
+ :type _cash_register_location: object_.Geolocation
+ :type _tab_item: list[TabItem]
+ :type _tab_attachment: list[object_.BunqId]
+ """
+
+ # Field constants.
+ FIELD_MERCHANT_REFERENCE = "merchant_reference"
+ FIELD_DESCRIPTION = "description"
+ FIELD_STATUS = "status"
+ FIELD_AMOUNT_TOTAL = "amount_total"
+ FIELD_ALLOW_AMOUNT_HIGHER = "allow_amount_higher"
+ FIELD_ALLOW_AMOUNT_LOWER = "allow_amount_lower"
+ FIELD_WANT_TIP = "want_tip"
+ FIELD_MINIMUM_AGE = "minimum_age"
+ FIELD_REQUIRE_ADDRESS = "require_address"
+ FIELD_REDIRECT_URL = "redirect_url"
+ FIELD_VISIBILITY = "visibility"
+ FIELD_EXPIRATION = "expiration"
+ FIELD_TAB_ATTACHMENT = "tab_attachment"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-single"
+ _ENDPOINT_URL_UPDATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-single/{}"
+ _ENDPOINT_URL_DELETE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-single/{}"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-single/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-single"
+
+ # Object type.
+ _OBJECT_TYPE = "TabUsageSingle"
+
+ def __init__(self):
+ self._uuid = None
+ self._created = None
+ self._updated = None
+ self._merchant_reference = None
+ self._description = None
+ self._status = None
+ self._amount_total = None
+ self._amount_paid = None
+ self._qr_code_token = None
+ self._tab_url = None
+ self._visibility = None
+ self._minimum_age = None
+ self._require_address = None
+ self._redirect_url = None
+ self._expiration = None
+ self._alias = None
+ self._cash_register_location = None
+ self._tab_item = None
+ self._tab_attachment = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, custom_headers=None):
+ """
+ Create a TabUsageSingle. The initial status must be OPEN
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, tab_usage_single_uuid, custom_headers=None):
+ """
+ Modify a specific TabUsageSingle. You can change the amount_total,
+ status and visibility. Once you change the status to WAITING_FOR_PAYMENT
+ the TabUsageSingle will expire after 5 minutes (default) or up to 1 hour
+ if a different expiration is provided.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_single_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_single_uuid)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def delete(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ tab_usage_single_uuid, custom_headers=None):
+ """
+ Cancel a specific TabUsageSingle. This request returns an empty
+ response.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_single_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype None:
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_DELETE.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_single_uuid)
+ api_client.delete(endpoint_url, custom_headers)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ tab_usage_single_uuid, custom_headers=None):
+ """
+ Get a specific TabUsageSingle.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_single_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: TabUsageSingle
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_single_uuid)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ custom_headers=None):
+ """
+ Get a collection of TabUsageSingle.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[TabUsageSingle]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def uuid(self):
+ """
+ :rtype: str
+ """
+
+ return self._uuid
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def merchant_reference(self):
+ """
+ :rtype: str
+ """
+
+ return self._merchant_reference
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def amount_total(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._amount_total
+
+ @property
+ def amount_paid(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._amount_paid
+
+ @property
+ def qr_code_token(self):
+ """
+ :rtype: str
+ """
+
+ return self._qr_code_token
+
+ @property
+ def tab_url(self):
+ """
+ :rtype: str
+ """
+
+ return self._tab_url
+
+ @property
+ def visibility(self):
+ """
+ :rtype: object_.TabVisibility
+ """
+
+ return self._visibility
+
+ @property
+ def minimum_age(self):
+ """
+ :rtype: bool
+ """
+
+ return self._minimum_age
+
+ @property
+ def require_address(self):
+ """
+ :rtype: str
+ """
+
+ return self._require_address
+
+ @property
+ def redirect_url(self):
+ """
+ :rtype: str
+ """
+
+ return self._redirect_url
+
+ @property
+ def expiration(self):
+ """
+ :rtype: str
+ """
+
+ return self._expiration
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias
+
+ @property
+ def cash_register_location(self):
+ """
+ :rtype: object_.Geolocation
+ """
+
+ return self._cash_register_location
+
+ @property
+ def tab_item(self):
+ """
+ :rtype: list[TabItem]
+ """
+
+ return self._tab_item
+
+ @property
+ def tab_attachment(self):
+ """
+ :rtype: list[object_.BunqId]
+ """
+
+ return self._tab_attachment
+
+
+class TabItem(model.BunqModel):
+ """
+ Used to get items on a tab.
+
+ :type _id_: int
+ :type _description: str
+ :type _ean_code: str
+ :type _avatar_attachment: object_.AttachmentPublic
+ :type _tab_attachment: list[object_.AttachmentTab]
+ :type _quantity: str
+ :type _amount: object_.Amount
+ """
+
+ # Object type.
+ _OBJECT_TYPE = "TabItem"
+
+ def __init__(self):
+ self._id_ = None
+ self._description = None
+ self._ean_code = None
+ self._avatar_attachment = None
+ self._tab_attachment = None
+ self._quantity = None
+ self._amount = None
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+ @property
+ def ean_code(self):
+ """
+ :rtype: str
+ """
+
+ return self._ean_code
+
+ @property
+ def avatar_attachment(self):
+ """
+ :rtype: object_.AttachmentPublic
+ """
+
+ return self._avatar_attachment
+
+ @property
+ def tab_attachment(self):
+ """
+ :rtype: list[object_.AttachmentTab]
+ """
+
+ return self._tab_attachment
+
+ @property
+ def quantity(self):
+ """
+ :rtype: str
+ """
+
+ return self._quantity
+
+ @property
+ def amount(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._amount
+
+
+class TabUsageMultiple(model.BunqModel):
+ """
+ TabUsageMultiple is a Tab that can be paid by multiple users. Just like the
+ TabUsageSingle it is created with the status OPEN, the visibility can be
+ defined in the visibility object and TabItems can be added as long as the
+ status is OPEN. When you change the status to PAYABLE any bunq user can use
+ the tab to make a payment to your account. After an user has paid your
+ TabUsageMultiple the status will not change, it will stay PAYABLE. For
+ example: you can create a TabUsageMultiple with require_address set to true.
+ Now show the QR code of this Tab on your webshop, and any bunq user can
+ instantly pay and order something from your webshop.
+
+ :type _uuid: str
+ :type _created: str
+ :type _updated: str
+ :type _description: str
+ :type _status: str
+ :type _amount_total: object_.Amount
+ :type _qr_code_token: str
+ :type _tab_url: str
+ :type _visibility: object_.TabVisibility
+ :type _minimum_age: bool
+ :type _require_address: str
+ :type _redirect_url: str
+ :type _expiration: str
+ :type _alias: object_.MonetaryAccountReference
+ :type _cash_register_location: object_.Geolocation
+ :type _tab_item: list[TabItem]
+ :type _tab_attachment: list[object_.BunqId]
+ """
+
+ # Field constants.
+ FIELD_DESCRIPTION = "description"
+ FIELD_STATUS = "status"
+ FIELD_AMOUNT_TOTAL = "amount_total"
+ FIELD_ALLOW_AMOUNT_HIGHER = "allow_amount_higher"
+ FIELD_ALLOW_AMOUNT_LOWER = "allow_amount_lower"
+ FIELD_WANT_TIP = "want_tip"
+ FIELD_MINIMUM_AGE = "minimum_age"
+ FIELD_REQUIRE_ADDRESS = "require_address"
+ FIELD_REDIRECT_URL = "redirect_url"
+ FIELD_VISIBILITY = "visibility"
+ FIELD_EXPIRATION = "expiration"
+ FIELD_TAB_ATTACHMENT = "tab_attachment"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-multiple"
+ _ENDPOINT_URL_UPDATE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-multiple/{}"
+ _ENDPOINT_URL_DELETE = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-multiple/{}"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-multiple/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/cash-register/{" \
+ "}/tab-usage-multiple"
+
+ # Object type.
+ _OBJECT_TYPE = "TabUsageMultiple"
+
+ def __init__(self):
+ self._uuid = None
+ self._created = None
+ self._updated = None
+ self._description = None
+ self._status = None
+ self._amount_total = None
+ self._qr_code_token = None
+ self._tab_url = None
+ self._visibility = None
+ self._minimum_age = None
+ self._require_address = None
+ self._redirect_url = None
+ self._expiration = None
+ self._alias = None
+ self._cash_register_location = None
+ self._tab_item = None
+ self._tab_attachment = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, custom_headers=None):
+ """
+ Create a TabUsageMultiple. On creation the status must be set to OPEN
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, monetary_account_id,
+ cash_register_id, tab_usage_multiple_uuid, custom_headers=None):
+ """
+ Modify a specific TabUsageMultiple. You can change the amount_total,
+ status and visibility. Once you change the status to PAYABLE the
+ TabUsageMultiple will expire after a year (default). If you've created
+ any TabItems for a Tab the sum of the amounts of these items must be
+ equal to the total_amount of the Tab when you change its status to
+ PAYABLE.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_multiple_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: str
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_multiple_uuid)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_uuid(response.text)
+
+ @classmethod
+ def delete(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ tab_usage_multiple_uuid, custom_headers=None):
+ """
+ Close a specific TabUsageMultiple. This request returns an empty
+ response.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_multiple_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype None:
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_DELETE.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_multiple_uuid)
+ api_client.delete(endpoint_url, custom_headers)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ tab_usage_multiple_uuid, custom_headers=None):
+ """
+ Get a specific TabUsageMultiple.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type tab_usage_multiple_uuid: str
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: TabUsageMultiple
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ cash_register_id,
+ tab_usage_multiple_uuid)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id, cash_register_id,
+ custom_headers=None):
+ """
+ Get a collection of TabUsageMultiple.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type cash_register_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[TabUsageMultiple]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ cash_register_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def uuid(self):
+ """
+ :rtype: str
+ """
+
+ return self._uuid
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def amount_total(self):
+ """
+ :rtype: object_.Amount
+ """
+
+ return self._amount_total
+
+ @property
+ def qr_code_token(self):
+ """
+ :rtype: str
+ """
+
+ return self._qr_code_token
+
+ @property
+ def tab_url(self):
+ """
+ :rtype: str
+ """
+
+ return self._tab_url
+
+ @property
+ def visibility(self):
+ """
+ :rtype: object_.TabVisibility
+ """
+
+ return self._visibility
+
+ @property
+ def minimum_age(self):
+ """
+ :rtype: bool
+ """
+
+ return self._minimum_age
+
+ @property
+ def require_address(self):
+ """
+ :rtype: str
+ """
+
+ return self._require_address
+
+ @property
+ def redirect_url(self):
+ """
+ :rtype: str
+ """
+
+ return self._redirect_url
+
+ @property
+ def expiration(self):
+ """
+ :rtype: str
+ """
+
+ return self._expiration
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias
+
+ @property
+ def cash_register_location(self):
+ """
+ :rtype: object_.Geolocation
+ """
+
+ return self._cash_register_location
+
+ @property
+ def tab_item(self):
+ """
+ :rtype: list[TabItem]
+ """
+
+ return self._tab_item
+
+ @property
+ def tab_attachment(self):
+ """
+ :rtype: list[object_.BunqId]
+ """
+
+ return self._tab_attachment
+
+
+class CertificatePinned(model.BunqModel):
+ """
+ This endpoint allow you to pin the certificate chains to your account. These
+ certificate chains are used for SSL validation whenever a callback is
+ initiated to one of your https callback urls.
+
+ :type _certificate_chain: list[object_.Certificate]
+ :type _id_: int
+ """
+
+ # Field constants.
+ FIELD_CERTIFICATE_CHAIN = "certificate_chain"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/certificate-pinned"
+ _ENDPOINT_URL_DELETE = "user/{}/certificate-pinned/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/certificate-pinned"
+ _ENDPOINT_URL_READ = "user/{}/certificate-pinned/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "CertificatePinned"
+
+ def __init__(self):
+ self._certificate_chain = None
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, custom_headers=None):
+ """
+ Pin the certificate chain.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def delete(cls, api_context, user_id, certificate_pinned_id,
+ custom_headers=None):
+ """
+ Remove the pinned certificate chain with the specific ID.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type certificate_pinned_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype None:
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_DELETE.format(user_id,
+ certificate_pinned_id)
+ api_client.delete(endpoint_url, custom_headers)
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ List all the pinned certificate chain for the given user.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[CertificatePinned]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def get(cls, api_context, user_id, certificate_pinned_id,
+ custom_headers=None):
+ """
+ Get the pinned certificate chain with the specified ID.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type certificate_pinned_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: CertificatePinned
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ certificate_pinned_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def certificate_chain(self):
+ """
+ :rtype: list[object_.Certificate]
+ """
+
+ return self._certificate_chain
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class DeviceServer(model.BunqModel):
+ """
+ After having created an Installation you can now create a DeviceServer. A
+ DeviceServer is needed to do a login call with session-server.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _description: str
+ :type _ip: str
+ :type _status: str
+ """
+
+ # Field constants.
+ FIELD_DESCRIPTION = "description"
+ FIELD_SECRET = "secret"
+ FIELD_PERMITTED_IPS = "permitted_ips"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "device-server"
+ _ENDPOINT_URL_READ = "device-server/{}"
+ _ENDPOINT_URL_LISTING = "device-server"
+
+ # Object type.
+ _OBJECT_TYPE = "DeviceServer"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._description = None
+ self._ip = None
+ self._status = None
+
+ @classmethod
+ def create(cls, api_context, request_map, custom_headers=None):
+ """
+ Create a new DeviceServer. Provide the Installation token in the
+ "X-Bunq-Client-Authentication" header. And sign this request with the
+ key of which you used the public part to create the Installation. Your
+ API key will be bound to the ip address of this DeviceServer.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, device_server_id, custom_headers=None):
+ """
+ Get one of your DeviceServers.
+
+ :type api_context: context.ApiContext
+ :type device_server_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: DeviceServer
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(device_server_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, custom_headers=None):
+ """
+ Get a collection of all the DeviceServers you have created.
+
+ :type api_context: context.ApiContext
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[DeviceServer]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+ @property
+ def ip(self):
+ """
+ :rtype: str
+ """
+
+ return self._ip
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+
+class Device(model.BunqModel):
+ """
+ Used to get a Device or a listing of Devices. Creating a DeviceServer should
+ happen via /device-server
+
+ :type _DevicePhone: DevicePhone
+ :type _DeviceServer: DeviceServer
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_READ = "device/{}"
+ _ENDPOINT_URL_LISTING = "device"
+
+ # Object type.
+ _OBJECT_TYPE = "Device"
+
+ def __init__(self):
+ self._DevicePhone = None
+ self._DeviceServer = None
+
+ @classmethod
+ def get(cls, api_context, device_id, custom_headers=None):
+ """
+ Get a single Device. A Device is either a DevicePhone or a DeviceServer.
+
+ :type api_context: context.ApiContext
+ :type device_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: Device
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(device_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text)
+
+ @classmethod
+ def list(cls, api_context, custom_headers=None):
+ """
+ Get a collection of Devices. A Device is either a DevicePhone or a
+ DeviceServer.
+
+ :type api_context: context.ApiContext
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[Device]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text)
+
+ @property
+ def DevicePhone(self):
+ """
+ :rtype: DevicePhone
+ """
+
+ return self._DevicePhone
+
+ @property
+ def DeviceServer(self):
+ """
+ :rtype: DeviceServer
+ """
+
+ return self._DeviceServer
+
+
+class DevicePhone(model.BunqModel):
+ """
+ Used to register a device. This is the only unsigned/verified request.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _description: str
+ :type _phone_number: str
+ :type _os: str
+ :type _status: str
+ """
+
+ # Field constants.
+ FIELD_DESCRIPTION = "description"
+ FIELD_PHONE_NUMBER = "phone_number"
+
+ # Object type.
+ _OBJECT_TYPE = "DevicePhone"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._description = None
+ self._phone_number = None
+ self._os = None
+ self._status = None
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+ @property
+ def phone_number(self):
+ """
+ :rtype: str
+ """
+
+ return self._phone_number
+
+ @property
+ def os(self):
+ """
+ :rtype: str
+ """
+
+ return self._os
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+
+class DraftShareInviteBankQrCodeContent(model.BunqModel):
+ """
+ This call returns the raw content of the QR code that links to this draft
+ share invite. When a bunq user scans this QR code with the bunq app the
+ draft share invite will be shown on his/her device.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/draft-share-invite-bank/{}/qr-code-content"
+
+ # Object type.
+ _OBJECT_TYPE = "DraftShareInviteBankQrCodeContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, draft_share_invite_bank_id,
+ custom_headers=None):
+ """
+ Returns the raw content of the QR code that links to this draft share
+ invite. The raw content is the binary representation of a file, without
+ any JSON wrapping.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type draft_share_invite_bank_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ draft_share_invite_bank_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class DraftShareInviteBank(model.BunqModel):
+ """
+ Used to create a draft share invite for a monetary account with another bunq
+ user, as in the 'Connect' feature in the bunq app. The user that accepts the
+ invite can share one of their MonetaryAccounts with the user that created
+ the invite.
+
+ :type _user_alias_created: object_.LabelUser
+ :type _status: str
+ :type _expiration: str
+ :type _share_invite_bank_response_id: int
+ :type _draft_share_url: str
+ :type _draft_share_settings: object_.DraftShareInviteBankEntry
+ :type _id_: int
+ """
+
+ # Field constants.
+ FIELD_STATUS = "status"
+ FIELD_EXPIRATION = "expiration"
+ FIELD_DRAFT_SHARE_SETTINGS = "draft_share_settings"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/draft-share-invite-bank"
+ _ENDPOINT_URL_READ = "user/{}/draft-share-invite-bank/{}"
+ _ENDPOINT_URL_UPDATE = "user/{}/draft-share-invite-bank/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/draft-share-invite-bank"
+
+ # Object type.
+ _OBJECT_TYPE = "DraftShareInviteBank"
+
+ def __init__(self):
+ self._user_alias_created = None
+ self._status = None
+ self._expiration = None
+ self._share_invite_bank_response_id = None
+ self._draft_share_url = None
+ self._draft_share_settings = None
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, draft_share_invite_bank_id,
+ custom_headers=None):
+ """
+ Get the details of a specific draft of a share invite.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type draft_share_invite_bank_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: DraftShareInviteBank
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ draft_share_invite_bank_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id,
+ draft_share_invite_bank_id, custom_headers=None):
+ """
+ Update a draft share invite. When sending status CANCELLED it is
+ possible to cancel the draft share invite.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type draft_share_invite_bank_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: DraftShareInviteBank
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ draft_share_invite_bank_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[DraftShareInviteBank]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def user_alias_created(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._user_alias_created
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def expiration(self):
+ """
+ :rtype: str
+ """
+
+ return self._expiration
+
+ @property
+ def share_invite_bank_response_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._share_invite_bank_response_id
+
+ @property
+ def draft_share_url(self):
+ """
+ :rtype: str
+ """
+
+ return self._draft_share_url
+
+ @property
+ def draft_share_settings(self):
+ """
+ :rtype: object_.DraftShareInviteBankEntry
+ """
+
+ return self._draft_share_settings
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class ExportAnnualOverviewContent(model.BunqModel):
+ """
+ Fetch the raw content of an annual overview. The annual overview is always
+ in PDF format. Doc won't display the response of a request to get the
+ content of an annual overview.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/export-annual-overview/{}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "ExportAnnualOverviewContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, export_annual_overview_id,
+ custom_headers=None):
+ """
+ Used to retrieve the raw content of an annual overview.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type export_annual_overview_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ export_annual_overview_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class ExportAnnualOverview(model.BunqModel):
+ """
+ Used to create new and read existing annual overviews of all the user's
+ monetary accounts. Once created, annual overviews can be downloaded in PDF
+ format via the 'export-annual-overview/{id}/content' endpoint.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _year: int
+ :type _alias_user: object_.LabelUser
+ """
+
+ # Field constants.
+ FIELD_YEAR = "year"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/export-annual-overview"
+ _ENDPOINT_URL_READ = "user/{}/export-annual-overview/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/export-annual-overview"
+
+ # Object type.
+ _OBJECT_TYPE = "ExportAnnualOverview"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._year = None
+ self._alias_user = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, custom_headers=None):
+ """
+ Create a new annual overview for a specific year. An overview can be
+ generated only for a past year.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, export_annual_overview_id,
+ custom_headers=None):
+ """
+ Get an annual overview for a user by its id.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type export_annual_overview_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ExportAnnualOverview
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ export_annual_overview_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ List all the annual overviews for a user.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[ExportAnnualOverview]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def year(self):
+ """
+ :rtype: int
+ """
+
+ return self._year
+
+ @property
+ def alias_user(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._alias_user
+
+
+class CustomerStatementExportContent(model.BunqModel):
+ """
+ Fetch the raw content of a statement export. The returned file format could
+ be MT940, CSV or PDF depending on the statement format specified during the
+ statement creation. The doc won't display the response of a request to get
+ the content of a statement export.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/customer-statement/{" \
+ "}/content"
+
+ # Object type.
+ _OBJECT_TYPE = "CustomerStatementExportContent"
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id,
+ customer_statement_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type customer_statement_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: bytes
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id,
+ customer_statement_id)
+
+ return api_client.get(endpoint_url, custom_headers).content
+
+
+class CustomerStatementExport(model.BunqModel):
+ """
+ Used to create new and read existing statement exports. Statement exports
+ can be created in either CSV, MT940 or PDF file format.
+
+ :type _id_: int
+ :type _created: str
+ :type _updated: str
+ :type _date_start: str
+ :type _date_end: str
+ :type _status: str
+ :type _statement_number: int
+ :type _statement_format: str
+ :type _regional_format: str
+ :type _alias_monetary_account: object_.MonetaryAccountReference
+ """
+
+ # Field constants.
+ FIELD_STATEMENT_FORMAT = "statement_format"
+ FIELD_DATE_START = "date_start"
+ FIELD_DATE_END = "date_end"
+ FIELD_REGIONAL_FORMAT = "regional_format"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{}/customer-statement"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{}/customer-statement/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{}/customer-statement"
+ _ENDPOINT_URL_DELETE = "user/{}/monetary-account/{}/customer-statement/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "CustomerStatementExport"
+
+ def __init__(self):
+ self._id_ = None
+ self._created = None
+ self._updated = None
+ self._date_start = None
+ self._date_end = None
+ self._status = None
+ self._statement_number = None
+ self._statement_format = None
+ self._regional_format = None
+ self._alias_monetary_account = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id,
+ customer_statement_export_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type customer_statement_export_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: CustomerStatementExport
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ customer_statement_export_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[CustomerStatementExport]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def delete(cls, api_context, user_id, monetary_account_id,
+ customer_statement_export_id, custom_headers=None):
+ """
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type customer_statement_export_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype None:
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_DELETE.format(user_id,
+ monetary_account_id,
+ customer_statement_export_id)
+ api_client.delete(endpoint_url, custom_headers)
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+ @property
+ def created(self):
+ """
+ :rtype: str
+ """
+
+ return self._created
+
+ @property
+ def updated(self):
+ """
+ :rtype: str
+ """
+
+ return self._updated
+
+ @property
+ def date_start(self):
+ """
+ :rtype: str
+ """
+
+ return self._date_start
+
+ @property
+ def date_end(self):
+ """
+ :rtype: str
+ """
+
+ return self._date_end
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def statement_number(self):
+ """
+ :rtype: int
+ """
+
+ return self._statement_number
+
+ @property
+ def statement_format(self):
+ """
+ :rtype: str
+ """
+
+ return self._statement_format
+
+ @property
+ def regional_format(self):
+ """
+ :rtype: str
+ """
+
+ return self._regional_format
+
+ @property
+ def alias_monetary_account(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias_monetary_account
+
+
+class InstallationServerPublicKey(model.BunqModel):
+ """
+ Using /installation/_/server-public-key you can request the ServerPublicKey
+ again. This is done by referring to the id of the Installation.
+
+ :type _server_public_key: str
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_LISTING = "installation/{}/server-public-key"
+
+ # Object type.
+ _OBJECT_TYPE = "ServerPublicKey"
+
+ def __init__(self):
+ self._server_public_key = None
+
+ @classmethod
+ def list(cls, api_context, installation_id, custom_headers=None):
+ """
+ Show the ServerPublicKey for this Installation.
+
+ :type api_context: context.ApiContext
+ :type installation_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[InstallationServerPublicKey]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(installation_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def server_public_key(self):
+ """
+ :rtype: str
+ """
+
+ return self._server_public_key
+
+
+class ShareInviteBankAmountUsed(model.BunqModel):
+ """
+ When you have connected your monetary account bank to a user, and given this
+ user a (for example) daily budget of 10 EUR. If this users has used his
+ entire budget or part of it, this call can be used to reset the amount he
+ used to 0. The user can then spend the daily budget of 10 EUR again.
+ """
+
+ # Endpoint constants.
+ _ENDPOINT_URL_DELETE = "user/{}/monetary-account/{" \
+ "}/share-invite-bank-inquiry/{}/amount-used/{}"
+
+ # Object type.
+ _OBJECT_TYPE = "ShareInviteBankAmountUsed"
+
+ @classmethod
+ def delete(cls, api_context, user_id, monetary_account_id,
+ share_invite_bank_inquiry_id, share_invite_bank_amount_used_id,
+ custom_headers=None):
+ """
+ Reset the available budget for a bank account share. To be called
+ without any ID at the end of the path.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type share_invite_bank_inquiry_id: int
+ :type share_invite_bank_amount_used_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype None:
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_DELETE.format(user_id,
+ monetary_account_id,
+ share_invite_bank_inquiry_id,
+ share_invite_bank_amount_used_id)
+ api_client.delete(endpoint_url, custom_headers)
+
+
+class ShareInviteBankInquiry(model.BunqModel):
+ """
+ Used to share a monetary account with another bunq user, as in the 'Connect'
+ feature in the bunq app. Allow the creation of share inquiries that, in the
+ same way as request inquiries, can be revoked by the user creating them or
+ accepted/rejected by the other party.
+
+ :type _alias: object_.MonetaryAccountReference
+ :type _user_alias_created: object_.LabelUser
+ :type _user_alias_revoked: object_.LabelUser
+ :type _counter_user_alias: object_.LabelUser
+ :type _monetary_account_id: int
+ :type _draft_share_invite_bank_id: int
+ :type _share_detail: object_.ShareDetail
+ :type _status: str
+ :type _start_date: str
+ :type _end_date: str
+ :type _id_: int
+ """
+
+ # Field constants.
+ FIELD_COUNTER_USER_ALIAS = "counter_user_alias"
+ FIELD_DRAFT_SHARE_INVITE_BANK_ID = "draft_share_invite_bank_id"
+ FIELD_SHARE_DETAIL = "share_detail"
+ FIELD_STATUS = "status"
+ FIELD_START_DATE = "start_date"
+ FIELD_END_DATE = "end_date"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_CREATE = "user/{}/monetary-account/{" \
+ "}/share-invite-bank-inquiry"
+ _ENDPOINT_URL_READ = "user/{}/monetary-account/{" \
+ "}/share-invite-bank-inquiry/{}"
+ _ENDPOINT_URL_UPDATE = "user/{}/monetary-account/{" \
+ "}/share-invite-bank-inquiry/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/monetary-account/{" \
+ "}/share-invite-bank-inquiry"
+
+ # Object type.
+ _OBJECT_TYPE = "ShareInviteBankInquiry"
+
+ def __init__(self):
+ self._alias = None
+ self._user_alias_created = None
+ self._user_alias_revoked = None
+ self._counter_user_alias = None
+ self._monetary_account_id = None
+ self._draft_share_invite_bank_id = None
+ self._share_detail = None
+ self._status = None
+ self._start_date = None
+ self._end_date = None
+ self._id_ = None
+
+ @classmethod
+ def create(cls, api_context, request_map, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Create a new share inquiry for a monetary account, specifying the
+ permission the other bunq user will have on it.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: int
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_CREATE.format(user_id,
+ monetary_account_id)
+ response = api_client.post(endpoint_url, request_bytes, custom_headers)
+
+ return cls._process_for_id(response.text)
+
+ @classmethod
+ def get(cls, api_context, user_id, monetary_account_id,
+ share_invite_bank_inquiry_id, custom_headers=None):
+ """
+ Get the details of a specific share inquiry.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type share_invite_bank_inquiry_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ShareInviteBankInquiry
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ monetary_account_id,
+ share_invite_bank_inquiry_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id, monetary_account_id,
+ share_invite_bank_inquiry_id, custom_headers=None):
+ """
+ Update the details of a share. This includes updating status (revoking
+ or cancelling it), granted permission and validity period of this share.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type monetary_account_id: int
+ :type share_invite_bank_inquiry_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ShareInviteBankInquiry
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ monetary_account_id,
+ share_invite_bank_inquiry_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, monetary_account_id,
+ custom_headers=None):
+ """
+ Get a list with all the share inquiries for a monetary account, only if
+ the requesting user has permission to change the details of the various
+ ones.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type monetary_account_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[ShareInviteBankInquiry]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id,
+ monetary_account_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._alias
+
+ @property
+ def user_alias_created(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._user_alias_created
+
+ @property
+ def user_alias_revoked(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._user_alias_revoked
+
+ @property
+ def counter_user_alias(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._counter_user_alias
+
+ @property
+ def monetary_account_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._monetary_account_id
+
+ @property
+ def draft_share_invite_bank_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._draft_share_invite_bank_id
+
+ @property
+ def share_detail(self):
+ """
+ :rtype: object_.ShareDetail
+ """
+
+ return self._share_detail
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def start_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._start_date
+
+ @property
+ def end_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._end_date
+
+ @property
+ def id_(self):
+ """
+ :rtype: int
+ """
+
+ return self._id_
+
+
+class ShareInviteBankResponse(model.BunqModel):
+ """
+ Used to view or respond to shares a user was invited to. See
+ 'share-invite-bank-inquiry' for more information about the inquiring
+ endpoint.
+
+ :type _counter_alias: object_.MonetaryAccountReference
+ :type _user_alias_cancelled: object_.LabelUser
+ :type _monetary_account_id: int
+ :type _draft_share_invite_bank_id: int
+ :type _share_detail: object_.ShareDetail
+ :type _status: str
+ :type _start_date: str
+ :type _end_date: str
+ :type _description: str
+ """
+
+ # Field constants.
+ FIELD_STATUS = "status"
+
+ # Endpoint constants.
+ _ENDPOINT_URL_READ = "user/{}/share-invite-bank-response/{}"
+ _ENDPOINT_URL_UPDATE = "user/{}/share-invite-bank-response/{}"
+ _ENDPOINT_URL_LISTING = "user/{}/share-invite-bank-response"
+
+ # Object type.
+ _OBJECT_TYPE = "ShareInviteBankResponse"
+
+ def __init__(self):
+ self._counter_alias = None
+ self._user_alias_cancelled = None
+ self._monetary_account_id = None
+ self._draft_share_invite_bank_id = None
+ self._share_detail = None
+ self._status = None
+ self._start_date = None
+ self._end_date = None
+ self._description = None
+
+ @classmethod
+ def get(cls, api_context, user_id, share_invite_bank_response_id,
+ custom_headers=None):
+ """
+ Return the details of a specific share a user was invited to.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type share_invite_bank_response_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ShareInviteBankResponse
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_READ.format(user_id,
+ share_invite_bank_response_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def update(cls, api_context, request_map, user_id,
+ share_invite_bank_response_id, custom_headers=None):
+ """
+ Accept or reject a share a user was invited to.
+
+ :type api_context: context.ApiContext
+ :type request_map: dict[str, object]
+ :type user_id: int
+ :type share_invite_bank_response_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: ShareInviteBankResponse
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ request_bytes = converter.class_to_json(request_map).encode()
+ endpoint_url = cls._ENDPOINT_URL_UPDATE.format(user_id,
+ share_invite_bank_response_id)
+ response = api_client.put(endpoint_url, request_bytes, custom_headers)
+
+ return cls._from_json(response.text, cls._OBJECT_TYPE)
+
+ @classmethod
+ def list(cls, api_context, user_id, custom_headers=None):
+ """
+ Return all the shares a user was invited to.
+
+ :type api_context: context.ApiContext
+ :type user_id: int
+ :type custom_headers: dict[str, str]|None
+
+ :rtype: list[ShareInviteBankResponse]
+ """
+
+ if custom_headers is None:
+ custom_headers = {}
+
+ api_client = client.ApiClient(api_context)
+ endpoint_url = cls._ENDPOINT_URL_LISTING.format(user_id)
+ response = api_client.get(endpoint_url, custom_headers)
+
+ return cls._from_json_list(response.text, cls._OBJECT_TYPE)
+
+ @property
+ def counter_alias(self):
+ """
+ :rtype: object_.MonetaryAccountReference
+ """
+
+ return self._counter_alias
+
+ @property
+ def user_alias_cancelled(self):
+ """
+ :rtype: object_.LabelUser
+ """
+
+ return self._user_alias_cancelled
+
+ @property
+ def monetary_account_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._monetary_account_id
+
+ @property
+ def draft_share_invite_bank_id(self):
+ """
+ :rtype: int
+ """
+
+ return self._draft_share_invite_bank_id
+
+ @property
+ def share_detail(self):
+ """
+ :rtype: object_.ShareDetail
+ """
+
+ return self._share_detail
+
+ @property
+ def status(self):
+ """
+ :rtype: str
+ """
+
+ return self._status
+
+ @property
+ def start_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._start_date
+
+ @property
+ def end_date(self):
+ """
+ :rtype: str
+ """
+
+ return self._end_date
+
+ @property
+ def description(self):
+ """
+ :rtype: str
+ """
+
+ return self._description
+
+
+class MonetaryAccountBank(model.BunqModel):
+ """
+ With MonetaryAccountBank you can create a new bank account, retrieve
+ information regarding your existing MonetaryAccountBanks and update specific
+ fields of an existing MonetaryAccountBank. Examples of fields that can be
+ updated are the description, the daily limit and the avatar of the
+ account.