def _get_or_create_account(account_name, bank):
    """Searches the repository for an account with given name and bank and returns it if found.
    Otherwise returns a new account object."""
    account = account_repository().get_account_by_name_and_bank(
        account_name, bank)
    if not account:
        account = account_factory().create_account(account_name, bank)
        account_repository().save_account(account)
    return account
def map_transaction(transaction, transaction_mapper, update=False):
    """Map given transaction using given transaction_mapper. If the update flag is set to True, then transactions which
    have already been mapped will be updated. If the update flag is False, only uncategorized transactions will be
    processed."""
    category_scores = transaction_mapper.get_category_scores(transaction)
    category = get_best_scoring_category(category_scores)
    if category:
        if (update or
                not transaction.category) and transaction.category != category:
            transaction.update_category(category)
            account_repository().save_transaction(transaction)
Beispiel #3
0
def import_accounts(filename):
    if account_repository().get_accounts():
        logger.error(
            "Native import of accounts is only allowed on an empty database!")
        return

    with open(filename) as csv_file:
        reader = csv.DictReader(csv_file)
        for row in reader:
            account_id, name, bank = row["account_id"], row["name"], row[
                "bank"]
            account = account_repository().get_account(account_id)
            if not account:
                account = account_factory().create_account(name, bank)
                account.id = account_id
                account_repository().save_account(account)
            else:
                logger.info("Skipping import of existing account %s", account)
Beispiel #4
0
def set_category(transaction_id):
    category_id = request.json.get('categoryId')
    category = category_repository().get_category(category_id)
    transaction = account_repository().get_transaction(transaction_id)
    logger.info('Setting category of transaction id %s to %s', transaction,
                category)
    transaction.update_category(category)
    account_repository().save_transaction(transaction)
    # TODO: Fix threading issue!!! account_repository().save_transaction(transaction)
    return app.response_class(response=dumps(Transaction(
        transaction.id, transaction.date, transaction.account.name,
        transaction.amount,
        transaction.name, transaction.category and Category(
            transaction.category.id, transaction.category.qualified_name,
            transaction.category.parent).__dict__ or None,
        transaction.description, transaction.counter_account,
        transaction.internal).__dict__,
                                             cls=CategoryEncoder),
                              mimetype='application/json')
Beispiel #5
0
def import_transactions(filename):
    if list(
            itertools.chain.from_iterable([
                a.get_transactions()
                for a in account_repository().get_accounts()
            ])):
        logger.error(
            "Native import of transactions is only allowed on an empty transactions table!"
        )
        return

    with open(filename) as csv_file:
        reader = csv.DictReader(csv_file)
        for row in reader:
            transaction_id = row["transaction_id"]
            amount = row["amount"]
            date = datetime.datetime.strptime(row["date"], '%Y-%m-%d').date()
            name = row["name"]
            description = row["description"]
            balance_after = row["balance_after"]
            serial = row["serial"]
            counter_account = row["counter_account"]
            account_id = row["account"]
            category_qualified_name = row["category"]
            transaction = account_repository().get_transaction(transaction_id)
            account = account_repository().get_account(account_id)
            if not transaction:
                transaction = account_factory().create_transaction(
                    account, date, amount, name, description, serial,
                    counter_account, balance_after)
                transaction.id = transaction_id
                if category_qualified_name:
                    category = category_repository(
                    ).get_category_by_qualified_name(category_qualified_name)
                    if not category:
                        category = category_factory(
                        ).create_category_from_qualified_name(
                            category_qualified_name)
                        category_repository().save_category(category)
                    transaction.update_category(category)
            account_repository().save_transaction(transaction)
    def is_internal_transaction(self, transaction):
        def extract_accountnr_from_iban(iban):
            m = re.search("^[A-Z]{2}[0-9]{2}[A-Z]+0*([0-9]+)$", iban)
            if m:
                return m.group(1)
            else:
                return iban

        for account in account_repository().get_accounts():
            if account.name == transaction.counter_account or extract_accountnr_from_iban(
                    account.name) == transaction.counter_account:
                return True
        return False
def import_transactions_from_rabobank_text(csv_text, bank):
    logger.info("Parsing csv: '%s'", dir(csv_text))
    reader = csv.DictReader(csv_text, delimiter=',', doublequote=True)
    logger.info("Fieldnames: %s", reader.fieldnames)
    for row in reader:
        logger.debug("parsing row: %s", row)
        account_id = row["IBAN/BBAN"]
        account = _get_or_create_account(account_id, bank)

        date = datetime.datetime.strptime(row["Rentedatum"], "%Y-%m-%d").date()
        amount = decimal.Decimal(row["Bedrag"].replace(",", "."))
        name = " ".join(row["Naam tegenpartij"].split())

        description = " ".join(row["Omschrijving-1"].split() +
                               row["Omschrijving-2"].split() +
                               row["Omschrijving-3"].split() +
                               row["Betalingskenmerk"].split())
        serial = int(row["Volgnr"].lstrip("0"))
        counter_account = row["Tegenrekening IBAN/BBAN"]
        balance = decimal.Decimal(row["Saldo na trn"].replace(",", "."))

        # Only create a new transaction if no identical transaction already exists!
        existing_transactions = services.find_transactions_by_attributes(
            account, date, serial, amount, name, counter_account, description)
        if existing_transactions:
            if len(existing_transactions) > 1:
                raise ValueError("Database contains duplicate transactions!")
            else:
                logger.info("Skipping duplicate transaction: %s",
                            existing_transactions[0])
        else:
            transaction = account_factory().create_transaction(
                account, date, amount, name, description, serial,
                counter_account, balance)
            logger.info("Adding new transaction: %s", transaction)
            account_repository().save_transaction(transaction)
            account.add_transaction(transaction)