Exemple #1
0
def list_accounts():
    """
    List all shared accounts (id, name, balance)
    """

    # Ensure the whole account is included
    print("\nLoading Bunq API environment...")
    env = ApiEnvironmentType.PRODUCTION

    # Authenticate session & load context
    print("Authenticating and loading context...")
    api_context = ApiContext(ApiEnvironmentType.PRODUCTION, API_KEY,
                             socket.gethostname())
    api_context.ensure_session_active()
    BunqContext.load_api_context(api_context)

    # Get user info
    print("Loading user info...\n")
    user = endpoint.User.get().value.get_referenced_object()

    # Fetch account detials
    accounts = endpoint.MonetaryAccountJoint.list().value
    for account in accounts:
        print(
            f"[{account.id_}] {account.description} (\N{euro sign}{account.balance.value})"
        )
    def authenticate(self):
        if self.parameter_manager.exists("/bunq/api_context"):
            self.api_context = self._get_api_context_from_aws()
            self._ensure_active_session()
        else:
            self.api_context = self._create_api_context()

        BunqContext.load_api_context(self.api_context)
    def test_bad_request_with_response_id(self):
        """
        """
        BunqContext.load_api_context(self._get_api_context())

        with self.assertRaises(ApiException) as caught_exception:
            MonetaryAccountBank.get(self._INVALID_MONETARY_ACCOUNT_ID)
        self.assertIsNotNone(caught_exception.exception.response_id)
Exemple #4
0
async def async_setup_platform(hass, config, async_add_entities,
                               discovery_info=None):
    """Set up the Bunq Bank sensor platform."""
    from bunq.sdk.context import (
        ApiContext, ApiEnvironmentType,
        BunqContext)
    from bunq.sdk.exception import BunqException, ApiException
    from bunq.sdk.model.generated import endpoint
    from bunq.sdk.json import converter

    # set environment type
    api_environment = ApiEnvironmentType.SANDBOX \
        if config.get(CONF_SANDBOX) else ApiEnvironmentType.PRODUCTION

    accs = []
    try:
        # create the api context variable
        bunq_context = ApiContext(
            api_environment,
            config.get(CONF_API_KEY),
            'Home Assistant'
        )
        # ensure the key is active, or activate
        bunq_context.ensure_session_active()
        # load user context from api context (not IO)
        # checks if the user has active accounts
        # raises BunqException otherwise

        BunqContext.load_api_context(bunq_context)
        # call the account list endpoint
        accounts = converter.serialize(
            endpoint.MonetaryAccount.list().value)
        # create and add the devices to the list
        accs = [
            BunqAccountSensor(
                acc['MonetaryAccountBank']['description'],
                acc['MonetaryAccountBank']['id'],
                acc['MonetaryAccountBank']['currency'],
                float(acc['MonetaryAccountBank']['balance']['value']))
            for acc in accounts
            ]
        async_add_entities(accs)
        # create the refresh object
        data = BunqData(hass, bunq_context, accs)
        # schedule the first update
        await data.schedule_update(INTERVAL_TO_NEXT_REFRESH)
    except ApiException as err:
        # if there is something wrong with the user setup
        # such as a incorrect key or invalid IP address
        # log the error and raise HA error
        # nothing to setup further until the key is changed
        _LOGGER.error(err)
    except BunqException as err:
        # if the Bunq sdk errors out there is
        # such as API rate limit throtteling
        # log the error and raise PlatformNotReady to retry
        _LOGGER.error(err)
        raise PlatformNotReady
Exemple #5
0
    def _register_user(self):
        api_context = context.ApiContext(
            self._get_environment(), Config.get_option('API_KEY'),
            Config.get_option('DEVICE_DESCRIPTION'),
            [Config.get_option('PERMITTED_IP')])
        api_context.save(Config.get_option('API_CONTEXT_FILE_PATH'))
        BunqContext.load_api_context(api_context)

        self._pin_certificate()
    def setUpClass(cls):
        cls._PAYMENT_LISTING_PAGE_SIZE = 2
        cls._PAYMENT_REQUIRED_COUNT_MINIMUM = cls._PAYMENT_LISTING_PAGE_SIZE * 2
        cls._NUMBER_ZERO = 0
        cls._PAYMENT_AMOUNT_EUR = '0.01'
        cls._PAYMENT_CURRENCY = 'EUR'
        cls._PAYMENT_DESCRIPTION = 'Python test Payment'

        BunqContext.load_api_context(cls._get_api_context())
