Beispiel #1
0
def migrate_main():
    print('migrate YNAB4 to pynYNAB')
    """Migrate a YNAB4 budget transaction history to nYNAB, using pyynab"""

    parser = configargparse.getArgumentParser('pynYNAB')
    parser.description = inspect.getdoc(migrate_main)
    parser.add_argument('budget',
                        metavar='BudgetPath',
                        type=str,
                        help='The budget .ynab4 directory')
    args = parser.parse_args()
    test_common_args(args)

    budget_base_name = os.path.basename(args.budget)
    budget_path = os.path.dirname(args.budget)
    budget_name = re.match(r"(?P<budget_name>.*)~[A-Z0-9]{8}\.ynab4",
                           budget_base_name).groupdict().get('budget_name')

    if args.budgetname is not None:
        budget_name = args.budgetname

    thisynab = YNAB(budget_path, budget_name)

    client = clientfromargs(args, reset=True)

    for ynab4_account in thisynab.accounts:
        account = Account(
            name=ynab4_account.name,
            account_type=ynab4_account.type.value,
            on_budget=ynab4_account.on_budget,
            sortable_index=random.randint(-50000, 50000),
        )
        mindate = min([
            ynab4transaction.date for ynab4transaction in thisynab.transactions
            if ynab4transaction.account == ynab4_account
        ])
        client.add_account(account, 0, mindate)

    for master_category in thisynab.master_categories:
        master_entity = MasterCategory(name=master_category.name,
                                       sortable_index=random.randint(
                                           -50000, 50000))
        client.budget.be_master_categories.append(master_entity)
        for category in master_category.categories:

            entity = Subcategory(name=category.name,
                                 entities_master_category_id=master_entity.id,
                                 sortable_index=random.randint(-50000, 50000))
            client.budget.be_subcategories.append(entity)
        client.sync()

    for ynab4_payee in thisynab.payees:
        payee = Payee(name=ynab4_payee.name)
        client.budget.be_payees.append(payee)
        client.sync()

    for ynab4transaction in thisynab.transactions:
        transaction = Transaction()
        pass
Beispiel #2
0
def push_transactions(nordea_transactions, args):
    print("******** FETCHING DATA FROM YNAB ********")
    client = clientfromargs(args)
    client.sync()

    with client.session.no_autoflush:
        account = None
        for be_account in client.budget.be_accounts:
            if be_account.account_name == 'Checking':
                account = be_account
                break

        if not account:
            print("Could not find checking account")
            sys.exit()

        store_categories(client.budget.be_subcategories)
        new_transactions = []
        new_payees = []

        for nordea_transaction in nordea_transactions:
            subcategory_id = get_subcategory_for_transaction(
                nordea_transaction)
            payee = find_existing_payee(nordea_transaction.target,
                                        client.budget.be_payees)
            if payee is None:
                for new_payee in new_payees:
                    if new_payee.name == nordea_transaction.target:
                        payee = new_payee
                if payee is None:
                    payee = create_new_payee(nordea_transaction.target)
                    new_payees.append(payee)
            new_transaction = get_ynab_transaction(nordea_transaction,
                                                   account.id, subcategory_id,
                                                   payee.id)
            new_transactions.append(new_transaction)

        print("\n\n******** SENDING DATA TO YNAB ********\n\n")
        print("Pushing new payees:\n")

        for new_payee in new_payees:
            client.budget.be_payees.append(new_payee)
        client.push(len(new_payees))

        print("Done...\n")
        print("Syncing...\n")
        client.sync()

        bar = Bar('Sending transactions', max=len(new_transactions))
        for transaction in new_transactions:
            client.add_transaction(transaction)
            bar.next()

        bar.finish()
        client.sync()
        print("******** DONE ********")
Beispiel #3
0
import itertools
import random

from datetime import datetime

from pynYNAB.Client import clientfromargs
from pynYNAB.schema.budget import Transaction
from pynYNAB.scripts.config import parser

# used to ping the nYNAB API to check that the sync works

args = parser.parse_known_args()[0]
N = 2
client = clientfromargs(args)
client.sync()
account = next(acc for acc in client.budget.be_accounts)
for _ in itertools.repeat(None, N):
    transaction = Transaction(cleared='Uncleared',
                              date=datetime.now(),
                              entities_account_id=account.id,
                              amount=random.randrange(-10, 10))
    client.add_transaction(transaction)
    client.sync()
