def mock_fints_transaction(purpose, applicant_name, posting_text): amount = -50.00 date_day = 10 date_month = 11 date_year = 2019 return { 'status': 'D', 'funds_code': 'R', 'amount': Amount(str(amount), 'D', 'EUR'), 'id': 'N010', 'extra_details': '', 'currency': 'EUR', 'date': Date(year=date_year, month=date_month, day=date_day), 'entry_date': Date(year=date_year, month=date_month, day=date_day), 'guessed_entry_date': Date(year=date_year, month=date_month, day=date_day), 'transaction_code': '100', 'posting_text': posting_text, 'prima_nota': '0000', 'purpose': purpose, 'applicant_bin': 'ABCDEFMMXXX', 'applicant_iban': 'DE12345678912345678901', 'applicant_name': applicant_name, 'return_debit_notes': '011', 'deviate_applicant': 'REWE SAGT DANKE. 192841//Stadt/DE' }
def test_raise_error_without_matching_account(self): '''should raise an exception when the account can not be found online''' clientMock = Mock() account1Mock = Mock() account1Mock.accountnumber = "some account" clientMock.get_sepa_accounts.return_value = [account1Mock] retriever = TRetriever(clientMock, "selected account") with self.assertRaises(Exception) as context: retriever.get_hbci_transactions(Date(2017, 2, 2), Date(2017, 3, 3)) self.assertIn("Could not find a matching account", str(context.exception))
def test_calls_returns_correct_transaction(self): '''retrieved should return a transaction with data, amount and details from the hcbi data''' selectedAccount = "selected account" hbciData = Mock() clientMock = Mock() account1Mock = Mock() account1Mock.accountnumber = selectedAccount clientMock.get_sepa_accounts.return_value = [account1Mock] clientMock.get_transactions.return_value = [hbciData] retriever = TRetriever(clientMock, selectedAccount) result = retriever.get_hbci_transactions(Date(2017, 2, 2), Date(2017, 3, 3)) self.assertEqual(result[0], hbciData)
def test_uses_date_format(self): fintsTransaction = { "date": Date(2017, 11, 1), "amount": Amount('44', 'D', 'EUR'), "applicant_name": None, "posting_text": None, "purpose": None } hbciData = Mock() hbciData.data = {**fintsTransaction, "date": Date(2017, 11, 1)} result1 = CsvConverter(",", "%Y/%m/%d").convert(hbciData) hbciData.data = {**fintsTransaction, "date": Date(2017, 11, 1)} result2 = CsvConverter(",", "%Y-%m-%d").convert(hbciData) self.assertIn("2017/11/01", result1) self.assertIn("2017-11-01", result2)
def test_calls_client_with_select_account(self): '''retriever should get the transactions of the client with the selected account, when the client has two accounts''' startDate = Date(2017, 1, 1) endDate = Date(2017, 2, 1) selectedAccount = "selected account" clientMock = Mock() account1Mock = Mock() account1Mock.accountnumber = selectedAccount account2Mock = Mock() account2Mock.accountnumber = "other account" clientMock.get_sepa_accounts.return_value = [ account1Mock, account2Mock ] clientMock.get_transactions.return_value = [] retriever = TRetriever(clientMock, selectedAccount) retriever.get_hbci_transactions(startDate, endDate) clientMock.get_transactions.assert_called_with(account1Mock, startDate, endDate)
def test_convert_with_missing_values(self): fintsTransaction = { "date": Date(2017, 11, 1), "amount": Amount('44', 'D', 'EUR'), "applicant_name": None, "posting_text": None, "purpose": None } hbciData = Mock() hbciData.data = fintsTransaction csv_result = self.csvConverter.convert(hbciData) entries = csv_result.split(",") self.assertEquals(['2017/11/01', '-44', 'EUR', '', '', ''], entries)
def retrieveAndSave(self): client = FinTS3PinTanClient( self.config["fints"]["blz"], # Your bank's BLZ self.config["fints"]["account"], # your account number self.config["fints"]["password"], # e.g. 'https://fints.ing-diba.de/fints/' self.config["fints"]["endpoint"]) retriever = TRetriever(client, self.config["fints"]["selectedAccount"]) converter = CsvConverter(self.config["fints"]["csv_separator"]) csv_output = "\n".join( map( lambda transaction: converter.convert(transaction), retriever.get_hbci_transactions(self.config["fints"]["start"], Date.today()))) with open(self.config["files"]["csv_file"], 'w') as f: f.write(converter.get_headline()) f.write("\n") f.write(csv_output)
def test_convert_to_csv(self): expected_purpose = "purchased book" expected_applicant_name = "book store" expected_posting_text = "posting text" expected_date = Date(2017, 11, 1) expected_amount = Amount('44', 'D', 'EUR') fintsTransaction = { "date": expected_date, "amount": expected_amount, "applicant_name": expected_applicant_name, "posting_text": expected_posting_text, "purpose": expected_purpose } hbciData = Mock() hbciData.data = fintsTransaction csv_result = self.csvConverter.convert(hbciData) entries = csv_result.split(",") self.assertIn(expected_purpose, entries) self.assertIn(expected_applicant_name, entries) self.assertIn(expected_posting_text, entries) self.assertIn("2017/11/01", entries) self.assertIn("-44", entries)
def get_config(self): parser = argparse.ArgumentParser( description='Converting transactions from fints apis to ledger.') parser.add_argument( '--no-csv', dest='convert_to_csv', action='store_const', const=False, default=True, help='exclude conversion from fints to csv (default: not excluded)' ) parser.add_argument( '--no-ledger', dest='convert_to_ledger', action='store_const', const=False, default=True, help='exclude conversion from csv to ledger (default: not excluded)' ) parser.add_argument( '--csv-file', dest='csvfile', action='store', default="transactions.csv", help= 'file to store/load csv transactions to/from (default: transactions.csv)' ) parser.add_argument( '--ledger-file', dest='ledgerfile', action='store', default="journal.ledger", help='file to store ledger entries to (default: ledger.journal)') parser.add_argument( '--files-path', dest='files_path', action='store', default="~/.config/fints2ledger/", help= 'directory to store fints2ledger files (like config.yml) (default: ~/.config/fints2ledger/)' ) parser.add_argument( '--date', dest='start', action='store', default=None, help= 'start date to pull the FinTS entries from (format: 2017/12/31 or 17/12/31, default: last year)' ) parser.add_argument( '--separator', dest='separator', action='store', default=";", help='character used as separator in csv file (default: ;)') parser.add_argument( '--csv_date_format', dest='csv_date_format', action='store', default='%Y/%m/%d', help= 'Date format used in the donwloaded csv (and subsequently the ledger file). hledger supports 3 date formats (https://hledger.org/1.9/journal.html#simple-dates). Format needs to be compatible with pythons strftime(), see https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior (fints.csv_date_format in config.yml) (default: %%Y/%%m/%%d)' ) args = parser.parse_args() command_line_config = { "fints": { "start": utils.date_string_to_mt940_date(args.start) if args.start else Date(Date.today().year - 1, Date.today().month, Date.today().day), "csv_separator": args.separator, "csv_date_format": args.csv_date_format, "convert_to_csv": args.convert_to_csv }, "ledger": { "convert_to_ledger": args.convert_to_ledger }, "files": { "csv_file": os.path.expanduser(args.csvfile), "ledger_file": os.path.expanduser(args.ledgerfile), "files_path": os.path.expanduser(args.files_path) } } self.files_path = command_line_config["files"]["files_path"] self.setup_files() config = self.load_config_file() if not "selectedAccount" in config["fints"]: config["fints"]["selectedAccount"] = config["fints"]["account"] return utils.update_dict(command_line_config, config)
def get_config(self): parser = argparse.ArgumentParser( description='Converting transactions from fints apis to ledger.') parser.add_argument( '--no-csv', dest='convert_to_csv', action='store_const', const=False, default=True, help='exclude conversion from fints to csv (default: not excluded)' ) parser.add_argument( '--no-ledger', dest='convert_to_ledger', action='store_const', const=False, default=True, help='exclude conversion from csv to ledger (default: not excluded)' ) parser.add_argument( '--csv-file', dest='csvfile', action='store', default="transactions.csv", help= 'file to store/load csv transactions to/from (default: transactions.csv)' ) parser.add_argument( '--ledger-file', dest='ledgerfile', action='store', default="journal.ledger", help='file to store ledger entries to (default: ledger.journal)') parser.add_argument( '--date', dest='start', action='store', default=None, help= 'start date to pull the FinTS entires from (fromat: 2017/12/31 or 17/12/31, default: last year)' ) parser.add_argument( '--separator', dest='separator', action='store', default=";", help='character used as separator in csv file (default: ;)') args = parser.parse_args() command_line_config = { "fints": { "start": utils.date_string_to_mt940_date(args.start) if args.start else Date(Date.today().year - 1, Date.today().month, Date.today().day), "csv_separator": args.separator, "convert_to_csv": args.convert_to_csv }, "ledger": { "convert_to_ledger": args.convert_to_ledger }, "files": { "csv_file": args.csvfile, "ledger_file": args.ledgerfile } } self.setup_files() config = self.load_config_file() return utils.update_dict(config, command_line_config)
'currency': 'EUR', 'date': Date(year=date_year, month=date_month, day=date_day), 'entry_date': Date(year=date_year, month=date_month, day=date_day), 'guessed_entry_date': Date(year=date_year, month=date_month, day=date_day), 'transaction_code': '100', 'posting_text': posting_text, 'prima_nota': '0000', 'purpose': purpose, 'applicant_bin': 'ABCDEFMMXXX', 'applicant_iban': 'DE12345678912345678901', 'applicant_name': applicant_name, 'return_debit_notes': '011', 'deviate_applicant': 'REWE SAGT DANKE. 192841//Stadt/DE' } date = Date(year=2019, month=11, day=10) @pytest.fixture def mock_settings_file_path(): return 'settings.sample.json' @pytest.fixture def mock_fints_transaction_regular(): return mock_fints_transaction('2020-01-01T10.00Debitk.1 2020-01', 'REWE Regiemarkt GmbH', 'DIG. KARTE (APPLE PAY)') @pytest.fixture def mock_fints_transaction_cash(): return mock_fints_transaction('2020-01-01T10.00Debitk.1 2020-01', 'SPARKASSE STADT', 'BARGELDAUSZAHLUNG') @pytest.fixture def mock_fints_transaction_paypal():
def date_string_to_mt940_date(date_string): parts = date_string.split("/") return Date(year=parts[0], month=parts[1], day=parts[2])
def test_convert_mt940_date_17(self): '''should correctly convert the string 17/12/31 to a mt940 date by adding 2000 to the year''' result = utils.date_string_to_mt940_date("17/12/31") self.assertEqual(result, Date(year="2017", month="12", day="31"))