Exemple #7
0
    def _setup_context(self):
        if not self._user_is_registered():
            self._register_user()

        api_context = ApiContext.restore(
            Config.get_option('API_CONTEXT_FILE_PATH'))
        api_context.ensure_session_active()
        api_context.save(Config.get_option('API_CONTEXT_FILE_PATH'))

        BunqContext.load_api_context(api_context)
Exemple #8
0
def fetch_transactions(days):

    # Ensure the whole account is included
    print("\nLoading Bunq API environment...")
    env = ApiEnvironmentType.PRODUCTION

    # Authenticate session & load context
    print("Authenticating and loading context...")
    api_context = ApiContext(ApiEnvironmentType.PRODUCTION, API_KEY,
                             socket.gethostname())
    api_context.ensure_session_active()
    BunqContext.load_api_context(api_context)

    # Get user info
    print("Loading user info...")
    user = endpoint.User.get().value.get_referenced_object()

    # Fetch account detials
    account = endpoint.MonetaryAccountJoint.get(ACCOUNT_ID).value
    description = account.description
    balance = account.balance.value

    print(
        f"\nLoaded account '{description}' with current balance of \N{euro sign}{balance}"
    )

    start_date = datetime.now() - timedelta(days)
    transactions = []
    for transaction in iterate_transactions(ACCOUNT_ID):

        transaction_dict = {
            "timestamp":
            transaction.created,
            "amount":
            transaction.amount.value,
            "description":
            transaction.description.replace("\r", "").replace("\n", " "),
            "counterparty":
            transaction.counterparty_alias.label_monetary_account.display_name,
        }

        # Still in range
        if dateparse.parse(transaction.created) >= start_date:
            transactions.append(transaction_dict)
        else:
            break

    print(transactions)
Exemple #9
0
    def setup_context(self):
        if isfile(self.determine_bunq_conf_filename()):
            pass  # Config is already present
        elif self.env == ApiEnvironmentType.SANDBOX:
            sandbox_user = self.generate_new_sandbox_user()
            ApiContext(ApiEnvironmentType.SANDBOX, sandbox_user.api_key,
                       socket.gethostname()).save(
                           self.determine_bunq_conf_filename())
        else:
            raise BunqException(self._ERROR_COULD_NOT_DETIRMINE_CONF)

        api_context = ApiContext.restore(self.determine_bunq_conf_filename())
        api_context.ensure_session_active()
        api_context.save(self.determine_bunq_conf_filename())

        BunqContext.load_api_context(api_context)
    def setup_context(self):
        if Path(self.determine_bunq_conf_filename()).is_file():
            pass
        else:
            sandbox_user = self.generate_new_sandbox_user()
            ApiContext(
                ApiEnvironmentType.SANDBOX, sandbox_user.api_key, socket.gethostname()
            ).save(self.determine_bunq_conf_filename())

        self._api_context = ApiContext.restore(self.determine_bunq_conf_filename())
        self._api_context.ensure_session_active()
        self._api_context.save(self.determine_bunq_conf_filename())

        BunqContext.load_api_context(self._api_context)

        self._user_context = BunqContext.user_context()
Exemple #11
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(OPTION_API_KEY)
    all_option = parser.parse_args()

    if all_option.api_key is None:
        raise BunqException(ERROR_OPTION_MISSING_API_KEY)

    api_context = ApiContext(ApiEnvironmentType.PRODUCTION, all_option.api_key, '*')
    BunqContext.load_api_context(api_context)
    end = 50
    for i in range(0, end):
        endpoint.Payment.create(amount=Amount('0.01', 'EUR'),
                                counterparty_alias=Pointer('IBAN', '', ''),
                                description=str(round(i / end * 100, 2)) + " Prozent von deinem Geld",
                                monetary_account_id=)
        time.sleep(0.33333)