Beispiel #4
0
 def reload(self):
     parser = configargparse.getArgumentParser('pynYNAB')
     args = parser.parse_known_args()[0]
     self.client = clientfromargs(args)
Beispiel #5
0
    def testiimport(self):
        parser = configargparse.getArgumentParser('pynYNAB')
        args = parser.parse_known_args()[0]
        args.ofxfile = os.path.join(tempfile.gettempdir(), 'data.ofx')
        args.logginglevel = 'debug'

        self.client = clientfromargs(args)

        content = """OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1>
<SONRS>
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<DTSERVER>20130313133728
<LANGUAGE>FRA
</SONRS>
</SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>29939615002
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<STMTRS>
<CURDEF>EUR
<BANKACCTFROM>
<BANKID>11706
<BRANCHID>41029
<ACCTID>29939615002
<ACCTTYPE>CHECKING
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>20130128000000
<DTEND>20130314235959
<STMTTRN>
<TRNTYPE>CHECK
<DTPOSTED>20130312
<TRNAMT>-491.09
<FITID>13071099780237330004
<CHECKNUM>0003445
<NAME>CHEQUE
<MEMO>CHEQUE
</STMTTRN>
</BANKTRANLIST>
<LEDGERBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</LEDGERBAL>
<AVAILBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>"""
        with open(args.ofxfile, 'w') as f:
            f.writelines(content)
        imported_date = datetime.now().date()

        testaccount = 'TEST'
        account = util_get_empty_account_by_name_if_doesnt_exist(
            self.client, testaccount)

        key = '11706 41029 29939615002'
        account.note = 'great note key[%s]key' % key
        self.client.sync()

        payee = util_add_payee_by_name_if_doesnt_exist(self.client, 'CHEQUE')
        amount = -491.09

        transaction = Transaction(entities_account=account,
                                  date=datetime(year=2013, month=3,
                                                day=12).date(),
                                  entities_payee=payee,
                                  imported_payee=payee,
                                  source='Imported',
                                  check_number='0003445',
                                  memo='CHEQUE    13071099780237330004',
                                  amount=amount,
                                  imported_date=imported_date)

        do_ofximport(args)
        self.reload()
        self.assertIn(
            transaction,
            self.client.budget.be_transactions,
            msg='couldnt find an imported transaction after ofx import')
Beispiel #6
0
from memory_profiler import memory_usage, profile
from sqlalchemy import create_engine

from pynYNAB.Client import clientfromargs
from pynYNAB.schema.budget import Transaction


class Args(object):
    email = 'email'
    password = '******'
    nynabconnection = None
    budgetname = 'test budget'


client = clientfromargs(Args(), sync=False)
#client.session.bind.echo = True


@profile
def func():
    print('test_sync')
    for i in range(0, 5000):
        client.budget.be_transactions.append(Transaction())
    client.session.commit()
    client.budget.clear_changed_entities()
    print('Entities in the client: %i' % (
        sum([len(getattr(client.budget, f))
             for f in client.budget.listfields]) + sum([
                 len(getattr(client.catalog, f))
                 for f in client.catalog.listfields
             ])))
Beispiel #7
0
 def setUp(self):
     args = parser.parse_known_args()[0]
     self.client = clientfromargs(args, sync=False)
     self.client.sync_catalog()
     self.client.select_budget(test_budget_name)
