diff --git a/ofx_processor/main.py b/ofx_processor/main.py index b11d43b..99630db 100644 --- a/ofx_processor/main.py +++ b/ofx_processor/main.py @@ -9,7 +9,10 @@ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) @click.group(context_settings=CONTEXT_SETTINGS) @click.version_option() def cli(): - pass + """ + Import your data to YNAB with the processors listed below + or manage your config. + """ cli.add_command(ynab.config, name="config") diff --git a/ofx_processor/utils/processor.py b/ofx_processor/utils/processor.py index c54f7f4..c0249ce 100644 --- a/ofx_processor/utils/processor.py +++ b/ofx_processor/utils/processor.py @@ -43,13 +43,13 @@ class Line: class Processor: - transaction_ids = defaultdict(int) line_class = Line account_name = None def __init__(self, filename): self.filename = filename self.iterable = self.parse_file() + self.transaction_ids = defaultdict(int) def parse_file(self): return [] # pragma: nocover diff --git a/ofx_processor/utils/ynab.py b/ofx_processor/utils/ynab.py index 6a53bdb..641595a 100644 --- a/ofx_processor/utils/ynab.py +++ b/ofx_processor/utils/ynab.py @@ -29,18 +29,17 @@ def get_config_file_name(): @click.group() def config(): - pass + """ + Manage configuration with subcommands + """ -@click.command() +@config.command("edit") def edit_config(): config_file = get_config_file_name() click.edit(filename=config_file) -config.add_command(edit_config, "edit") - - def push_transactions(transactions, account): if not transactions: click.secho("No transaction, nothing to do.", fg="yellow") @@ -73,7 +72,7 @@ def push_transactions(transactions, account): created = set() for transaction in data["transactions"]: - matched_id = transaction["matched_transaction_id"] + matched_id = transaction.get("matched_transaction_id") if not matched_id or matched_id not in created: created.add(transaction["id"]) diff --git a/tests/samples/bpvf_expected.json b/tests/samples/bpvf_expected.json index eb09353..01eb781 100644 --- a/tests/samples/bpvf_expected.json +++ b/tests/samples/bpvf_expected.json @@ -1 +1,121 @@ -[{"date": "2020-02-26", "amount": -9660, "payee_name": "PRLV SEPA Company 3", "memo": "123456789 PAYPAL 542UHBON", "import_id": "YNAB:-9660:2020-02-26:1"}, {"date": "2020-02-25", "amount": -2400, "payee_name": "H.I.K 69VILLEURBANNE", "memo": "240220 CB****5555", "import_id": "YNAB:-2400:2020-02-25:1"}, {"date": "2020-02-25", "amount": -39200, "payee_name": "DELIVEROO FR WWW", "memo": "230220 CB****5555 39,20EUR 1 EURO = 1,000000", "import_id": "YNAB:-39200:2020-02-25:1"}, {"date": "2020-02-25", "amount": -9990, "payee_name": "PRLV SEPA Company 1", "memo": "Votre abonnement mobile: 06XXXXX 6498165189060897", "import_id": "YNAB:-9990:2020-02-25:1"}, {"date": "2020-02-24", "amount": -7500, "payee_name": "COMPANY FR LYON 6EME", "memo": "210220 CB****5555 7,50EUR 1 EURO = 1,000000", "import_id": "YNAB:-7500:2020-02-24:1"}, {"date": "2020-02-24", "amount": -34990, "payee_name": "PRLV SEPA Company 2", "memo": "24-02-2020 / 22-03-2020 56418710", "import_id": "YNAB:-34990:2020-02-24:1"}, {"date": "2020-02-24", "amount": -2390, "payee_name": "VIR Person 1", "memo": "481840871 Splitwise", "import_id": "YNAB:-2390:2020-02-24:1"}, {"date": "2020-02-20", "amount": 235000, "payee_name": "VIREMENT Person 2", "memo": "Cadeau", "import_id": "YNAB:235000:2020-02-20:1"}, {"date": "2020-02-20", "amount": 55000, "payee_name": "VIREMENT Company 3", "memo": "48716508719", "import_id": "YNAB:55000:2020-02-20:1"}, {"date": "2020-02-19", "amount": -55000, "payee_name": "BDE INSA LYON 69VILLEURBANNE", "memo": "170220 CB****5555", "import_id": "YNAB:-55000:2020-02-19:1"}, {"date": "2020-02-19", "amount": -900, "payee_name": "GUY AND SONS FR LYON", "memo": "180220 CB****5555 0,90EUR 1 EURO = 1,000000", "import_id": "YNAB:-900:2020-02-19:1"}, {"date": "2020-02-19", "amount": -1400, "payee_name": "GUY AND SONS FR LYON", "memo": "170220 CB****5555 1,40EUR 1 EURO = 1,000000", "import_id": "YNAB:-1400:2020-02-19:1"}, {"date": "2020-02-19", "amount": -473500, "payee_name": "VIR Person 1", "memo": "65187460 Acompte cuisine 2", "import_id": "YNAB:-473500:2020-02-19:1"}, {"date": "2020-02-18", "amount": -96960, "payee_name": "PRLV SEPA Company 4", "memo": "487105874 Amazon.fr 3X QC.(OJBIYN:ZOFEUBZF51871", "import_id": "YNAB:-96960:2020-02-18:1"}, {"date": "2020-02-17", "amount": -232000, "payee_name": "GRAND PARC PUY 85LES EPESSES", "memo": "150220 CB****5555", "import_id": "YNAB:-232000:2020-02-17:1"}, {"date": "2020-02-17", "amount": -1000, "payee_name": "UBER BV NL HELP.UBER.CO", "memo": "140220 CB****5555 1,00EUR 1 EURO = 1,000000", "import_id": "YNAB:-1000:2020-02-17:1"}, {"date": "2020-02-17", "amount": 8600, "payee_name": "VIREMENT Person 5", "memo": "VIREMENT DE PERSON 6", "import_id": "YNAB:8600:2020-02-17:1"}] \ No newline at end of file +[ + { + "date": "2020-02-26", + "amount": -9660, + "payee_name": "PRLV SEPA Company 3", + "memo": "123456789 PAYPAL 542UHBON", + "import_id": "YNAB:-9660:2020-02-26:1" + }, + { + "date": "2020-02-25", + "amount": -2400, + "payee_name": "H.I.K 69VILLEURBANNE", + "memo": "240220 CB****5555", + "import_id": "YNAB:-2400:2020-02-25:1" + }, + { + "date": "2020-02-25", + "amount": -39200, + "payee_name": "DELIVEROO FR WWW", + "memo": "230220 CB****5555 39,20EUR 1 EURO = 1,000000", + "import_id": "YNAB:-39200:2020-02-25:1" + }, + { + "date": "2020-02-25", + "amount": -9990, + "payee_name": "PRLV SEPA Company 1", + "memo": "Votre abonnement mobile: 06XXXXX 6498165189060897", + "import_id": "YNAB:-9990:2020-02-25:1" + }, + { + "date": "2020-02-24", + "amount": -7500, + "payee_name": "COMPANY FR LYON 6EME", + "memo": "210220 CB****5555 7,50EUR 1 EURO = 1,000000", + "import_id": "YNAB:-7500:2020-02-24:1" + }, + { + "date": "2020-02-24", + "amount": -34990, + "payee_name": "PRLV SEPA Company 2", + "memo": "24-02-2020 / 22-03-2020 56418710", + "import_id": "YNAB:-34990:2020-02-24:1" + }, + { + "date": "2020-02-24", + "amount": -2390, + "payee_name": "VIR Person 1", + "memo": "481840871 Splitwise", + "import_id": "YNAB:-2390:2020-02-24:1" + }, + { + "date": "2020-02-20", + "amount": 235000, + "payee_name": "VIREMENT Person 2", + "memo": "Cadeau", + "import_id": "YNAB:235000:2020-02-20:1" + }, + { + "date": "2020-02-20", + "amount": 55000, + "payee_name": "VIREMENT Company 3", + "memo": "48716508719", + "import_id": "YNAB:55000:2020-02-20:1" + }, + { + "date": "2020-02-19", + "amount": -55000, + "payee_name": "BDE INSA LYON 69VILLEURBANNE", + "memo": "170220 CB****5555", + "import_id": "YNAB:-55000:2020-02-19:1" + }, + { + "date": "2020-02-19", + "amount": -900, + "payee_name": "GUY AND SONS FR LYON", + "memo": "180220 CB****5555 0,90EUR 1 EURO = 1,000000", + "import_id": "YNAB:-900:2020-02-19:1" + }, + { + "date": "2020-02-19", + "amount": -1400, + "payee_name": "GUY AND SONS FR LYON", + "memo": "170220 CB****5555 1,40EUR 1 EURO = 1,000000", + "import_id": "YNAB:-1400:2020-02-19:1" + }, + { + "date": "2020-02-19", + "amount": -473500, + "payee_name": "VIR Person 1", + "memo": "65187460 Acompte cuisine 2", + "import_id": "YNAB:-473500:2020-02-19:1" + }, + { + "date": "2020-02-18", + "amount": -96960, + "payee_name": "PRLV SEPA Company 4", + "memo": "487105874 Amazon.fr 3X QC.(OJBIYN:ZOFEUBZF51871", + "import_id": "YNAB:-96960:2020-02-18:1" + }, + { + "date": "2020-02-17", + "amount": -232000, + "payee_name": "GRAND PARC PUY 85LES EPESSES", + "memo": "150220 CB****5555", + "import_id": "YNAB:-232000:2020-02-17:1" + }, + { + "date": "2020-02-17", + "amount": -1000, + "payee_name": "UBER BV NL HELP.UBER.CO", + "memo": "140220 CB****5555 1,00EUR 1 EURO = 1,000000", + "import_id": "YNAB:-1000:2020-02-17:1" + }, + { + "date": "2020-02-17", + "amount": 8600, + "payee_name": "VIREMENT Person 5", + "memo": "VIREMENT DE PERSON 6", + "import_id": "YNAB:8600:2020-02-17:1" + } +] \ No newline at end of file diff --git a/tests/samples/ce_expected.json b/tests/samples/ce_expected.json index 4e76833..28751ab 100644 --- a/tests/samples/ce_expected.json +++ b/tests/samples/ce_expected.json @@ -1 +1,44 @@ -[{"date": "2020-02-25", "amount": -21000, "payee_name": "CB DECATHLON", "memo": "FACT 240220", "import_id": "YNAB:-21000:2020-02-25:1"}, {"date": "2020-02-25", "amount": -7000, "payee_name": "PRLV COMPANY", "memo": "Company Ref Prlvt SEPA 99-1KIBHEF-01 45871984", "import_id": "YNAB:-7000:2020-02-25:1"}, {"date": "2020-02-24", "amount": -48130, "payee_name": "CB 3403 MONOP", "memo": "FACT 210220", "import_id": "YNAB:-48130:2020-02-24:1"}, {"date": "2020-02-24", "amount": -1200, "payee_name": "CB MALATIER", "memo": "FACT 210220", "import_id": "YNAB:-1200:2020-02-24:1"}, {"date": "2020-02-24", "amount": 2390, "payee_name": "VIR SEPA PERSON 1", "memo": "_", "import_id": "YNAB:2390:2020-02-24:1"}, {"date": "2020-02-24", "amount": 14490, "payee_name": "VIR SEPA PERSON 2", "memo": "_", "import_id": "YNAB:14490:2020-02-24:1"}] \ No newline at end of file +[ + { + "date": "2020-02-25", + "amount": -21000, + "payee_name": "CB DECATHLON", + "memo": "FACT 240220", + "import_id": "YNAB:-21000:2020-02-25:1" + }, + { + "date": "2020-02-25", + "amount": -7000, + "payee_name": "PRLV COMPANY", + "memo": "Company Ref Prlvt SEPA 99-1KIBHEF-01 45871984", + "import_id": "YNAB:-7000:2020-02-25:1" + }, + { + "date": "2020-02-24", + "amount": -48130, + "payee_name": "CB 3403 MONOP", + "memo": "FACT 210220", + "import_id": "YNAB:-48130:2020-02-24:1" + }, + { + "date": "2020-02-24", + "amount": -1200, + "payee_name": "CB MALATIER", + "memo": "FACT 210220", + "import_id": "YNAB:-1200:2020-02-24:1" + }, + { + "date": "2020-02-24", + "amount": 2390, + "payee_name": "VIR SEPA PERSON 1", + "memo": "_", + "import_id": "YNAB:2390:2020-02-24:1" + }, + { + "date": "2020-02-24", + "amount": 14490, + "payee_name": "VIR SEPA PERSON 2", + "memo": "_", + "import_id": "YNAB:14490:2020-02-24:1" + } +] \ No newline at end of file diff --git a/tests/samples/config.ini b/tests/samples/config.ini new file mode 100644 index 0000000..69847f3 --- /dev/null +++ b/tests/samples/config.ini @@ -0,0 +1,12 @@ +[DEFAULT] +token = +budget = + +[bpvf] +account = + +[revolut] +account = + +[ce] +account = diff --git a/tests/samples/revolut_expected.json b/tests/samples/revolut_expected.json index adc661d..c5e6709 100644 --- a/tests/samples/revolut_expected.json +++ b/tests/samples/revolut_expected.json @@ -1 +1,65 @@ -[{"date": "2020-01-29", "amount": -53630, "payee_name": "To Person 1", "memo": "Transfers", "import_id": "YNAB:-53630:2020-01-29:1"}, {"date": "2020-01-29", "amount": -900, "payee_name": "To Person 2", "memo": "Transfers", "import_id": "YNAB:-900:2020-01-29:1"}, {"date": "2020-01-29", "amount": 53630, "payee_name": "Refund from Company 2", "memo": "Shopping", "import_id": "YNAB:53630:2020-01-29:1"}, {"date": "2020-01-24", "amount": -8500, "payee_name": "To Person 3", "memo": "Transfers", "import_id": "YNAB:-8500:2020-01-24:1"}, {"date": "2020-01-16", "amount": -1400, "payee_name": "To Person 4", "memo": "Transfers", "import_id": "YNAB:-1400:2020-01-16:1"}, {"date": "2020-01-10", "amount": -2009, "payee_name": "To Person 5", "memo": "Transfers", "import_id": "YNAB:-2009:2020-01-10:1"}, {"date": "2020-01-10", "amount": -1210, "payee_name": "To Person 6", "memo": "Transfers", "import_id": "YNAB:-1210:2020-01-10:1"}, {"date": "2020-01-05", "amount": -123680, "payee_name": "Company 1", "memo": "Shopping - FX-rate \u20ac1\u2008=\u2008US$1,1158", "import_id": "YNAB:-123680:2020-01-05:1"}, {"date": "2020-01-04", "amount": 100000, "payee_name": "Top-up via Apple Pay", "memo": "General", "import_id": "YNAB:100000:2020-01-04:1"}] \ No newline at end of file +[ + { + "date": "2020-01-29", + "amount": -53630, + "payee_name": "To Person 1", + "memo": "Transfers", + "import_id": "YNAB:-53630:2020-01-29:1" + }, + { + "date": "2020-01-29", + "amount": -900, + "payee_name": "To Person 2", + "memo": "Transfers", + "import_id": "YNAB:-900:2020-01-29:1" + }, + { + "date": "2020-01-29", + "amount": 53630, + "payee_name": "Refund from Company 2", + "memo": "Shopping", + "import_id": "YNAB:53630:2020-01-29:1" + }, + { + "date": "2020-01-24", + "amount": -8500, + "payee_name": "To Person 3", + "memo": "Transfers", + "import_id": "YNAB:-8500:2020-01-24:1" + }, + { + "date": "2020-01-16", + "amount": -1400, + "payee_name": "To Person 4", + "memo": "Transfers", + "import_id": "YNAB:-1400:2020-01-16:1" + }, + { + "date": "2020-01-10", + "amount": -2009, + "payee_name": "To Person 5", + "memo": "Transfers", + "import_id": "YNAB:-2009:2020-01-10:1" + }, + { + "date": "2020-01-10", + "amount": -1210, + "payee_name": "To Person 6", + "memo": "Transfers", + "import_id": "YNAB:-1210:2020-01-10:1" + }, + { + "date": "2020-01-05", + "amount": -123680, + "payee_name": "Company 1", + "memo": "Shopping - FX-rate \u20ac1\u2008=\u2008US$1,1158", + "import_id": "YNAB:-123680:2020-01-05:1" + }, + { + "date": "2020-01-04", + "amount": 100000, + "payee_name": "Top-up via Apple Pay", + "memo": "General", + "import_id": "YNAB:100000:2020-01-04:1" + } +] \ No newline at end of file diff --git a/tests/samples/transactions.json b/tests/samples/transactions.json new file mode 100644 index 0000000..dab48a0 --- /dev/null +++ b/tests/samples/transactions.json @@ -0,0 +1,76 @@ +{ + "transactions": [ + { + "date": "2020-01-29", + "amount": -53630, + "payee_name": "To Person 1", + "memo": "Transfers", + "import_id": "YNAB:-53630:2020-01-29:1", + "account_id": "" + }, + { + "date": "2020-01-29", + "amount": -900, + "payee_name": "To Person 2", + "memo": "Transfers", + "import_id": "YNAB:-900:2020-01-29:1", + "account_id": "" + }, + { + "date": "2020-01-29", + "amount": 53630, + "payee_name": "Refund from Company 2", + "memo": "Shopping", + "import_id": "YNAB:53630:2020-01-29:1", + "account_id": "" + }, + { + "date": "2020-01-24", + "amount": -8500, + "payee_name": "To Person 3", + "memo": "Transfers", + "import_id": "YNAB:-8500:2020-01-24:1", + "account_id": "" + }, + { + "date": "2020-01-16", + "amount": -1400, + "payee_name": "To Person 4", + "memo": "Transfers", + "import_id": "YNAB:-1400:2020-01-16:1", + "account_id": "" + }, + { + "date": "2020-01-10", + "amount": -2009, + "payee_name": "To Person 5", + "memo": "Transfers", + "import_id": "YNAB:-2009:2020-01-10:1", + "account_id": "" + }, + { + "date": "2020-01-10", + "amount": -1210, + "payee_name": "To Person 6", + "memo": "Transfers", + "import_id": "YNAB:-1210:2020-01-10:1", + "account_id": "" + }, + { + "date": "2020-01-05", + "amount": -123680, + "payee_name": "Company 1", + "memo": "Shopping - FX-rate €1 = US$1,1158", + "import_id": "YNAB:-123680:2020-01-05:1", + "account_id": "" + }, + { + "date": "2020-01-04", + "amount": 100000, + "payee_name": "Top-up via Apple Pay", + "memo": "General", + "import_id": "YNAB:100000:2020-01-04:1", + "account_id": "" + } + ] +} \ No newline at end of file diff --git a/tests/test_end_to_end.py b/tests/test_end_to_end.py new file mode 100644 index 0000000..eb27189 --- /dev/null +++ b/tests/test_end_to_end.py @@ -0,0 +1,184 @@ +import unittest +from unittest import mock +from unittest.mock import call + +from click.testing import CliRunner + +from ofx_processor.processors.bpvf import BpvfProcessor +from ofx_processor.processors.ce import CeProcessor +from ofx_processor.processors.revolut import RevolutProcessor +from ofx_processor.utils import utils +from ofx_processor.utils import ynab +from ofx_processor.utils.ynab import config + + +class UtilsTestCase(unittest.TestCase): + """ + This class needs to run before any other that imports + ofx_processor.main.cli because it tests import time stuff. + """ + + @staticmethod + def test_discover_processors(): + ce_main = CeProcessor.main + bpvf_main = BpvfProcessor.main + revolut_main = RevolutProcessor.main + runner = CliRunner() + with mock.patch("click.core.Group.add_command") as add_command: + from ofx_processor.main import cli + + runner.invoke(cli, ["--help"]) + calls = [ + call(ce_main), + call(bpvf_main), + call(revolut_main), + call(config, name="config"), + ] + add_command.assert_has_calls(calls, any_order=True) + + +class ConfigEditTestCase(unittest.TestCase): + @mock.patch("click.edit") + def test_config_edit(self, edit): + config_dir = "tests/samples" + ynab.DEFAULT_CONFIG_DIR = config_dir + expected_filename = f"{config_dir}/config.ini" + runner = CliRunner() + from ofx_processor.main import cli + + # This is run at import time and the cli module is already imported before this test + # so we need to re-run the add_command to make it available. + cli.add_command(ynab.config, name="config") + + runner.invoke(cli, ["config", "edit"]) + edit.assert_called_once_with(filename=expected_filename) + + +class DataTestCase(unittest.TestCase): + @mock.patch("requests.post") + def test_revolut_sends_data_only_created(self, post): + ynab.DEFAULT_CONFIG_DIR = "tests/samples" + post.return_value.json.return_value = { + "data": { + "transactions": [ + { + "id": "ynab_existing:1", + "matched_transaction_id": "imported_matched:2", + }, + { + "id": "imported_matched:2", + "matched_transaction_id": "ynab_existing:1", + }, + { + "id": "imported_matched:3", + "matched_transaction_id": "ynab_existing:4", + }, + { + "id": "ynab_existing:4", + "matched_transaction_id": "imported_matched:3", + }, + {"id": "created:5", "matched_transaction_id": None}, + {"id": "created:6", "matched_transaction_id": None}, + {"id": "created:7", "matched_transaction_id": None}, + {"id": "created:8", "matched_transaction_id": None}, + {"id": "created:9", "matched_transaction_id": None}, + {"id": "created:10", "matched_transaction_id": None}, + {"id": "created:11", "matched_transaction_id": None}, + ], + "duplicate_import_ids": [], + } + } + from ofx_processor.main import cli + + # This is run at import time and the cli module is already imported before this test + # so we need to re-run the add_command to make it available. + utils.discover_processors(cli) + + runner = CliRunner() + result = runner.invoke(cli, ["revolut", "tests/samples/revolut.csv"]) + + self.assertEqual(result.exit_code, 0) + self.assertIn("Processed 9 transactions total.", result.output) + self.assertIn("9 transactions created in YNAB.", result.output) + self.assertNotIn("transactions ignored (duplicates).", result.output) + + @mock.patch("requests.post") + def test_revolut_sends_data_some_created_some_duplicates(self, post): + ynab.DEFAULT_CONFIG_DIR = "tests/samples" + post.return_value.json.return_value = { + "data": { + "transactions": [ + { + "id": "ynab_existing:1", + "matched_transaction_id": "imported_matched:2", + }, + { + "id": "imported_matched:2", + "matched_transaction_id": "ynab_existing:1", + }, + { + "id": "imported_matched:3", + "matched_transaction_id": "ynab_existing:4", + }, + { + "id": "ynab_existing:4", + "matched_transaction_id": "imported_matched:3", + }, + {"id": "created:5", "matched_transaction_id": None}, + ], + "duplicate_import_ids": [ + "duplicate:6", + "duplicate:7", + "duplicate:8", + "duplicate:9", + "duplicate:10", + "duplicate:11", + ], + } + } + from ofx_processor.main import cli + + # This is run at import time and the cli module is already imported before this test + # so we need to re-run the add_command to make it available. + utils.discover_processors(cli) + + runner = CliRunner() + result = runner.invoke(cli, ["revolut", "tests/samples/revolut.csv"]) + + self.assertEqual(result.exit_code, 0) + self.assertIn("Processed 9 transactions total.", result.output) + self.assertIn("3 transactions created in YNAB.", result.output) + self.assertIn("6 transactions ignored (duplicates).", result.output) + + @mock.patch("requests.post") + def test_revolut_sends_data_only_duplicates(self, post): + ynab.DEFAULT_CONFIG_DIR = "tests/samples" + post.return_value.json.return_value = { + "data": { + "transactions": [], + "duplicate_import_ids": [ + "duplicate:1", + "duplicate:2", + "duplicate:3", + "duplicate:4", + "duplicate:5", + "duplicate:6", + "duplicate:7", + "duplicate:8", + "duplicate:9", + ], + } + } + from ofx_processor.main import cli + + # This is run at import time and the cli module is already imported before this test + # so we need to re-run the add_command to make it available. + utils.discover_processors(cli) + + runner = CliRunner() + result = runner.invoke(cli, ["revolut", "tests/samples/revolut.csv"]) + + self.assertEqual(result.exit_code, 0) + self.assertIn("Processed 9 transactions total.", result.output) + self.assertNotIn("transactions created in YNAB.", result.output) + self.assertIn("9 transactions ignored (duplicates).", result.output) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index ceb9a37..0000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -from unittest import mock -from unittest.mock import call - -from click.testing import CliRunner - -from ofx_processor.processors.bpvf import BpvfProcessor -from ofx_processor.processors.ce import CeProcessor -from ofx_processor.processors.revolut import RevolutProcessor -from ofx_processor.utils.ynab import config - - -class UtilsTestCase(unittest.TestCase): - @staticmethod - def test_discover_processors(): - ce_main = CeProcessor.main - bpvf_main = BpvfProcessor.main - revolut_main = RevolutProcessor.main - runner = CliRunner() - with mock.patch("click.core.Group.add_command") as add_command: - from ofx_processor.main import cli - - runner.invoke(cli, ["--help"]) - calls = [ - call(ce_main), - call(bpvf_main), - call(revolut_main), - call(config, name="config"), - ] - add_command.assert_has_calls(calls, any_order=True) - - -if __name__ == "__main__": - unittest.main() # pragma: nocover diff --git a/tests/test_ynab_integration.py b/tests/test_ynab_integration.py new file mode 100644 index 0000000..f2b69d1 --- /dev/null +++ b/tests/test_ynab_integration.py @@ -0,0 +1,34 @@ +import json +import unittest +from unittest import mock + +from ofx_processor.utils import ynab + + +class YNABIntegrationTestCase(unittest.TestCase): + @mock.patch("requests.post") + def test_data_sent_to_ynab(self, post): + ynab.DEFAULT_CONFIG_DIR = "tests/samples" + + with open("tests/samples/revolut_expected.json", encoding="utf-8") as f: + transactions = json.load(f) + with open("tests/samples/transactions.json", encoding="utf-8") as f: + expected_data = json.load(f) + + expected_headers = {"Authorization": f"Bearer "} + expected_url = f"{ynab.BASE_URL}/budgets//transactions" + + ynab.push_transactions(transactions, "revolut") + + post.assert_called_once_with( + expected_url, json=expected_data, headers=expected_headers + ) + + @mock.patch("requests.post") + def test_no_data_to_send(self, post): + ynab.push_transactions([], "") + post.assert_not_called() + + +if __name__ == "__main__": + unittest.main() # pragma: nocover