Exemple #12
0
    def setup_context(self, reset_config_if_needed=True):
        if isfile(self.determine_bunq_conf_filename()):
            pass  # Config is already present
        elif self.env == ApiEnvironmentType.SANDBOX:
            sandbox_user = self.generate_new_sandbox_user()
            ApiContext(ApiEnvironmentType.SANDBOX, sandbox_user.api_key,
                       socket.gethostname()).save(
                           self.determine_bunq_conf_filename())
        else:
            raise BunqException(self._ERROR_COULD_NOT_DETERMINE_CONF)

        try:
            api_context = ApiContext.restore(
                self.determine_bunq_conf_filename())
            api_context.ensure_session_active()
            api_context.save(self.determine_bunq_conf_filename())

            BunqContext.load_api_context(api_context)
        except ForbiddenException as forbidden_exception:
            if reset_config_if_needed:
                self.__handle_forbidden_exception(forbidden_exception)
            else:
                raise forbidden_exception
Exemple #13
0
from bunq.sdk.context import ApiContext, BunqContext
from bunq.sdk.context import ApiEnvironmentType
import socket

apiContext = ApiContext(
    ApiEnvironmentType.SANDBOX,
    "sandbox_ae9afa8798dc521804bd1d8900167457243b9fd323e6799a9d42d75d",
    socket.gethostname())
apiContext.save("bunq.conf")
BunqContext.load_api_context(apiContext)
Exemple #14
0
def all_transactions(dt=None):
    # This should be enough to ensure the whole account is included.
    if dt == None:
        dt = epoch

    env = ApiEnvironmentType.PRODUCTION

    if not isfile('bunq-production.conf'):
        raise Exception("No config file found, run start.py first.")

    # Reload the API context
    api_context = ApiContext.restore('bunq-production.conf')
    api_context.ensure_session_active()
    api_context.save('bunq-production.conf')

    BunqContext.load_api_context(api_context)

    # User info
    user = endpoint.User.get().value.get_referenced_object()

    # To get a list we want a pagination object.
    # When making a pagination object yourself you normally only set the 'count'
    # Then you get the url params from it using 'url_params_count_only'
    pagination = Pagination()
    pagination.count = 100

    accounts = []

    all_monetary_account_bank = endpoint.MonetaryAccountBank.list(
        pagination.url_params_count_only).value

    for monetary_account_bank in all_monetary_account_bank:
        if monetary_account_bank.status == "ACTIVE":
            accounts.append(monetary_account_bank)

    all_monetary_account_savings = endpoint.MonetaryAccountSavings.list(
        pagination.url_params_count_only).value

    for monetary_account_savings in all_monetary_account_savings:
        if monetary_account_savings.status == "ACTIVE":
            accounts.append(monetary_account_savings)

    # Reload where we where last time.
    try:
        with open("seen.pickle", "rb") as fp:
            seen = pickle.load(fp)
    except Exception:
        seen = set()
    # We will keep a list of transactions that are already processed in this set.
    # The transactions will contain:
    #  - A set of the two possible roundings of the datestamp
    #  - The ammount of money in absolute value
    #  - The description
    #  - A set containing the two accounts involved
    # The goal here is that this representation is the same for two accounts when shifting money arround.

    for a in accounts:
        aid = a.id_
        # keep track of where we are
        print(a.description)

        for p in iter_payments(aid):
            # python can handle the dates we get back
            date = dateparse.parse(p.created)

            #round to the second to get a (sort of) unique, but not to precise timestamp
            since_epoch = int(unix_time(date))

            row = [
                p.created, p.amount.value,
                p.description.replace("\r", "").replace("\n", " "),
                p.alias.label_monetary_account.iban,
                p.counterparty_alias.label_monetary_account.iban
            ]

            # frozenset can be used to hash a set, so the order does not matter.
            summary = (
                unique_float(
                    since_epoch),  #take both so there is norounding problem
                abs(float(p.amount.value)),
                p.description,
                frozenset([
                    p.alias.label_monetary_account.iban,
                    p.counterparty_alias.label_monetary_account.iban
                ]))

            # Still in range
            if date >= dt:
                if summary in seen:
                    continue
                else:
                    seen.add(summary)
                    yield (row)
            else:
                break

    with open("seen.pickle", "wb") as fp:
        pickle.dump(seen, fp)
 def setup_context(self, api_key):
     api_context = ApiContext(ApiEnvironmentType.SANDBOX, api_key,
                              socket.gethostname())
     api_context.ensure_session_active()
     BunqContext.load_api_context(api_context)