Beispiel #8
0
def do_csvimport(args, client=None):
    if client is None:
        client = clientfromargs(args)
    logger = get_logger(args)

    logger.debug('selected schema %s' % (args.schema,))
    if os.path.exists(args.schema):
        schemafile = args.schema
    else:
        schemafile = os.path.join(schemas_dir, args.schema + '.json')
        if not os.path.exists(schemafile):
            logger.error('This schema doesn''t exist in csv_schemas')
            exit(-1)
    try:
        schema = SchemaModel(schemafile, case_insensitive_headers=True)
        with open(schemafile, 'r') as sf:
            schemacontent = json.load(sf)
            try:
                nheaders = schemacontent['nheaders']
            except KeyError:
                nheaders = 1
    except InvalidSchemaError:
        logger.error('Invalid CSV schema')
        raise
    logger.debug('schema headers %s' % schema.headers)

    if 'account' not in schema.headers and args.accountname is None:
        logger.error('This schema does not have an account column and no account name was provided')
        exit(-1)

    accounts = {x.account_name: x for x in client.budget.be_accounts}
    payees = {p.name: p for p in client.budget.be_payees}
    mastercategories_perid = {m.id: m for m in client.budget.be_master_categories}
    subcategories = {}
    for s in client.budget.be_subcategories:
        m = mastercategories_perid[s.entities_master_category_id]
        subcategories[m.name + ':' + s.name] = s

    def getaccount(accountname):
        try:
            logger.debug('searching for account %s' % accountname)
            return accounts[accountname]
        except KeyError:
            logger.error('Couldn''t find this account: %s' % accountname)
            exit(-1)

    def getpayee(payeename):
        try:
            logger.debug('searching for payee %s' % payeename)
            return payees[payeename]
        except KeyError:
            logger.debug('Couldn''t find this payee: %s' % payeename)
            payee = Payee(name=payeename)
            client.budget.be_payees.append(payee)
            return payee

    def getsubcategory(categoryname):
        try:
            logger.debug('searching for subcategory %s' % categoryname)
            return subcategories[categoryname]
        except KeyError:
            logger.debug('Couldn''t find this category: %s' % categoryname)
            exit(-1)

    entities_account_id = None
    if 'account' not in schema.headers:
        entities_account_id = getaccount(args.accountname).id

    amount = None
    if 'inflow' in schema.headers and 'outflow' in schema.headers:
        pass
    elif 'amount' in schema.headers:
        pass
    else:
        logger.error('This schema doesn''t provide an amount column or (inflow,outflow) columns')
        exit(-1)

    csvrow = namedtuple('CSVrow', field_names=schema.headers)
    transactions = []

    imported_date = datetime.now().date()

    logger.debug('OK starting the import from %s ' % os.path.abspath(args.csvfile))
    with open(args.csvfile, 'r') as inputfile:
        header = []
        for i in range(0, nheaders):
            header.append(inputfile.readline())
        for row in csv.reader(inputfile):
            if sys.version[0] == '2':
                row = [cell.decode('utf-8') for cell in row]
            if all(map(lambda x: x.strip() == '', row)):
                continue
            logger.debug('read line %s' % row)
            result = csvrow(*list(schema.convert_row(*row, fail_fast=True)))
            if 'account' in schema.headers:
                entities_account_id = getaccount(result.account).id
            if entities_account_id is None:
                logger.error(
                    'No account id, the account %s in the an account column was not recognized' % result.account)
                exit(-1)
            if 'inflow' in schema.headers and 'outflow' in schema.headers:
                amount = result.inflow - result.outflow
            elif 'amount' in schema.headers:
                amount = result.amount

            if 'category' in schema.headers and result.category:
                entities_subcategory_id = getsubcategory(result.category).id
            else:
                entities_subcategory_id = None
            if 'payee' in schema.headers:
                imported_payee = result.payee
            else:
                imported_payee = ''
            entities_payee_id = getpayee(imported_payee).id
            if 'memo' in schema.headers:
                memo = result.memo
            else:
                memo = ''

            transaction = Transaction(
                entities_account_id=entities_account_id,
                amount=amount,
                date=result.date,
                entities_payee_id=entities_payee_id,
                entities_subcategory_id=entities_subcategory_id,
                imported_date=imported_date,
                imported_payee=imported_payee,
                memo=memo,
                source="Imported"
            )
            if args.import_duplicates or (not transaction in client.budget.be_transactions):
                logger.debug('Appending transaction %s ' % transaction.get_dict())
                transactions.append(transaction)
            else:
                logger.debug('Duplicate transaction found %s ' % transaction.get_dict())

    client.add_transactions(transactions)
import itertools
import random

from datetime import datetime

from pynYNAB.Client import clientfromargs
from pynYNAB.schema.budget import Transaction
from pynYNAB.scripts.config import parser

# used to ping the nYNAB API to check that the sync works

