Example #1
0
    def test_roundtrip(self):
        args = parser.parse_known_args()[0]

        # 1. gets sync data from server
        # 2. tests that to_api(from_api(data)) is the same thing

        client = clientfromargs(args, sync=False)
        sync_data = client.catalogClient.get_sync_data_obj()
        budget_version_id = next(d['id'] for d in sync_data['changed_entities']['ce_budget_versions'] if
                                 d['version_name'] == args.budgetname)
        client.budget_version_id = budget_version_id

        for objclient in (client.budgetClient, client.catalogClient):
            sync_data = objclient.get_sync_data_obj()
            server_changed_entities = sync_data['changed_entities']

            for key in server_changed_entities:
                if key in objclient.obj.listfields:
                    if len(server_changed_entities[key]) == 0:
                        continue
                    obj_dict = server_changed_entities[key][0]
                    typ = objclient.obj.listfields[key]
                    obj_dict2 = typ.from_apidict(obj_dict).get_apidict()

                    diff = DictDiffer(obj_dict2, obj_dict)
                    for k in diff.changed():
                        AssertionError('changed {}: {}->{}'.format(k, obj_dict[k], obj_dict2[k]))
                    for k in diff.removed():
                        AssertionError('removed {}: {}'.format(k, obj_dict[k]))
                    for k in diff.added():
                        AssertionError('added {}: {}'.format(k, obj_dict2[k]))
                elif key in objclient.obj.scalarfields:
                    obj_dict2 = objclient.obj.from_apidict(server_changed_entities).get_apidict()
                    if server_changed_entities[key] != obj_dict2[key]:
                        AssertionError('changed {}: {}->{}'.format(key, server_changed_entities[key], obj_dict2[key]))
Example #2
0
    def ofximport(cls):
        """Manually import an OFX into a nYNAB budget"""
        print('pynYNAB OFX import')

        args = cls.ofximport_parser.parse_args()
        verify_common_args(args)
        client = clientfromargs(args)
        delta = do_ofximport(args, client)
        client.push(expected_delta=delta)
Example #3
0
    def csvimport(cls):
        """Manually import a CSV into a nYNAB budget"""
        print('pynYNAB CSV import')

        args = cls.csvimport_parser.parse_args()
        verify_common_args(args)

        schema = verify_csvimport(args)
        client = clientfromargs(args)
        delta = do_csvimport(args, schema, client)
        client.push(expected_delta=delta)
Example #4
0
    def csvimport(cls):
        """Manually import a CSV into a nYNAB budget"""
        print('pynYNAB CSV import')

        args = cls.csvimport_parser.parse_args()
        verify_common_args(args)

        if not os.path.exists(args.csvfile):
            LOG.error('input CSV file does not exist')
            exit(-1)

        client = clientfromargs(args)
        delta = do_csvimport(args, client)
        client.push(expected_delta=delta)
Example #5
0
 def reload(self):
     # parser = configargparse.getArgumentParser('pynYNAB')
     args = parser.parse_known_args()[0]
     self.client = clientfromargs(args)
Example #6
0
 def setUp(self):
     args = parser.parse_known_args()[0]
     args.budgetname = test_budget_name
     self.client = clientfromargs(args, sync=False)
     self.client.catalogClient.sync()
     self.client.select_budget(test_budget_name)
Example #7
0
def do_ofximport(args, stmts, client=None):
    delta = 0
    if client is None:
        client = clientfromargs(args)

    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
        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)
                            delta += 1

                        # 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.budget.be_transactions.append(transaction)
                            delta += 1

    return delta
Example #8
0
def do_csvimport(args, client=None):
    delta = 0
    if client is None:
        client = clientfromargs(args)

    LOG.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):
            LOG.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:
        LOG.error('Invalid CSV schema')
        raise
    LOG.debug('schema headers %s' % schema.headers)

    if 'account' not in schema.headers and args.accountname is None:
        LOG.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:
            LOG.debug('searching for account %s' % accountname)
            return accounts[accountname]
        except KeyError:
            LOG.error('Couldn''t find this account: %s' % accountname)
            exit(-1)

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

    def getsubcategory(categoryname):
        try:
            LOG.debug('searching for subcategory %s' % categoryname)
            return subcategories[categoryname]
        except KeyError:
            LOG.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:
        LOG.error('This schema doesn''t provide an amount column or (inflow,outflow) columns')
        exit(-1)

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

    imported_date = datetime.now().date()

    LOG.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
            LOG.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:
                LOG.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,
                cash_amount=amount,
                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.key2 in [tr.key2 for tr in client.budget.be_transactions]):
                LOG.debug('Appending transaction %s ' % transaction.get_dict())
                client.budget.be_transactions.append(transaction)
                delta += 1
            else:
                LOG.debug('Duplicate transaction found %s ' % transaction.get_dict())

    return delta
Example #9
0
import random

from datetime import datetime

from pynYNAB.ClientFactory import clientfromargs
from pynYNAB.__main__ import parser
from pynYNAB.schema.budget import Transaction

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

args = parser.parse_known_args()[0]
N = 20
client = clientfromargs(args)
client.sync()
account = next(acc for acc in client.budget.be_accounts)
for _ in range(0, N):
    transaction = Transaction(cleared='Uncleared',
                              date=datetime.now(),
                              entities_account=account,
                              amount=random.randrange(-10, 10))
    client.add_transaction(transaction)