예제 #1
0
 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)
예제 #2
0
    def __init__(self, **kwargs):
        self.server_entities = {}
        self.budget_version_id = None
        self.logger = kwargs.get('logger', None)
        if self.logger is None:
            self.logger = get_logger()

        self.budget_name = kwargs.get('budgetname', None)
        if self.budget_name is None:
            logger.error('No budget name was provided')
            exit(-1)
        self.connection = kwargs.get('nynabconnection', None)
        self.catalog = Catalog()
        self.budget = Budget()
        self.budget_version = BudgetVersion()

        self.current_device_knowledge = {}
        self.device_knowledge_of_server = {}
        self.starting_device_knowledge = 0
        self.ending_device_knowledge = 0

        engine = kwargs.get('engine', create_engine('sqlite://'))

        Base.metadata.create_all(engine)
        self.Session = sessionmaker(bind=engine)

        self.session = self.Session()
        self.session.add(self.catalog)
        self.session.add(self.budget)
        self.session.commit()

        self.online = self.connection is not None
        self.catalogClient = RootObjClient(self.catalog, self, 'syncCatalogData')
        self.budgetClient = RootObjClient(self.budget, self, 'syncBudgetData')
예제 #3
0
def csvimport_main():
    print('pynYNAB CSV import')
    """Manually import a CSV into a nYNAB budget"""
    parser = configargparse.getArgumentParser('pynYNAB')
    parser.description = inspect.getdoc(csvimport_main)
    parser.add_argument('csvfile', metavar='CSVpath', type=str,
                        help='The CSV file to import')
    parser.add_argument('schema', metavar='schemaName', type=str,
                        help='The CSV schema to use (see csv_schemas directory)')
    parser.add_argument('accountname', metavar='AccountName', type=str, nargs='?',
                        help='The nYNAB account name  to use')
    parser.add_argument('-import-duplicates', action='store_true',
                        help='Forces the import even if a duplicate (same date, account, amount, memo, payee) is found')

    args = parser.parse_args()
    test_common_args(args)

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

    do_csvimport(args)
예제 #4
0
def csvimport_main():
    print('pynYNAB CSV import')
    """Manually import a CSV into a nYNAB budget"""
    parser = configargparse.getArgumentParser('pynYNAB')
    parser.description=inspect.getdoc(csvimport_main)
    parser.add_argument('csvfile', metavar='CSVpath', type=str,
                        help='The CSV file to import')
    parser.add_argument('schema', metavar='schemaName', type=str,
                        help='The CSV schema to use (see csv_schemas directory)')
    parser.add_argument('accountname', metavar='AccountName', type=str,nargs='?',
                        help='The nYNAB account name  to use')
    parser.add_argument('-import-duplicates', action='store_true',
                        help='Forces the import even if a duplicate (same date, account, amount, memo, payee) is found')

    args = parser.parse_args()
    test_common_args(args)

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

    do_csvimport(args)
예제 #5
0
    def __init__(self, nynabconnection, budget_name):
        self.delta_device_knowledge = 0
        self.budget_version_id = None
        self.logger = get_logger()
        if budget_name is None:
            logger.error('No budget name was provided')
            exit(-1)
        self.budget_name = budget_name
        self.connection = nynabconnection
        self.budget_name = budget_name
        self.catalog = Catalog()
        self.budget = Budget()
        self.budget_version = BudgetVersion()

        self.current_device_knowledge = {}
        self.device_knowledge_of_server = {}

        self.first = True
        self.sync()
예제 #6
0
    def __init__(self, nynabconnection, budget_name):
        self.delta_device_knowledge = 0
        self.budget_version_id = None
        self.logger = get_logger()
        if budget_name is None:
            logger.error('No budget name was provided')
            exit(-1)
        self.budget_name = budget_name
        self.connection = nynabconnection
        self.budget_name = budget_name
        self.catalog = Catalog()
        self.budget = Budget()
        self.budget_version = BudgetVersion()

        self.current_device_knowledge = {}
        self.device_knowledge_of_server = {}

        self.first = True
        self.sync()
예제 #7
0
    def from_obj(args, reset=False, sync=True, **kwargs):
        try:
            if not hasattr(args, 'logginglevel'):
                setattr(args, 'logginglevel', 'error')

            kwargs['logger'] = get_logger(args)
            kwargs['budgetname'] = args.budgetname
            kwargs['nynabconnection'] = nYnabConnection(args.email, args.password)
            if hasattr(args, 'engine'):
                kwargs['engine'] = args.engine

            client = nYnabClient(**kwargs)
            if sync:
                client.sync()
            if reset:
                # deletes the budget
                client.delete_budget(args.budgetname)
                client.create_budget(args.budgetname)
                client.select_budget(args.budgetname)
            return client
        except BudgetNotFound:
            print('No budget by the name %s found in nYNAB' % args.budgetname)
            exit(-1)
예제 #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)
예제 #9
0
import unittest

from pynYNAB.Client import clientfromargs
from pynYNAB.scripts.config import parser, get_logger

# sets up the logger
logger = get_logger()


# used to ping the nYNAB API to check that the sync works
class TestSync(unittest.TestCase):
    @staticmethod
    def test_sync():
        print('test_live')
        args = parser.parse_known_args()[0]
        client = clientfromargs(args)
        client.sync()


if __name__ == '__main__':
    TestSync.test_sync()
예제 #10
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]
            if all(map(lambda x:x.strip()=='',row)):
                continue
            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)