args = parser.parse_known_args()[0]
N=2
client = clientfromargs(args)
client.sync()
account = next(acc for acc in client.budget.be_accounts)
for _ in itertools.repeat(None, N):
    transaction = Transaction(
        cleared='Uncleared',
        date=datetime.now(),
        entities_account_id=account.id,
        amount=random.randrange(-10,10)
    )
    client.add_transaction(transaction)
    client.sync()
Beispiel #10
0
 def test_sync():
     print('test_live')
     args = parser.parse_known_args()[0]
     client = clientfromargs(args)
     client.sync()
Beispiel #11
0
def migrate_main():
    print('migrate YNAB4 to pynYNAB')
    """Migrate a YNAB4 budget transaction history to nYNAB, using pyynab"""

    parser = configargparse.getArgumentParser('pynYNAB')
    parser.description=inspect.getdoc(migrate_main)
    parser.add_argument('budget', metavar='BudgetPath', type=str,
                        help='The budget .ynab4 directory')
    args = parser.parse_args()
    test_common_args(args)

    budget_base_name=os.path.basename(args.budget)
    budget_path=os.path.dirname(args.budget)
    budget_name=re.match(r"(?P<budget_name>.*)~[A-Z0-9]{8}\.ynab4",budget_base_name).groupdict().get('budget_name')

    if args.budgetname is not None:
        budget_name=args.budgetname

    thisynab = YNAB(budget_path,budget_name)

    client = clientfromargs(args, reset=True)



    for ynab4_account in thisynab.accounts:
        account=Account(
            name=ynab4_account.name,
            account_type=ynab4_account.type.value,
            on_budget=ynab4_account.on_budget,
            sortable_index=random.randint(-50000, 50000),
        )
        mindate=min([ynab4transaction.date for ynab4transaction in thisynab.transactions if ynab4transaction.account == ynab4_account])
        client.add_account(account, 0, mindate)

    for master_category in thisynab.master_categories:
        master_entity = MasterCategory(
            name=master_category.name,
            sortable_index=random.randint(-50000, 50000)
        )
        client.budget.be_master_categories.append(master_entity)
        for category in master_category.categories:

            entity = Subcategory(
                name=category.name,
                entities_master_category_id=master_entity.id,
                sortable_index=random.randint(-50000, 50000)
            )
            client.budget.be_subcategories.append(entity)
        client.sync()

    for ynab4_payee in thisynab.payees:
        payee=Payee(
            name=ynab4_payee.name
                   )
        client.budget.be_payees.append(payee)
        client.sync()

    for ynab4transaction in thisynab.transactions:
        transaction=Transaction(

        )
        pass
Beispiel #12
0
 def reload(self):
     # parser = configargparse.getArgumentParser('pynYNAB')
     args = parser.parse_known_args()[0]
     self.client = clientfromargs(args)
Beispiel #13
0
 def test_sync():
     print('test_sync')
     args = parser.parse_known_args()[0]
     client = clientfromargs(args)
     client.sync()
Beispiel #14
0
def do_ofximport(args, client=None):
    if client is None:
        client = clientfromargs(args)

    tree = OFXTree()
    tree.parse(args.ofxfile)
    response = tree.convert()
    stmts = response.statements

    accounts = client.budget.be_accounts
    accountvsnotes = {
        account.note: account
        for account in accounts if account.note is not None
    }

    for stmt in stmts:
        key = stmt.account.bankid + ' ' + stmt.account.branchid + ' ' + stmt.account.acctid
        if all(key not in note for note in accountvsnotes):
            if len(accounts) == 0:
                print('No accounts available in this budget')
                exit(-1)

            # ask user input for which bank account this is, then save it into the account note in nYNAB
            account = client.select_account_ui()

            # Save the selection in the nYNAB account note
            addon = 'key[' + key + ']key'
            if account.note is not None:
                account.note += addon
            else:
                account.note = addon
            client.sync()
        else:
            for note in accountvsnotes:
                if key in note:
                    account = accountvsnotes[note]

                    imported_date = datetime.now().date()

                    for ofx_transaction in stmt.transactions:
                        payee_name = ofx_transaction.name if ofx_transaction.payee is None else ofx_transaction.payee
                        try:
                            payee = next(p for p in client.budget.be_payees
                                         if p.name == payee_name)
                        except StopIteration:
                            payee = Payee(name=payee_name)
                            client.budget.be_payees.append(payee)
                            client.sync()

                        # use ftid so we don't import duplicates
                        if not any(
                                ofx_transaction.fitid in transaction.memo for
                                transaction in client.budget.be_transactions
                                if transaction.memo is not None and
                                transaction.entities_account_id == account.id):
                            transaction = Transaction(
                                date=ofx_transaction.dtposted,
                                memo=ofx_transaction.memo + '    ' +
                                ofx_transaction.fitid,
                                imported_payee=payee_name,
                                entities_payee_id=payee.id,
                                imported_date=imported_date,
                                source="Imported",
                                check_number=ofx_transaction.checknum,
                                amount=float(ofx_transaction.trnamt),
                                entities_account_id=account.id)
                            client.add_transaction(transaction)
