def test_add_transfer(self): account1 = next(account for account in self.client.budget.be_accounts if account.account_name == 'account1') account2 = next(account for account in self.client.budget.be_accounts if account.account_name == 'account2') try: payee_2 = next(payee for payee in self.client.budget.be_payees if payee.entities_account_id == account2.id) except StopIteration: payee_2 = Payee(entities_account_id=account2.id) self.client.budget.be_payees.append(payee_2) try: payee_1 = next(payee for payee in self.client.budget.be_payees if payee.entities_account_id == account1.id) except StopIteration: payee_1 = Payee(entities_account_id=account1.id) self.client.budget.be_payees.append(payee_1) transaction1 = Transaction(amount=random.randint(-10, 10), date=datetime.now(), entities_account_id=account1.id, entities_payee_id=payee_2.id) transaction2 = Transaction(amount=-transaction1.amount, date=datetime.now(), entities_account_id=account2.id, entities_payee_id=payee_1.id) self.client.budget.be_transactions.append(transaction1) self.client.budget.be_transactions.append(transaction2) self.client.sync() self.reload() self.assertIn(transaction1, self.client.budget.be_transactions) self.assertIn(transaction2, self.client.budget.be_transactions)
def test_get_ce_addtransactionsubtransaction(client): client.budgetClient.clear_changed_entities() added_transaction = Transaction() subtransaction1 = Subtransaction(entities_transaction=added_transaction) subtransaction2 = Subtransaction(entities_transaction=added_transaction) client.budget.be_transactions.append(added_transaction) client.budget.be_subtransactions.append(subtransaction1) client.budget.be_subtransactions.append(subtransaction2) client.session.commit() changed_entities = client.budgetClient.get_changed_apidict() assert isinstance(changed_entities, dict) assert 1 == len(changed_entities.keys()) assert 'be_transaction_groups' == list(changed_entities.keys())[0] transaction_groups = list(changed_entities['be_transaction_groups']) assert 1 == len(transaction_groups) assert added_transaction.get_apidict( ) == transaction_groups[0]['be_transaction'] assert transaction_groups[0]['be_subtransactions'] is not None subtransactions = transaction_groups[0]['be_subtransactions'] assert len(subtransactions) == 2 assert subtransaction1.get_apidict() in subtransactions assert subtransaction2.get_apidict() in subtransactions
def test_equality(): tr1 = Transaction(id='t') tr2 = Transaction(id='t') assert tr1 == tr2 tr1 = Transaction() tr2 = Transaction() assert tr1 != tr2
def testequality(self): tr1 = Transaction(id='t') tr2 = Transaction(id='t') self.assertEqual(tr1, tr2) tr1 = Transaction() tr2 = Transaction() self.assertNotEqual(tr1, tr2)
def testequality(self): tr1 = Transaction() tr2 = Transaction() self.assertNotEqual(tr1, tr2) tr1 = Transaction(entities_account_id=1) tr2 = Transaction(entities_account_id=2) self.assertNotEqual(tr1, tr2)
def testequality(self): tr1 = Transaction(id='t') tr2 = Transaction(id='t') self.assertTrue(tr1 == tr2) tr1 = Transaction() tr2 = Transaction() self.assertFalse(tr1 == tr2)
def test_str(self): # tests no exceptions when getting the string representation of some entities obj = Transaction() obj.__str__() obj.__unicode__() obj2 = Budget() obj2.be_accounts.__str__() obj2.be_accounts.__unicode__()
def create_transaction_from_csv(data, account, settings=settings_module, ynab_client = ynab_client_module): settings.log.debug('received data %s' % data) expected_delta = 0 if data['amount'] == 0: return {'error': 'Transaction amount is 0.'} payee_name = data['description'] subcategory_id = get_subcategory_from_payee(payee_name) # If we are creating the payee, then we need to increase the delta if not ynab_client.payeeexists(payee_name): print 'does not exist' settings.log.debug('payee does not exist, will create %s', payee_name) expected_delta += 1 # Get the payee ID. This will append a new one if needed entities_payee_id = ynab_client.getpayee(payee_name).id # If we created a payee, then we need to resync the payees cache if expected_delta == 1: ynab_client.cache_payees() # Create the Transaction settings.log.debug('Creating transaction object') transaction = Transaction( entities_account_id=account.id, amount=Decimal(data['amount']), date=parse(data['date'], dayfirst=True), entities_payee_id=entities_payee_id, imported_date=datetime.now().date(), imported_payee=payee_name, cleared=True, source='Imported' ) if subcategory_id is not None: transaction.entities_subcategory_id = subcategory_id settings.log.debug('Duplicate detection') if ynab_client.containsDuplicate(transaction): settings.log.debug('skipping due to duplicate transaction') # We may just be adding a payee if expected_delta == 1: print 'just adding payee' return expected_delta else: return {'error': 'Tried to add a duplicate transaction.'} else: expected_delta += 1 settings.log.debug('appending and pushing transaction to YNAB. Delta: %s', expected_delta) ynab_client.client.budget.be_transactions.append(transaction) return expected_delta
def testgetChangedEntities_addtransactionsubtransaction(self): added_transaction = Transaction() subtransaction1 = Subtransaction( entities_transaction=added_transaction) subtransaction2 = Subtransaction( entities_transaction=added_transaction) self.client.budget.be_transactions.append(added_transaction) self.client.budget.be_subtransactions.append(subtransaction1) self.client.budget.be_subtransactions.append(subtransaction2) self.client.session.commit() changed_entities = self.client.budget.get_changed_entities() self.assertIsInstance(changed_entities, dict) self.assertEqual(1, len(changed_entities.keys())) self.assertEqual('be_transaction_groups', list(changed_entities.keys())[0]) transaction_groups = changed_entities['be_transaction_groups'] self.assertEqual(1, len(transaction_groups)) self.assertEqual(added_transaction, transaction_groups[0]['be_transaction']) self.assertIsNotNone(transaction_groups[0]['be_subtransactions']) try: self.assertItemsEqual( [subtransaction1, subtransaction2], set(transaction_groups[0]['be_subtransactions'])) except AttributeError: self.assertCountEqual( [subtransaction1, subtransaction2], set(transaction_groups[0]['be_subtransactions']))
def add_account(self, account, balance, balance_date): payee = Payee( entities_account_id=account.id, enabled=True, auto_fill_subcategory_enabled=True, auto_fill_memo_enabled=False, auto_fill_amount_enabled=False, rename_on_import_enabled=False, name="Transfer : %s" % account.account_name ) immediateincomeid = next( s.id for s in self.budget.be_subcategories if s.internal_name == 'Category/__ImmediateIncome__') startingbalanceid = next(p.id for p in self.budget.be_payees if p.internal_name == 'StartingBalancePayee') transaction = Transaction( accepted=True, amount=balance, entities_subcategory_id=immediateincomeid, cash_amount=0, cleared='Cleared', date=balance_date, entities_account_id=account.id, credit_amount=0, entities_payee_id=startingbalanceid, is_tombstone=False ) self.budget.be_accounts.append(account) self.budget.be_payees.append(payee) self.budget.be_transactions.append(transaction)
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
def testappendBad(self): obj = Budget() transaction = Transaction() def testappend(): obj.be_accounts.append(transaction) self.assertRaises(ValueError, testappend)
def util_add_transaction(self): transaction = Transaction( amount=1, cleared='Uncleared', date=datetime.now(), entities_account_id=self.account.id, ) self.client.add_transaction(transaction)
def test_add_deletetransactions(self): from datetime import datetime transactions = [ Transaction( amount=random.randint(-10, 10), cleared='Uncleared', date=datetime.now() - 8 * timedelta(days=365), entities_account_id=self.account.id, ), Transaction( amount=random.randint(-10, 10), cleared='Uncleared', date=datetime.now() + 8 * timedelta(days=365), entities_account_id=self.account.id, ), Transaction( amount=random.randint(-10, 10), cleared='Uncleared', date=datetime.now(), entities_account_id=self.account.id, ) ] self.client.add_transactions(transactions) print('Time for request: ' + str(self.client.connection.lastrequest_elapsed.total_seconds()) + ' s') self.reload() for transaction in transactions: self.assertIn(transaction, self.client.budget.be_transactions) for transaction in transactions: self.client.delete_transaction(transaction) self.reload() for transaction in transactions: resulttransaction = self.client.budget.be_transactions.get( transaction.id) self.assertTrue(resulttransaction is None)
def get_transaction(client, date, payee, amount, memo, account): imported_date = datetime.now().date() return Transaction(entities_account_id=get_or_create_account( client, account).id, date=date, entities_payee_id=get_or_create_payee(client, payee).id, imported_payee=payee, source='Imported', memo=memo, amount=amount, cash_amount=amount, imported_date=imported_date)
def get_ynab_transaction(nordea_transaction, account_id, subcategory_id, payee_id): imported_date = datetime.datetime.now().date() splitted_amount = nordea_transaction.amount.split(",") return Transaction( entities_account_id=account_id, amount=float("-%s.%s" % (splitted_amount[0], splitted_amount[1])), date=datetime.datetime.strptime(nordea_transaction.date, "%d.%m.%Y"), imported_date=imported_date, entities_subcategory_id=subcategory_id, entities_payee_id=payee_id, source="Imported")
def test_add_deletetransaction(account, live_client_w_account): transaction = Transaction( amount=1, cleared='Uncleared', date=datetime.now(), entities_account_id=account.id, ) live_client_w_account.add_transaction(transaction) live_client_w_account = reload() assert transaction in live_client_w_account.budget.be_transactions live_client_w_account.delete_transaction(transaction) live_client_w_account = reload() assert transaction not in live_client_w_account.budget.be_transactions
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)
def getTr(self, date, payee, amount, memo, account): imported_date = datetime.now().date() return Transaction( entities_account_id=self.util_get_empty_account_by_name_if_doesnt_exist(account).id, date=date, entities_payee_id=self.util_add_payee_by_name_if_doesnt_exist(payee).id, imported_payee=payee, source='Imported', memo=memo, amount=amount, cash_amount=amount, imported_date=imported_date )
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 ]))) pass
def test_str(self): # tests no exceptions when getting the string representation of some entities obj = Transaction() obj.__str__() obj.__unicode__() obj2 = Budget() obj2.be_accounts.__str__()
def test_add_deletetransaction(self): from datetime import datetime transaction = Transaction( amount=1, cleared='Uncleared', date=datetime.now(), entities_account_id=self.account.id, ) self.client.add_transaction(transaction) self.reload() self.assertIn(transaction, self.client.budget.be_transactions) self.client.delete_transaction(transaction) self.reload() self.assertNotIn(transaction, self.client.budget.be_transactions)
def test_add_splittransactions(self): subcatsplit_id = next( subcategory.id for subcategory in self.client.budget.be_subcategories if subcategory.internal_name == 'Category/__Split__') transaction = Transaction(amount=1, date=datetime.now(), entities_account_id=self.account.id, entities_subcategory_id=subcatsplit_id) sub1 = Subtransaction(amount=5000, entities_transaction_id=transaction.id) sub2 = Subtransaction(amount=5000, entities_transaction_id=transaction.id) self.client.budget.be_transactions.append(transaction) self.client.budget.be_subtransactions.append(sub1) self.client.budget.be_subtransactions.append(sub2) self.client.sync() self.reload() self.assertIn(transaction, self.client.budget.be_transactions) self.assertIn(sub1, self.client.budget.be_subtransactions) self.assertIn(sub2, self.client.budget.be_subtransactions)
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)
def test_hash(self): tr1 = Transaction() result = tr1._hash() self.assertIsInstance(result, int)
def testrepr(self): tr1 = Transaction(id='t') self.assertEqual(tr1.__repr__(), tr1.__str__())
def testCE_nochange(self): obj = Transaction(None) self.assertEqual(obj.get_changed_entities(), {})
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()
def add_transaction(self, **kwargs): payee = self.get_payee(kwargs['payee']) subcategory = self.get_subcategory(kwargs['subcategory']) if not self.has_matching_transaction(kwargs['id']): transaction = Transaction() transaction.date = kwargs['date'] transaction.memo = 'AUTO IMPORT - {}'.format(kwargs['id']) transaction.imported_payee = payee.name transaction.entities_payee_id = payee.id transaction.entities_subcategory_id = subcategory.id if subcategory else None transaction.imported_date = datetime.datetime.now().date() transaction.source = "Imported" transaction.amount = kwargs['value'] transaction.entities_account_id = self.account.id self.client.budget.be_transactions.append(transaction) self.delta += 1
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')
def do_csvimport(args, client): LOG.debug('selected schema %s' % (args.schema, )) LOG.debug('schema headers %s' % args.schema.headers) delta = 0 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(account_name): try: LOG.debug('searching for account %s' % account_name) return accounts[account_name] except KeyError: LOG.error('Couldn' 't find this account: %s' % account_name) exit(-1) def getpayee(payee_name): global delta try: LOG.debug('searching for payee %s' % payee_name) return payees[payee_name] except KeyError: LOG.debug('Couldn' 't find this payee: %s' % payee_name) payee = Payee(name=payee_name) client.budget.be_payees.append(payee) delta += 1 return payee def getsubcategory(category_name): try: LOG.debug('searching for subcategory %s' % category_name) return subcategories[category_name] except KeyError: LOG.debug('Couldn' 't find this category: %s' % category_name) exit(-1) entities_account_id = None if 'account' not in args.schema.headers: entities_account_id = getaccount(args.account_name).id amount = None if 'inflow' in args.schema.headers and 'outflow' in args.schema.headers: pass elif 'amount' in args.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=args.schema.headers) imported_date = datetime.now().date() LOG.debug('OK starting the import from %s ' % os.path.abspath(args.csv_file)) with open(args.csv_file, 'r') as inputfile: header = [] for i in range(0, args.schema.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(args.schema.convert_row(*row, fail_fast=True))) if 'account' in args.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 args.schema.headers and 'outflow' in args.schema.headers: amount = result.inflow - result.outflow elif 'amount' in args.schema.headers: amount = result.amount if 'category' in args.schema.headers and result.category: entities_subcategory_id = getsubcategory(result.category).id else: entities_subcategory_id = None if 'payee' in args.schema.headers: imported_payee = result.payee else: imported_payee = '' entities_payee_id = getpayee(imported_payee).id if 'memo' in args.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
def create_transaction_from_monzo(data, settings=settings_module, ynab_client = ynab_client_module): settings.log.debug('received data %s' % data) expected_delta = 0 data_type = data.get('type') settings.log.debug('webhook type received %s', data_type) if data_type != 'transaction.created': return {'error': 'Unsupported webhook type: %s' % data_type}, 400 # the actual monzo data is in the data['data]' value data = data['data'] if 'decline_reason' in data: return {'message': 'Ignoring declined transaction ({})'.format(data['decline_reason'])}, 200 # Sync the account so we get the latest payees ynab_client.sync() if data['amount'] == 0: return {'error': 'Transaction amount is 0.'}, 200 # Does this account exist? account = ynab_client.getaccount(settings.monzo_ynab_account) if not account: return {'error': 'Account {} was not found'.format(settings.monzo_ynab_account)}, 400 # Work out the Payee Name if data.get('merchant'): payee_name = data['merchant']['name'] subcategory_id = get_subcategory_from_payee(payee_name) else: # This is a p2p transaction payee_name = get_p2p_transaction_payee_name(data) subcategory_id = None # If we are creating the payee, then we need to increase the delta if not ynab_client.payeeexists(payee_name): settings.log.debug('payee does not exist, will create %s', payee_name) expected_delta += 1 # Get the payee ID. This will append a new one if needed entities_payee_id = ynab_client.getpayee(payee_name).id memo = '' if settings.include_emoji and data['merchant'] and data['merchant'].get('emoji'): memo += ' %s' % data['merchant']['emoji'] if settings.include_tags and data['merchant'] and data['merchant'].get('metadata', {}).get('suggested_tags'): memo += ' %s' % data['merchant']['metadata']['suggested_tags'] # Show the local currency in the notes if this is not in the accounts currency flag = None cleared = None if data['local_currency'] != data['currency']: memo += ' (%s %s)' % (data['local_currency'], (abs(Decimal(data['local_amount'])) / 100)) flag = 'Orange' else: cleared = 'Cleared' # Create the Transaction expected_delta += 1 settings.log.debug('Creating transaction object') transaction = Transaction( check_number=data['id'], entities_account_id=account.id, amount=Decimal(data['amount']) / 100, date=parse(data['created']), entities_payee_id=entities_payee_id, imported_date=datetime.now().date(), imported_payee=payee_name, memo=memo, flag=flag, cleared=cleared ) if subcategory_id is not None: transaction.entities_subcategory_id = subcategory_id settings.log.debug('Duplicate detection') if ynab_client.containsDuplicate(transaction): settings.log.debug('skipping due to duplicate transaction') return {'error': 'Tried to add a duplicate transaction.'}, 200 else: settings.log.debug('appending and pushing transaction to YNAB. Delta: %s', expected_delta) ynab_client.client.budget.be_transactions.append(transaction) ynab_client.client.push(expected_delta) return {'message': 'Transaction created in YNAB successfully.'}, 201
def create_transaction_from_starling(data, settings=settings_module, ynab_client = ynab_client_module): settings.log.debug('received data %s'%data) expected_delta = 0 if not data.get('content') or not data['content'].get('type'): return {'error': 'No webhook content type provided'}, 400 if not data.get('content') or not data['content'].get('type') or not data['content']['type'] in ['TRANSACTION_CARD', 'TRANSACTION_FASTER_PAYMENT_IN', 'TRANSACTION_FASTER_PAYMENT_OUT', 'TRANSACTION_DIRECT_DEBIT']: return {'error': 'Unsupported webhook type: %s' % data.get('content')['type']}, 400 # Sync the account so we get the latest payees ynab_client.sync() if data['content']['amount'] == 0: return {'error': 'Transaction amount is 0.'}, 200 # Does this account exist? account = ynab_client.getaccount(settings.starling_ynab_account) if not account: return {'error': 'Account {} was not found'.format(settings.starling_ynab_account)}, 400 payee_name = data['content']['counterParty'] subcategory_id = None flag = None cleared = None memo = '' # If we are creating the payee, then we need to increase the delta if ynab_client.payeeexists(payee_name): settings.log.debug('payee exists, using %s', payee_name) subcategory_id = get_subcategory_from_payee(payee_name) else: settings.log.debug('payee does not exist, will create %s', payee_name) expected_delta += 1 entities_payee_id = ynab_client.getpayee(payee_name).id if data['content']['sourceCurrency'] != 'GBP': memo += ' (%s %s)' % (data['content']['sourceCurrency'], abs(data['content']['sourceAmount'])) flag = 'Orange' else: cleared = 'Cleared' # Create the Transaction expected_delta += 1 settings.log.debug('Creating transaction object') transaction = Transaction( check_number=data['content'].get('transactionUid'), entities_account_id=account.id, amount=data['content']['amount'], date=parse(data['timestamp']), entities_payee_id=entities_payee_id, imported_date=datetime.now().date(), imported_payee=payee_name, flag=flag, cleared=cleared, memo=memo ) if subcategory_id is not None: transaction.entities_subcategory_id = subcategory_id settings.log.debug('Duplicate detection') if ynab_client.containsDuplicate(transaction): settings.log.debug('skipping due to duplicate transaction') return {'error': 'Tried to add a duplicate transaction.'}, 200 else: expected_delta += 1 settings.log.debug('appending and pushing transaction to YNAB. Delta: %s', expected_delta) ynab_client.client.budget.be_transactions.append(transaction) ynab_client.client.push(expected_delta) return {'message': 'Transaction created in YNAB successfully.'}, 201