Ejemplo n.º 1
0
def load_ofx(ofx_file):
    """ Import an OFX bank statement file """
    ofx = ofxparse.OfxParser.parse(ofx_file)

    acct_id = ofx.account.account_id
    sort_code = ofx.account.routing_number
    account = BankAccount.get(sort_code, acct_id)
    if ofx.account.statement.currency.lower() != account.currency.lower():
        app.logger.error(
            "Currency %s doesn't match account currency %s",
            ofx.account.statement.currency,
            account.currency,
        )
        return

    added = 0
    duplicate = 0
    dubious = 0

    for txn in ofx.account.statement.transactions:
        if 0 < int(txn.id) < 200101010000000:
            app.logger.debug("Ignoring uncleared transaction %s", txn.id)
            continue
        # date is actually dtposted and is a datetime
        if txn.date < datetime(2015, 1, 1):
            app.logger.debug("Ignoring historic transaction from %s", txn.date)
            continue
        if txn.amount <= 0:
            app.logger.info("Ignoring non-credit transaction for %s",
                            txn.amount)
            continue

        dbtxn = BankTransaction(
            account_id=account.id,
            posted=txn.date,
            type=txn.type,
            amount=txn.amount,
            payee=txn.payee,
            fit_id=txn.id,
        )

        # Check for matching/duplicate transactions.
        # Insert if possible - conflicts can be sorted out within the app.
        matches = dbtxn.get_matching()

        # Euro payments have a blank fit_id
        if dbtxn.fit_id == "00000000":
            # There seems to be a serial in the payee field. Assume that's enough for uniqueness.
            if matches.count():
                app.logger.debug("Ignoring duplicate transaction from %s",
                                 dbtxn.payee)
                duplicate += 1

            else:
                db.session.add(dbtxn)
                added += 1

        else:
            different_fit_ids = matches.filter(
                BankTransaction.fit_id != dbtxn.fit_id)
            same_fit_ids = matches.filter(
                BankTransaction.fit_id == dbtxn.fit_id)

            if same_fit_ids.count():
                app.logger.debug("Ignoring duplicate transaction %s",
                                 dbtxn.fit_id)
                duplicate += 1

            elif BankTransaction.query.filter(
                    BankTransaction.fit_id == dbtxn.fit_id).count():
                app.logger.error(
                    "Non-matching transactions with same fit_id %s",
                    dbtxn.fit_id)
                dubious += 1

            elif different_fit_ids.count():
                app.logger.warn(
                    "%s matching transactions with different fit_ids for %s",
                    different_fit_ids.count(),
                    dbtxn.fit_id,
                )
                # fit_id may have been changed, so add it anyway
                db.session.add(dbtxn)
                added += 1
                dubious += 1

            else:
                db.session.add(dbtxn)
                added += 1

    db.session.commit()
    app.logger.info("Import complete: %s new, %s duplicate, %s dubious", added,
                    duplicate, dubious)
Ejemplo n.º 2
0
    def run(self, filename):
        ofx = ofxparse.OfxParser.parse(open(filename))

        acct_id = ofx.account.account_id
        sort_code = ofx.account.routing_number
        account = BankAccount.get(sort_code, acct_id)
        if ofx.account.statement.currency.lower() != account.currency.lower():
            app.logger.error("Currency %s doesn't match account currency %s",
                             ofx.account.statement.currency, account.currency)
            return

        added = 0
        duplicate = 0
        dubious = 0

        for txn in ofx.account.statement.transactions:
            if 0 < int(txn.id) < 200101010000000:
                app.logger.debug('Ignoring uncleared transaction %s', txn.id)
                continue
            # date is actually dtposted and is a datetime
            if txn.date < datetime(2015, 1, 1):
                app.logger.debug('Ignoring historic transaction from %s', txn.date)
                continue
            if txn.amount <= 0:
                app.logger.info('Ignoring non-credit transaction for %s', txn.amount)
                continue

            dbtxn = BankTransaction(
                account_id=account.id,
                posted=txn.date,
                type=txn.type,
                amount=txn.amount,
                payee=txn.payee,
                fit_id=txn.id,
            )

            # Check for matching/duplicate transactions.
            # Insert if possible - conflicts can be sorted out within the app.
            matches = dbtxn.get_matching()

            # Euro payments have a blank fit_id
            if dbtxn.fit_id == '00000000':
                # There seems to be a serial in the payee field. Assume that's enough for uniqueness.
                if matches.count():
                    app.logger.debug('Ignoring duplicate transaction from %s', dbtxn.payee)
                    duplicate += 1

                else:
                    db.session.add(dbtxn)
                    added += 1

            else:
                different_fit_ids = matches.filter( BankTransaction.fit_id != dbtxn.fit_id )
                same_fit_ids = matches.filter( BankTransaction.fit_id == dbtxn.fit_id )

                if same_fit_ids.count():
                    app.logger.debug('Ignoring duplicate transaction %s', dbtxn.fit_id)
                    duplicate += 1

                elif BankTransaction.query.filter( BankTransaction.fit_id == dbtxn.fit_id ).count():
                    app.logger.error('Non-matching transactions with same fit_id %s', dbtxn.fit_id)
                    dubious += 1

                elif different_fit_ids.count():
                    app.logger.warn('%s matching transactions with different fit_ids for %s',
                                    different_fit_ids.count(), dbtxn.fit_id)
                    # fit_id may have been changed, so add it anyway
                    db.session.add(dbtxn)
                    added += 1
                    dubious += 1

                else:
                    db.session.add(dbtxn)
                    added += 1

        db.session.commit()
        app.logger.info('Import complete: %s new, %s duplicate, %s dubious',
                        added, duplicate, dubious)