Beispiel #15
0
def do_csvimport(args,client=None):
    if client is None:
        client = clientfromargs(args)
    logger=get_logger(args)

    logger.debug('selected schema %s' % (args.schema,))
    if os.path.exists(args.schema):
        schemafile = args.schema
    else:
        schemafile = os.path.join(schemas_dir, args.schema + '.json')
        if not os.path.exists(schemafile):
            logger.error('This schema doesn''t exist in csv_schemas')
            exit(-1)
    try:
        schema = SchemaModel(schemafile, case_insensitive_headers=True)
        with open(schemafile,'r') as sf:
            schemacontent = json.load(sf)
            try:
                nheaders = schemacontent['nheaders']
            except KeyError:
                nheaders = 1
    except InvalidSchemaError:
        logger.error('Invalid CSV schema')
        raise
    logger.debug('schema headers %s' % schema.headers)

    if 'account' not in schema.headers and args.accountname is None:
        logger.error('This schema does not have an account column and no account name was provided')
        exit(-1)

    accounts = {x.account_name: x for x in client.budget.be_accounts}
    payees = {p.name: p for p in client.budget.be_payees}
    mastercategories_perid = {m.id: m for m in client.budget.be_master_categories}
    subcategories = {}
    for s in client.budget.be_subcategories:
        m=mastercategories_perid[s.entities_master_category_id]
        subcategories[m.name+':'+s.name]=s

    def getaccount(accountname):
        try:
            logger.debug('searching for account %s' % accountname)
            return accounts[accountname]
        except KeyError:
            logger.error('Couldn''t find this account: %s' % accountname)
            exit(-1)

    def getpayee(payeename):
        try:
            logger.debug('searching for payee %s' % payeename)
            return payees[payeename]
        except KeyError:
            logger.debug('Couldn''t find this payee: %s' % payeename)
            payee=Payee(name=payeename)
            client.budget.be_payees.append(payee)
            return payee

    def getsubcategory(categoryname):
        try:
            logger.debug('searching for subcategory %s' % categoryname)
            return subcategories[categoryname]
        except KeyError:
            get_logger(args).debug('Couldn''t find this category: %s' % categoryname)
            exit(-1)

    if 'account' not in schema.headers:
        entities_account_id = getaccount(args.accountname).id

    if 'inflow' in schema.headers and 'outflow' in schema.headers:
        pass
    elif 'amount' in schema.headers:
        pass
    else:
        logger.error('This schema doesn''t provide an amount column or (inflow,outflow) columns')
        exit(-1)

    csvrow = namedtuple('CSVrow', field_names=schema.headers)
    transactions = []

    imported_date=datetime.now().date()

    get_logger(args).debug('OK starting the import from %s '%os.path.abspath(args.csvfile))
    with open(args.csvfile, 'r') as inputfile:
        header = inputfile.readline()
        for row in csv.reader(inputfile):
            if sys.version[0] == '2':
                row = [cell.decode('utf-8') for cell in row]
            get_logger(args).debug('read line %s' % row)
            result = csvrow(*list(schema.convert_row(*row, fail_fast=True)))
            if 'account' in schema.headers:
                entities_account_id = getaccount(result.account).id
            if 'inflow' in schema.headers and 'outflow' in schema.headers:
                amount = result.inflow - result.outflow
            elif 'amount' in schema.headers:
                amount = result.amount
            else:
                get_logger(args).error('Couldn''t find this account: %s' % args.accountname)
                exit(-1)

            if 'category' in schema.headers and result.category:
                entities_subcategory_id = getsubcategory(result.category).id
            else:
                entities_subcategory_id = None
            if 'payee' in schema.headers:
                imported_payee=result.payee
            else:
                imported_payee=''
            entities_payee_id = getpayee(imported_payee).id
            if 'memo' in schema.headers:
                memo=result.memo
            else:
                memo=''


            transaction=Transaction(
                entities_account_id=entities_account_id,
                amount=amount,
                date=result.date,
                entities_payee_id=entities_payee_id,
                entities_subcategory_id=entities_subcategory_id,
                imported_date=imported_date,
                imported_payee=imported_payee,
                memo=memo,
                source="Imported"
            )
            if args.import_duplicates or (not client.budget.be_transactions.containsduplicate(transaction)):
                get_logger(args).debug('Appending transaction %s '%transaction.getdict())
                transactions.append(transaction)
            else:
                get_logger(args).debug('Duplicate transaction found %s '%transaction.getdict())



    client.add_transactions(transactions)
Beispiel #16
0
    def testiimport(self):
        parser = configargparse.getArgumentParser('pynYNAB')
        args = parser.parse_known_args()[0]
        args.ofxfile = os.path.join(tempfile.gettempdir(), 'data.ofx')
        args.logginglevel = 'debug'

        self.client = clientfromargs(args)

        content = """OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1>
<SONRS>
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<DTSERVER>20130313133728
<LANGUAGE>FRA
</SONRS>
</SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>29939615002
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<STMTRS>
<CURDEF>EUR
<BANKACCTFROM>
<BANKID>11706
<BRANCHID>41029
<ACCTID>29939615002
<ACCTTYPE>CHECKING
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>20130128000000
<DTEND>20130314235959
<STMTTRN>
<TRNTYPE>CHECK
<DTPOSTED>20130312
<TRNAMT>-491.09
<FITID>13071099780237330004
<CHECKNUM>0003445
<NAME>CHEQUE
<MEMO>CHEQUE
</STMTTRN>
</BANKTRANLIST>
<LEDGERBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</LEDGERBAL>
<AVAILBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>"""
        with open(args.ofxfile, 'w') as f:
            f.writelines(content)
        imported_date = datetime.now().date()

        testaccount = 'TEST'
        account = self.util_get_empty_account_by_name_if_doesnt_exist(
            testaccount)

        key = '11706 41029 29939615002'
        account.note = 'great note key[%s]key' % key
        self.client.budget.be_accounts.modify(account)
        self.client.sync()

        def getTr(date, payee, amount, memo, account):
            return Transaction(
                entities_account_id=account.id,
                date=date,
                entities_payee_id=self.util_add_payee_by_name_if_doesnt_exist(
                    payee).id,
                imported_payee=payee,
                source='Imported',
                check_number='0003445',
                memo=memo,
                amount=amount,
                cash_amount=amount,
                imported_date=imported_date)

        Transactions = [
            getTr(
                datetime(year=2013, month=3, day=12).date(), 'CHEQUE', -491.09,
                'CHEQUE    13071099780237330004', account),
        ]

        do_ofximport(args)
        self.reload()
        for tr in Transactions:
            print('Should have been imported:')
            print(json.dumps(tr, cls=ComplexEncoder))
            print('Found in the register:')
            print(
                json.dumps([
                    tr2 for tr2 in self.client.budget.be_transactions
                    if tr2.amount == tr.amount
                ],
                           cls=ComplexEncoder))
            self.assertTrue(
                self.client.budget.be_transactions.containsduplicate(tr),
                msg=
                'couldnt find a transaction with the same hash after ofx import'
            )
Beispiel #17
0
    def testiimport(self):
        parser = configargparse.getArgumentParser('pynYNAB')
        args=parser.parse_known_args()[0]
        args.ofxfile = os.path.join(tempfile.gettempdir(),'data.ofx')
        args.logginglevel= 'debug'

        self.client=clientfromargs(args)

        content="""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1>
<SONRS>
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<DTSERVER>20130313133728
<LANGUAGE>FRA
</SONRS>
</SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>29939615002
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<STMTRS>
<CURDEF>EUR
<BANKACCTFROM>
<BANKID>11706
<BRANCHID>41029
<ACCTID>29939615002
<ACCTTYPE>CHECKING
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>20130128000000
<DTEND>20130314235959
<STMTTRN>
<TRNTYPE>CHECK
<DTPOSTED>20130312
<TRNAMT>-491.09
<FITID>13071099780237330004
<CHECKNUM>0003445
<NAME>CHEQUE
<MEMO>CHEQUE
</STMTTRN>
</BANKTRANLIST>
<LEDGERBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</LEDGERBAL>
<AVAILBAL>
<BALAMT>-6348.01
<DTASOF>20130312
</AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>"""
        with open(args.ofxfile,'w') as f:
            f.writelines(content)
        imported_date=datetime.now().date()

        testaccount='TEST'
        account=self.util_get_empty_account_by_name_if_doesnt_exist(testaccount)

        key = '11706 41029 29939615002'
        account.note='great note key[%s]key' %key
        self.client.budget.be_accounts.modify(account)
        self.client.sync()

        def getTr(date,payee,amount,memo,account):
            return Transaction(
                entities_account_id=account.id,
                date=date,
                entities_payee_id=self.util_add_payee_by_name_if_doesnt_exist(payee).id,
                imported_payee=payee,
                source='Imported',
                check_number='0003445',
                memo=memo,
                amount=amount,
                cash_amount=amount,
                imported_date=imported_date
            )
        Transactions = [
            getTr(datetime(year=2013, month=3, day=12).date(),'CHEQUE',-491.09,'CHEQUE    13071099780237330004',account),
        ]

        do_ofximport(args)
        self.reload()
        for tr in Transactions:
            print('Should have been imported:')
            print(json.dumps(tr,cls=ComplexEncoder))
            print('Found in the register:')
            print(json.dumps([tr2 for tr2 in self.client.budget.be_transactions if tr2.amount==tr.amount],cls=ComplexEncoder))
            self.assertTrue(self.client.budget.be_transactions.containsduplicate(tr),
                            msg='couldnt find a transaction with the same hash after ofx import')
Beispiel #18
0
def do_ofximport(args, client = None):
    if client is None:
        client = clientfromargs(args)

    tree = OFXTree()
    tree.parse(args.ofxfile)
    response = tree.convert()
    stmts = response.statements

    accounts = client.budget.be_accounts
    accountvsnotes={account.note:account for account in accounts if account.note is not None}

    for stmt in stmts:
        key = stmt.account.bankid + ' ' + stmt.account.branchid + ' ' + stmt.account.acctid
        if all(key not in note for note in accountvsnotes):
            if len(accounts) == 0:
                print('No accounts available in this budget')
                exit(-1)

            # ask user input for which bank account this is, then save it into the account note in nYNAB
            account = client.select_account_ui()

            # Save the selection in the nYNAB account note
            addon = 'key[' + key + ']key'
            if account.note is not None:
                account.note += addon
            else:
                account.note = addon
            client.budget.be_accounts.modify(account)
            client.sync()
        else:
            for note in accountvsnotes:
                if key in note:
                    account=accountvsnotes[note]

                    imported_date=datetime.now().date()

                    for ofx_transaction in stmt.transactions:
                        payee_name = ofx_transaction.name if ofx_transaction.payee is None else ofx_transaction.payee
                        try:
                            payee = next(p for p in client.budget.be_payees if p.name == payee_name)
                        except StopIteration:
                            payee=Payee(
                                name=payee_name
                            )
                            client.budget.be_payees.append(payee)
                            client.sync()

                        # use ftid so we don't import duplicates
                        if not any(ofx_transaction.fitid in transaction.memo for transaction in client.budget.be_transactions if
                                   transaction.memo is not None and transaction.entities_account_id == account.id):

                            transaction = Transaction(
                                date=ofx_transaction.dtposted,
                                memo=ofx_transaction.memo + '    '+ofx_transaction.fitid,
                                imported_payee=payee_name,
                                entities_payee_id=payee.id,
                                imported_date=imported_date,
                                source="Imported",
                                check_number=ofx_transaction.checknum,
                                amount=float(ofx_transaction.trnamt),
                                entities_account_id=account.id
                            )
                            client.add_transaction(transaction)