diff --git a/README.md b/README.md index 51613f1..cbf2b6f 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,6 @@ $ beanahead make x -f x ``` include "x.beancount" ``` - So, if you want to include both regular and ad hoc expected transactions then you should have created three new `.beancount` files and added two 'include' lines to top of your main ledger. > :information_source: The -f option provides for defining the filename (`make` will add the `.beancount` extension). If -f is not passed then default names will be used which are as those explicitly passed in the examples. @@ -111,12 +110,15 @@ The [examples/new_empty_files](./examples/new_empty_files) folder includes a sam - [Regular Expected Transactions Ledger](./examples/new_empty_files/rx.beancount) - [Expected Transactions Ledger](./examples/new_empty_files/x.beancount) -## Regular Expected Transactions +NB If you're not using the default account root names (e.g. 'Assets', 'Income', 'Expenses' etc) then you'll also need to use the optional --main argument to provide the path to a ledger from which beanahead can read the customised name options. Example: +``` +$ beanahead make x -f x --main my_ledger +``` +## Regular Expected Transactions Regular expected transactions are defined on the Regular Expected Transaction _Definitions_ file. The `addrx` command can then be used to populate the Regular Expected Transactions _Ledger_ with transactions generated from these definitions. ### Defining regular transactions - A new regular transaction can be defined at any time by adding a single transaction to the definitions file (the 'initial definition'). The date of this transaction will serve as the anchor off which future transactions are evaluated. The following initial definition would generate regular transactions on the 5th of every month, with the first generated transaction dated 2022-10-05. @@ -376,7 +378,8 @@ With a bit of luck and perhaps a tweak or two to your ledger, your `bean-check` ## Worth remembering > :warning: Whenever an expected transactions ledger or the regular expected transaction definition files are updated the entries are resorted and the file is overwritten - anything that is not a directive (e.g. comments) will be lost. -## Developers +## Options +### Print to stderr If you are employing a workflow that directs output through `sys.stdout` then this will merge with Beanahead's own output to this stream. To avoid such conflicts `beanahead` provides for directing its output to `sys.stderr`. This can be set from the command line by preceeding any subcommand with --print_stderr, for example... ``` $ beanahead --print_stderr exp rx x @@ -389,6 +392,15 @@ If using the underlying functions directly in the codebase then the print stream - `set_print_stderr()` - `set_print_stdout()` +### Custom account root names +If you're not using the default account root names (e.g. 'Assets', 'Income', 'Expenses' etc) then beanahead will need to know the values that you are using. + +The subcommands of the cli that require these names get them from a ledger ('addrx' will read them from the main ledger which is a required argument, 'make' will read them from any ledger passed to its optional --main argument). + +If using the underlying functions directly in the codebase then the names can be set either by passing a dictionary to `config.set_account_root_names` or by passing a ledger that contains these options to `utils.set_account_root_names`. + +The currently set names can be inspected via `config.get_account_root_names()` and reset to the default values with`config.reset_account_root_names()`. + ## Alternative packages The beancount community offers a considerable array of add-on packages, many of which are well-rated and maintained. Below I've noted those I know of with functionality that includes some of what `beanahead` offers. Which package you're likely to find most useful will come down to your specific circumstances and requirements - horses for courses. * [beancount-import](https://github.com/jbms/beancount-import) - an importer interface. Functionality provides for adding expected transactions directly to the main ledger and later merging these with imported transactions via a web-based UI. It requires implementing the importer interface and doesn't directly provide for regular expected transactions. But, if that import interface works for you then you'll probably want to be using `beancount-import`. (If you need the regular trasactions functionality provided by `beanahead`, just use `beanahead` to generate the transactions, copy them over to your ledger and let `beancount-import` handle the subsequent reconcilation.) diff --git a/src/beanahead/config.py b/src/beanahead/config.py index 841ab4b..e460d42 100644 --- a/src/beanahead/config.py +++ b/src/beanahead/config.py @@ -5,6 +5,11 @@ _print_stdout = True +def get_print_file(): + """Get stream to print to.""" + return sys.stdout if _print_stdout else sys.stderr + + def set_print_stdout(): """Set output stream for print to stdout.""" global _print_stdout @@ -17,6 +22,85 @@ def set_print_stderr(): _print_stdout = False -def get_print_file(): - """Get stream to print to.""" - return sys.stdout if _print_stdout else sys.stderr +DEFAULT_ACCOUNT_ROOT_NAMES = { + "name_assets": "Assets", + "name_liabilities": "Liabilities", + "name_equity": "Equity", + "name_income": "Income", + "name_expenses": "Expenses", +} + +_account_root_names = DEFAULT_ACCOUNT_ROOT_NAMES.copy() + + +def get_account_root_names() -> dict[str, str]: + """Get account root names.""" + return _account_root_names.copy() + + +def set_account_root_names(names: dict) -> dict[str, str]: + """Set account root names. + + Use this method to set the account root names. + + Default account root names that otherwise prevail are: + { + 'name_assets': 'Assets', + 'name_liabilities': 'Liabilities', + 'name_equity': 'Equity', + 'name_income': 'Income', + 'name_expenses': 'Expenses', + } + + Parameters + ---------- + names + Dictionary with: + keys: str + Any of the account root name options {'name_assets', + 'name_expenses', 'name_income', 'name_liabilities', + 'name_equity'} + + values: str + Corresponding account root name. + + Returns + ------- + account_root_names: dict[str, str] + Newly set account root names. + """ + global _account_root_names + diff = set(names) - set(_account_root_names) + if diff: + raise ValueError( + f"'names' parameter can only contain keys: {set(_account_root_names)}," + f" although received 'names' included keys: {diff}" + ) + _account_root_names |= names + set_names = get_account_root_names() + assert _account_root_names == set_names + return set_names + + +def reset_account_root_names() -> dict[str, str]: + """Set account root names to default values. + + Default account root names are: + { + 'name_assets': 'Assets', + 'name_liabilities': 'Liabilities', + 'name_equity': 'Equity', + 'name_income': 'Income', + 'name_expenses': 'Expenses', + } + + Returns + ------- + account_root_names: dict[str, str] + Newly set account root names. + """ + global _account_root_names + _account_root_names |= DEFAULT_ACCOUNT_ROOT_NAMES + set_names = get_account_root_names() + assert _account_root_names == set_names + return set_names diff --git a/src/beanahead/rx_txns.py b/src/beanahead/rx_txns.py index 583e8ec..90c81bc 100644 --- a/src/beanahead/rx_txns.py +++ b/src/beanahead/rx_txns.py @@ -17,7 +17,7 @@ from beancount.parser import parser from beancount.parser.printer import EntryPrinter -from . import utils, errors +from . import utils, errors, config from .errors import BeanaheadWriteError, BeancountLoaderErrors END_DFLT = utils.TODAY + datetime.timedelta(weeks=13) @@ -209,9 +209,9 @@ def get_definition_group(definition: Transaction) -> GrouperKey: if account == bal_sheet_account: continue account_type = get_account_type(account) - if account_type == "Assets": + if account_type == config.get_account_root_names()["name_assets"]: other_sides.add("Assets") - elif account_type == "Income": + elif account_type == config.get_account_root_names()["name_income"]: other_sides.add("Income") else: other_sides.add("Expenses") diff --git a/src/beanahead/scripts/cli.py b/src/beanahead/scripts/cli.py index 2932c3d..9382eca 100644 --- a/src/beanahead/scripts/cli.py +++ b/src/beanahead/scripts/cli.py @@ -112,8 +112,19 @@ def main(): parser_make.add_argument( *["-f", "--filename"], help=( - "Name of new beanahead file. By default, as `key`.\nShould not" - " include the .beancount extension." + "Name of new beanahead file. By default, as `key`." + "\nShould not include the .beancount extension." + ), + metavar="", + ) + + parser_make.add_argument( + *["-m", "--main"], + help=( + "Path to existing main Ledger file. Only required if\n" + "account root names are not the default values, in\n" + "which case will use root names as defined by\n" + "the options on this ledger.\n" ), metavar="", ) @@ -270,11 +281,18 @@ def main(): # Call pass-through function corresponding with subcommand args = parser.parse_args() - # Set print stream and revert to stdout + # Set print stream if args.print_stderr: config.set_print_stderr() + # Set root account names + if "main" in args and args.main is not None: + utils.set_account_root_names(args.main) + args.func(args) + + # Revert options to default values config.set_print_stdout() + config.reset_account_root_names() if __name__ == "__main__": diff --git a/src/beanahead/utils.py b/src/beanahead/utils.py index 166e5a8..75ede33 100644 --- a/src/beanahead/utils.py +++ b/src/beanahead/utils.py @@ -16,6 +16,7 @@ from beancount.parser import parser, printer from . import config +from .config import get_account_root_names, DEFAULT_ACCOUNT_ROOT_NAMES from .errors import ( BeancountFileExistsError, BeanaheadFileExistsError, @@ -132,6 +133,12 @@ def compose_header_footer(file_key: str) -> tuple[str, str]: plugin, tag, comment = config["plugin"], config["tag"], config["comment"] header = f"""option "title" "{config['title']}"\n""" + + for k, v in get_account_root_names().items(): + if DEFAULT_ACCOUNT_ROOT_NAMES[k] == v: + continue + header += f'option "{k}" "{v}"\n' + if plugin is not None: header += f'plugin "{plugin}"\n' header += f"pushtag #{tag}\n" @@ -305,6 +312,32 @@ def get_options(path: Path) -> dict: return options +def set_account_root_names(filepath: str) -> dict[str, str]: + """Set account root names from options defined on a beancount file. + + Parameters + ---------- + filepath: str + Path to .beancount file containing options defining account root + names, for example: + option "name_assets" "AltAssetsRootName" + + Can be passed as either absolute path or path relative to the cwd. + It is not necessary to include the. beancount extension. + For example, "ledger" would refer to the file 'ledger.beancount' in + the cwd. + + Returns + ------- + account_root_names: dict[str, str] + Newly set account root names. + """ + path = get_verified_path(filepath) + options = get_options(path) + names = {k: options[k] for k in DEFAULT_ACCOUNT_ROOT_NAMES if k in options} + return config.set_account_root_names(names) + + def get_verified_file_key(path: Path) -> str: """Verify path to a beanahead file and return its file key. @@ -553,10 +586,7 @@ def is_assets_account(string: str) -> bool: >>> is_assets_account("Assets:US:BofA:Checking") True """ - return is_account_type("Assets", string) - - -BAL_SHEET_ACCS = ["Assets", "Liabilities"] + return is_account_type(get_account_root_names()["name_assets"], string) def is_balance_sheet_account(string: str) -> bool: @@ -582,7 +612,14 @@ def is_balance_sheet_account(string: str) -> bool: >>> is_balance_sheet_account("Income:US:BayBook:Match401k") False """ - return any(is_account_type(acc_type, string) for acc_type in BAL_SHEET_ACCS) + account_root_names = get_account_root_names() + return any( + is_account_type(acc_type, string) + for acc_type in [ + account_root_names["name_assets"], + account_root_names["name_liabilities"], + ] + ) def get_balance_sheet_accounts(txn: Transaction) -> list[str]: diff --git a/tests/conftest.py b/tests/conftest.py index a9f28a6..7798755 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -244,3 +244,15 @@ def rx_txn_chase(txns_rx) -> abc.Iterator[data.Transaction]: assert txn.payee == "Chase" assert txn.date == datetime.date(2022, 10, 31) yield txn + + +@pytest.fixture +def account_root_names_dflt() -> abc.Iterator[dict[str, str]]: + """Expected default account_root_names.""" + yield { + "name_assets": "Assets", + "name_liabilities": "Liabilities", + "name_equity": "Equity", + "name_income": "Income", + "name_expenses": "Expenses", + } diff --git a/tests/resources/defs/defs_opts.beancount b/tests/resources/defs/defs_opts.beancount new file mode 100644 index 0000000..1823ac5 --- /dev/null +++ b/tests/resources/defs/defs_opts.beancount @@ -0,0 +1,126 @@ +option "title" "Regular Expected Transaction Definitions" +option "name_assets" "Biens" +option "name_income" "Ingresos" +plugin "rx_txn_plugin" +pushtag #rx_txn +;; All accounts referenced by definitions should be defined on the main ledger. +;; Enter definitions after this line... + +* Expenses + +2022-10-05 * "EDISON" "Electricity, monthly fixed tarrif" + freq: "m" + Biens:US:BofA:Checking -65.00 USD + Expenses:Home:Electricity + +2022-10-16 * "Verizon" "Telecoms, monthly variable" #you-can-inc-tags + ; 2022-10-16 is a Sunday. By default, the next generated transaction + ; will be rolled forwards to 2022-10-17 (Monday) although transactions + ; thereafter will be dated the 15 of each month whenever the 15 is a + ; weekday. + ; Also serves to test that definitions update to a non-rolled + ; transaction - updated definition following adding rx txns through to + ; 2023-06-30 should update this definition to have date 2023-07-16, + ; which is a Sunday. + freq: "m" + Biens:US:BofA:Checking -55.00 USD + Expenses:Home:Phone + +2023-04-18 * "Erie" "Home insurance, yearly premium" + freq: "y" ; annual frequency + Biens:US:BofA:Checking -427.60 USD + Expenses:Home:Insurance + + +* Define frequency as a pandas frequency + +2022-10-01 * "Account Fee" "Monthly bank fee" + freq: "BMS" ; date transactions as first business day of each month + Biens:US:BofA:Checking -4.00 USD + Expenses:Financial:Fees + +2022-10-31 * "Slate" "Credit Card payment" + freq: "BME" ; date transactions as last business day of each month + Biens:US:BofA:Checking -250.00 USD + Liabilities:US:Chase:Slate + +2022-10-15 * "Metro" "Tram tickets, Metro Authority" + ; Also serves to test that definitions update to a non-rolled + ; transaction - updated definition following adding rx txns through to + ; 2023-06-30 should update this definition to have date 2023-07-01, + ; which is a Saturday. + freq: "SMS" ; semi-month start, 1st and 15th of every month + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + + +* Prevent rolling forwards a quarterly transfer between accounts + +2022-11-13 * "ETrade Transfer" "Transfering accumulated savings to other account" + ; As roll is defined as FALSE the next transaction will be dated + ; 2022-11-13 even through this is a Sunday. + freq: "3m" + roll: FALSE + Biens:US:BofA:Checking -4000 USD + Biens:US:ETrade:Cash + + +* Including a 'final' transaction date + +2022-10-31 * "Chase" "Chase Hire Purchase" + freq: "BME" + ; No transaction will be created which would be dated (before any + ; rolling) later than 2022-11-30 + final: 2022-11-30 + Liabilities:US:Chase:HirePurchase 322.00 USD + Biens:US:BofA:Checking + + +* Fortnightly income + +2022-10-07 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + + +* Fortnightly investments + +2022-10-07 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @@ 479.94 USD + +2022-10-07 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @@ 720.02 USD + + +* Quarterly income + +2022-12-15 * "Dividend" "Dividends on portfolio" + freq: "3m" + Biens:US:ETrade:Cash 29.59 USD + Ingresos:US:ETrade:GLD:Dividend + + +;; ...enter definitions before this line. +poptag #rx_txn diff --git a/tests/resources/defs/defs_opts_221231.beancount b/tests/resources/defs/defs_opts_221231.beancount new file mode 100644 index 0000000..eef3d8e --- /dev/null +++ b/tests/resources/defs/defs_opts_221231.beancount @@ -0,0 +1,104 @@ +option "title" "Regular Expected Transaction Definitions" +option "name_assets" "Biens" +option "name_income" "Ingresos" +plugin "rx_txn_plugin" +pushtag #rx_txn +;; All accounts referenced by definitions should be defined on the main ledger. +;; Enter definitions after this line... + + +* Transactions between 'Biens:US:BofA:Checking' and other Assets accounts + +2023-02-13 * "ETrade Transfer" "Transfering accumulated savings to other account" + freq: "3m" + roll: FALSE + Biens:US:BofA:Checking -4000 USD + Biens:US:ETrade:Cash + + +* 'Biens:US:BofA:Checking' to Expenses and Liabilities + +2023-01-02 * "Account Fee" "Monthly bank fee" + freq: "BMS" + Biens:US:BofA:Checking -4.00 USD + Expenses:Financial:Fees + +2023-01-05 * "EDISON" "Electricity, monthly fixed tarrif" + freq: "m" + Biens:US:BofA:Checking -65.00 USD + Expenses:Home:Electricity + +2023-04-18 * "Erie" "Home insurance, yearly premium" + freq: "y" + Biens:US:BofA:Checking -427.60 USD + Expenses:Home:Insurance + +2023-01-31 * "Slate" "Credit Card payment" + freq: "BME" + Biens:US:BofA:Checking -250.00 USD + Liabilities:US:Chase:Slate + +2023-01-16 * "Verizon" "Telecoms, monthly variable" #you-can-inc-tags + freq: "m" + Biens:US:BofA:Checking -55.00 USD + Expenses:Home:Phone + + +* 'Biens:US:BofA:Checking' to various account types + +2023-01-13 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + + +* Income to 'Biens:US:ETrade:Cash' + +2023-03-15 * "Dividend" "Dividends on portfolio" + freq: "3m" + Biens:US:ETrade:Cash 29.59 USD + Ingresos:US:ETrade:GLD:Dividend + + +* Transactions between 'Biens:US:Vanguard:Cash' and other Assets accounts + +2023-01-13 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2023-01-13 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + + +* 'Liabilities:US:Chase:Slate' to Expenses and Liabilities + +2023-01-01 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + + + + +;; ...enter definitions before this line. +poptag #rx_txn diff --git a/tests/resources/defs/ledger_opts.beancount b/tests/resources/defs/ledger_opts.beancount new file mode 100644 index 0000000..68334c3 --- /dev/null +++ b/tests/resources/defs/ledger_opts.beancount @@ -0,0 +1,105 @@ +;; -*- mode: org; mode: beancount; -*- +* Options + +option "title" "Example Beancount file" +option "name_assets" "Biens" +option "name_income" "Ingresos" +option "operating_currency" "USD" +include "rx_opts.beancount" + +* Commodities + + +1792-01-01 commodity USD + export: "CASH" + name: "US Dollar" + +1995-09-18 commodity VBMPX + export: "MUTF:VBMPX" + name: "Vanguard Total Bond Market Index Fund Institutional Plus Shares" + price: "USD:google/MUTF:VBMPX" + +2009-05-01 commodity RGAGX + export: "MUTF:RGAGX" + name: "American Funds The Growth Fund of America Class R-6" + price: "USD:google/MUTF:RGAGX" + +* Equity Accounts + +1980-05-12 open Equity:Opening-Balances + +* Banking + +2020-01-01 open Biens:US:BofA + address: "123 America Street, LargeTown, USA" + institution: "Bank of America" + phone: "+1.012.345.6789" +2020-01-01 open Biens:US:BofA:Checking USD + account: "00234-48574897" + +2020-01-01 * "Opening Balance for checking account" + Biens:US:BofA:Checking 3262.01 USD + Equity:Opening-Balances + +* Liabilities + +2020-05-12 open Liabilities:US:Chase:Slate USD +2020-05-12 open Liabilities:US:Chase:HirePurchase USD + +* Taxable Investments + +2020-01-01 open Biens:US:ETrade:Cash USD +2020-01-01 open Ingresos:US:ETrade:GLD:Dividend USD + +* Vanguard Investments + +2020-01-01 open Biens:US:Vanguard:VBMPX VBMPX + number: "882882" +2020-01-01 open Biens:US:Vanguard:RGAGX RGAGX + number: "882882" +2020-01-01 open Biens:US:Vanguard USD + address: "P.O. Box 1110, Valley Forge, PA 19482-1110" + institution: "Vanguard Group" + phone: "+1.800.523.1188" +2020-01-01 open Biens:US:Vanguard:Cash USD + number: "882882" + +* Taxes + +2020-01-01 open Ingresos:US:Federal:PreTax401k IRAUSD +2020-01-01 open Biens:US:Federal:PreTax401k IRAUSD + +* Sources of Income + +2020-01-01 open Ingresos:US:BayBook:Salary USD +2020-01-01 open Ingresos:US:BayBook:GroupTermLife USD +2020-01-01 open Ingresos:US:BayBook:Vacation VACHR +2020-01-01 open Biens:US:BayBook:Vacation VACHR +2020-01-01 open Expenses:Vacation VACHR +2020-01-01 open Expenses:Health:Life:GroupTermLife +2020-01-01 open Expenses:Health:Medical:Insurance +2020-01-01 open Expenses:Health:Dental:Insurance +2020-01-01 open Expenses:Health:Vision:Insurance + +** Tax Year 2020 + +2020-01-01 open Expenses:Taxes:Y2020:US:Federal:PreTax401k IRAUSD +2020-01-01 open Expenses:Taxes:Y2020:US:Medicare USD +2020-01-01 open Expenses:Taxes:Y2020:US:Federal USD +2020-01-01 open Expenses:Taxes:Y2020:US:CityNYC USD +2020-01-01 open Expenses:Taxes:Y2020:US:SDI USD +2020-01-01 open Expenses:Taxes:Y2020:US:State USD +2020-01-01 open Expenses:Taxes:Y2020:US:SocSec USD + +* Expenses + +2020-01-01 open Expenses:Home:Insurance +2020-01-01 open Expenses:Home:Electricity +2020-01-01 open Expenses:Home:Phone +2020-01-01 open Expenses:Financial:Fees +2020-01-01 open Expenses:Transport:Tram +2020-01-01 open Expenses:Food:Restaurant +2020-01-01 open Expenses:Food:Alcohol +2020-01-01 open Expenses:Food:Coffee + +;; PREVIOUS TRANSACTIONS WOULD BE LISTED HERE diff --git a/tests/resources/defs/rx_opts.beancount b/tests/resources/defs/rx_opts.beancount new file mode 100644 index 0000000..2eb335b --- /dev/null +++ b/tests/resources/defs/rx_opts.beancount @@ -0,0 +1,9 @@ +option "title" "Regular Expected Transactions Ledger" +option "name_assets" "Biens" +option "name_income" "Ingresos" +plugin "rx_txn_plugin" +pushtag #rx_txn +;; Transactions should not be manually added to this file. + + +poptag #rx_txn diff --git a/tests/resources/defs/rx_opts_221231.beancount b/tests/resources/defs/rx_opts_221231.beancount new file mode 100644 index 0000000..15e08c4 --- /dev/null +++ b/tests/resources/defs/rx_opts_221231.beancount @@ -0,0 +1,340 @@ +option "title" "Regular Expected Transactions Ledger" +option "name_assets" "Biens" +option "name_income" "Ingresos" +plugin "rx_txn_plugin" +pushtag #rx_txn +;; Transactions should not be manually added to this file. + + +2022-10-03 * "Account Fee" "Monthly bank fee" + freq: "BMS" + Biens:US:BofA:Checking -4.00 USD + Expenses:Financial:Fees + +2022-10-05 * "EDISON" "Electricity, monthly fixed tarrif" + freq: "m" + Biens:US:BofA:Checking -65.00 USD + Expenses:Home:Electricity + +2022-10-07 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-10-07 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-10-07 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-10-17 * "Verizon" "Telecoms, monthly variable" #you-can-inc-tags + freq: "m" + Biens:US:BofA:Checking -55.00 USD + Expenses:Home:Phone + +2022-10-17 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + +2022-10-21 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-10-21 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-10-21 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-10-31 * "Slate" "Credit Card payment" + freq: "BME" + Biens:US:BofA:Checking -250.00 USD + Liabilities:US:Chase:Slate + +2022-10-31 * "Chase" "Chase Hire Purchase" + freq: "BME" + final: 2022-11-30 + Liabilities:US:Chase:HirePurchase 322.00 USD + Biens:US:BofA:Checking + +2022-11-01 * "Account Fee" "Monthly bank fee" + freq: "BMS" + Biens:US:BofA:Checking -4.00 USD + Expenses:Financial:Fees + +2022-11-01 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + +2022-11-04 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-11-04 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-11-04 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-11-07 * "EDISON" "Electricity, monthly fixed tarrif" + freq: "m" + Biens:US:BofA:Checking -65.00 USD + Expenses:Home:Electricity + +2022-11-13 * "ETrade Transfer" "Transfering accumulated savings to other account" + freq: "3m" + roll: FALSE + Biens:US:BofA:Checking -4000 USD + Biens:US:ETrade:Cash + +2022-11-15 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + +2022-11-16 * "Verizon" "Telecoms, monthly variable" #you-can-inc-tags + freq: "m" + Biens:US:BofA:Checking -55.00 USD + Expenses:Home:Phone + +2022-11-18 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-11-18 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-11-18 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-11-30 * "Slate" "Credit Card payment" + freq: "BME" + Biens:US:BofA:Checking -250.00 USD + Liabilities:US:Chase:Slate + +2022-11-30 * "Chase" "Chase Hire Purchase" + freq: "BME" + final: 2022-11-30 + Liabilities:US:Chase:HirePurchase 322.00 USD + Biens:US:BofA:Checking + +2022-12-01 * "Account Fee" "Monthly bank fee" + freq: "BMS" + Biens:US:BofA:Checking -4.00 USD + Expenses:Financial:Fees + +2022-12-01 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + +2022-12-02 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-12-02 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-12-02 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-12-05 * "EDISON" "Electricity, monthly fixed tarrif" + freq: "m" + Biens:US:BofA:Checking -65.00 USD + Expenses:Home:Electricity + +2022-12-15 * "Metro" "Tram tickets, Metro Authority" + freq: "SMS" + test_meta: "You can include meta fields" + Liabilities:US:Chase:Slate -120.00 USD + Expenses:Transport:Tram + +2022-12-15 * "Dividend" "Dividends on portfolio" + freq: "3m" + Biens:US:ETrade:Cash 29.59 USD + Ingresos:US:ETrade:GLD:Dividend + +2022-12-16 * "Verizon" "Telecoms, monthly variable" #you-can-inc-tags + freq: "m" + Biens:US:BofA:Checking -55.00 USD + Expenses:Home:Phone + +2022-12-16 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-12-16 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-12-16 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + +2022-12-30 * "Slate" "Credit Card payment" + freq: "BME" + Biens:US:BofA:Checking -250.00 USD + Liabilities:US:Chase:Slate + +2022-12-30 * "BayBook" "Payroll" + freq: "2w" + Biens:US:BofA:Checking 1350.60 USD + Biens:US:Vanguard:Cash 1200.00 USD + Ingresos:US:BayBook:Salary -4615.38 USD + Ingresos:US:BayBook:GroupTermLife -24.32 USD + Expenses:Health:Life:GroupTermLife 24.32 USD + Expenses:Health:Dental:Insurance 2.90 USD + Expenses:Health:Medical:Insurance 27.38 USD + Expenses:Health:Vision:Insurance 42.30 USD + Expenses:Taxes:Y2020:US:Medicare 106.62 USD + Expenses:Taxes:Y2020:US:Federal 1062.92 USD + Expenses:Taxes:Y2020:US:State 365.08 USD + Expenses:Taxes:Y2020:US:CityNYC 174.92 USD + Expenses:Taxes:Y2020:US:SDI 1.12 USD + Expenses:Taxes:Y2020:US:SocSec 281.54 USD + Biens:US:Federal:PreTax401k -1200.00 IRAUSD + Expenses:Taxes:Y2020:US:Federal:PreTax401k 1200.00 IRAUSD + Biens:US:BayBook:Vacation 5 VACHR + Ingresos:US:BayBook:Vacation -5 VACHR + +2022-12-30 * "VBMPX" "Investing 40% of cash in VBMPX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:VBMPX 50 VBMPX @ 9.5988 USD + +2022-12-30 * "RGAGX" "Investing 60% of cash in RGAGX" + freq: "2w" + Biens:US:Vanguard:Cash + Biens:US:Vanguard:RGAGX 13.3 RGAGX @ 54.13684210526315789473684211 USD + + +poptag #rx_txn diff --git a/tests/resources/make/rx_opts.beancount b/tests/resources/make/rx_opts.beancount new file mode 100644 index 0000000..2eb335b --- /dev/null +++ b/tests/resources/make/rx_opts.beancount @@ -0,0 +1,9 @@ +option "title" "Regular Expected Transactions Ledger" +option "name_assets" "Biens" +option "name_income" "Ingresos" +plugin "rx_txn_plugin" +pushtag #rx_txn +;; Transactions should not be manually added to this file. + + +poptag #rx_txn diff --git a/tests/test_config.py b/tests/test_config.py index dbf8f0e..eb2f7b3 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,6 +2,8 @@ import sys +import pytest + from beanahead import config as m from .conftest import also_get_stdout, also_get_stderr @@ -21,9 +23,19 @@ # invalid-name: names in tests not expected to strictly conform with snake_case. +def test_default_options_values(account_root_names_dflt): + """Verify default options values. + + Also verifies value of constants. + """ + assert m._print_stdout is True + + assert m._account_root_names == account_root_names_dflt + assert m.DEFAULT_ACCOUNT_ROOT_NAMES == account_root_names_dflt + + def test_print_stream(): """Tests output of print stream between stdout and stderr.""" - assert m._print_stdout is True assert m.get_print_file() is sys.stdout def print_something(): @@ -45,3 +57,21 @@ def print_something(): assert prnt == "something\n" _, prnt = also_get_stderr(print_something) assert not prnt + + +def test_account_name_roots(account_root_names_dflt): + """Tests methods for getting and setting account name roots.""" + rtrn_dflt = m.get_account_root_names() + assert rtrn_dflt == account_root_names_dflt + + names = {"name_assets": "Biens", "name_invalid": "Irrelevant"} + with pytest.raises(ValueError, match="'names' parameter can only contain keys:"): + m.set_account_root_names(names) + assert m.get_account_root_names() == account_root_names_dflt # verify all unchnaged + + names = {"name_assets": "Biens", "name_income": "Ingresos"} + set_names = m.set_account_root_names(names) + assert set_names == account_root_names_dflt | names + + reset_names = m.reset_account_root_names() + assert reset_names == account_root_names_dflt == m.get_account_root_names() diff --git a/tests/test_rx_txns.py b/tests/test_rx_txns.py index 732486b..32656b0 100644 --- a/tests/test_rx_txns.py +++ b/tests/test_rx_txns.py @@ -12,7 +12,7 @@ import pytest from beanahead import rx_txns as m -from beanahead import errors +from beanahead import errors, config from beanahead.scripts import cli from . import cmn @@ -53,6 +53,21 @@ def filepath_defs_rx(defs_dir) -> abc.Iterator[Path]: yield defs_dir / "rx.beancount" +@pytest.fixture +def filepath_defs_opts(defs_dir) -> abc.Iterator[Path]: + yield defs_dir / "defs_opts.beancount" + + +@pytest.fixture +def filepath_defs_ledger_opts(defs_dir) -> abc.Iterator[Path]: + yield defs_dir / "ledger_opts.beancount" + + +@pytest.fixture +def filepath_defs_rx_opts(defs_dir) -> abc.Iterator[Path]: + yield defs_dir / "rx_opts.beancount" + + @pytest.fixture def filepath_defs_ledger_with_error(defs_dir) -> abc.Iterator[Path]: yield defs_dir / "ledger_with_error.beancount" @@ -64,6 +79,12 @@ def defs(filepath_defs) -> abc.Iterator[list[data.Transaction]]: yield entries +@pytest.fixture +def defs_opts(filepath_defs_opts) -> abc.Iterator[list[data.Transaction]]: + entries, errors, options = beancount.loader.load_file(filepath_defs_opts) + yield entries + + @pytest.fixture def def_verizon(defs) -> abc.Iterator[data.Transaction]: def_ = defs[6] @@ -137,6 +158,33 @@ def filepaths_defs_copy_0( path.unlink() +@pytest.fixture +def filepaths_defs_opts_copy_0( + filepath_defs_opts, filepath_defs_rx_opts, filepath_defs_ledger_opts, temp_dir +) -> abc.Iterator[dict[str, Path]]: + """Filepaths to files before generating regular transactions. + + Files define non-default names for account root for Assets and Income. + + Copies each of the defs files to temporary folder. + + Yields mapping to temporary paths with keys as: + "defs" - Regular Transactions Definitions File + "rx" - Regular Transactions Ledger + "ledger" - Main ledger which references ledger 'rx'. + """ + d = {} + for k, filepath in zip( + ("defs", "rx", "ledger"), + (filepath_defs_opts, filepath_defs_rx_opts, filepath_defs_ledger_opts), + ): + string = shutil.copy(filepath, temp_dir) + d[k] = Path(string) + yield d + for path in d.values(): + path.unlink() + + # Tests @@ -301,6 +349,23 @@ def defs_221231(self, defs_221231_filepath) -> abc.Iterator[list[data.Transactio defs, _, _ = beancount.loader.load_file(defs_221231_filepath) yield defs + @pytest.fixture + def defs_opts_221231_filepath(self, defs_dir) -> abc.Iterator[Path]: + yield defs_dir / "defs_opts_221231.beancount" + + @pytest.fixture + def defs_opts_221231_content( + self, defs_opts_221231_filepath, encoding + ) -> abc.Iterator[str]: + yield defs_opts_221231_filepath.read_text(encoding) + + @pytest.fixture + def defs_opts_221231( + self, defs_opts_221231_filepath + ) -> abc.Iterator[list[data.Transaction]]: + defs, _, _ = beancount.loader.load_file(defs_opts_221231_filepath) + yield defs + @pytest.fixture def rx_221231_filepath(self, defs_dir) -> abc.Iterator[Path]: yield defs_dir / "rx_221231.beancount" @@ -316,6 +381,23 @@ def rx_txns_221231( txns, _, _ = beancount.loader.load_file(rx_221231_filepath) yield txns + @pytest.fixture + def rx_opts_221231_filepath(self, defs_dir) -> abc.Iterator[Path]: + yield defs_dir / "rx_opts_221231.beancount" + + @pytest.fixture + def rx_opts_221231_content( + self, rx_opts_221231_filepath, encoding + ) -> abc.Iterator[str]: + yield rx_opts_221231_filepath.read_text(encoding) + + @pytest.fixture + def rx_opts_txns_221231( + self, rx_opts_221231_filepath + ) -> abc.Iterator[list[data.Transaction]]: + txns, _, _ = beancount.loader.load_file(rx_opts_221231_filepath) + yield txns + @pytest.fixture def defs_230630_filepath(self, defs_dir) -> abc.Iterator[Path]: yield defs_dir / "defs_230630.beancount" @@ -375,6 +457,12 @@ def test_admin( rx_txns_221231, defs_230630_content, rx_230630_content, + filepaths_defs_opts_copy_0, + defs_opts, + defs_opts_221231, + rx_opts_txns_221231, + defs_opts_221231_content, + rx_opts_221231_content, encoding, ): """Test for initial generation of rx txns. @@ -453,6 +541,53 @@ def test_admin( assert defs_path.read_text(encoding) == defs_230630_content assert rx_path.read_text(encoding) == rx_230630_content + # verify as required when files include non-default account root names + config.set_account_root_names( + {"name_assets": "Biens", "name_income": "Ingresos"} + ) + defs_opts_path = filepaths_defs_opts_copy_0["defs"] + rx_opts_path = filepaths_defs_opts_copy_0["rx"] + ledger_opts_path = filepaths_defs_copy_0["ledger"] + admin_opts = m.Admin(defs_opts_path, rx_opts_path, ledger_opts_path) + + def_payees = { + "Account Fee", + "EDISON", + "BayBook", + "VBMPX", + "RGAGX", + "Metro", + "Verizon", + "Slate", + "Chase", + "ETrade Transfer", + "Dividend", + "Erie", + } + + cmn.assert_txns_equal(admin_opts.rx_defs.values(), defs_opts) + assert set(admin_opts.payees) == def_payees + assert admin_opts.rx_files == [defs_opts_path, rx_opts_path] + assert admin_opts.rx_txns == [] + + _, output = also_get_stdout(admin_opts.add_txns, datetime.date(2022, 12, 31)) + expected_output = ( + "42 transactions have been added to the ledger 'rx_opts'.\n" + "Definitions on 'defs_opts' have been updated to reflect the" + " most recent transactions.\n" + ) + assert output == expected_output + assert defs_opts_path.read_text(encoding) == defs_opts_221231_content + assert rx_opts_path.read_text(encoding) == rx_opts_221231_content + + cmn.assert_txns_equal(admin_opts.rx_defs.values(), defs_opts_221231) + def_payees.remove("Chase") + assert set(admin_opts.payees) == def_payees + assert admin_opts.rx_files == [defs_opts_path, rx_opts_path] + cmn.assert_txns_equal(admin_opts.rx_txns, rx_opts_txns_221231) + + config.reset_account_root_names() + @pytest.mark.usefixtures("cwd_as_temp_dir") def test_cli_addrx( self, @@ -461,6 +596,9 @@ def test_cli_addrx( rx_221231_content, defs_230630_content, rx_230630_content, + filepaths_defs_opts_copy_0, + defs_opts_221231_content, + rx_opts_221231_content, encoding, ): """Test calling `Admin.add_txns` via cli. @@ -491,3 +629,18 @@ def test_cli_addrx( assert output == expected_output assert defs_path.read_text(encoding) == defs_230630_content assert rx_path.read_text(encoding) == rx_230630_content + + # verify as required when files include non-default account root names + defs_opts_path = filepaths_defs_opts_copy_0["defs"] + rx_opts_path = filepaths_defs_opts_copy_0["rx"] + + set_cl_args("addrx defs_opts rx_opts ledger_opts -e 2022-12-31") + _, output = also_get_stdout(cli.main) + expected_output = ( + "42 transactions have been added to the ledger 'rx_opts'.\n" + "Definitions on 'defs_opts' have been updated to reflect the" + " most recent transactions.\n" + ) + assert output == expected_output + assert defs_opts_path.read_text(encoding) == defs_opts_221231_content + assert rx_opts_path.read_text(encoding) == rx_opts_221231_content diff --git a/tests/test_utils.py b/tests/test_utils.py index 7136a51..f071492 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -96,6 +96,11 @@ def filepath_make_rx(make_dir) -> abc.Iterator[Path]: yield make_dir / "rx.beancount" +@pytest.fixture +def filepath_make_rx_opts(make_dir) -> abc.Iterator[Path]: + yield make_dir / "rx_opts.beancount" + + @pytest.fixture def filepath_make_rx_def(make_dir) -> abc.Iterator[Path]: yield make_dir / "rx_def.beancount" @@ -309,7 +314,7 @@ def test_compose_header_footer(): assert f("rx_def") == (expected_rx_def_start, expected_rx_def_end) -def test_create_beanahead_file(files_make, cwd_as_temp_dir): +def test_create_beanahead_file(files_make, cwd_as_temp_dir, filepath_make_rx_opts): f = m.create_beanahead_file make_contents = {k: fileobj.read() for k, fileobj in files_make.items()} @@ -358,9 +363,26 @@ def assertions(expected_path: Path, file_key: str): with pytest.raises(NotADirectoryError, match=f"{dirname}"): f(key, dirpath="./" + dirname) + # verify as expected with non-default account root names + key = "rx" + filename = "rx_opts" + expected_path = cwd_as_temp_dir / f"{filename}.beancount" + assert not expected_path.is_file() + + config.set_account_root_names({"name_assets": "Biens", "name_income": "Ingresos"}) + f(key, filename=filename) + config.reset_account_root_names() + + assert expected_path.is_file() + fileobj = get_fileobj(filepath_make_rx_opts) + expected_contents = fileobj.read() + fileobj.close() + with get_fileobj(expected_path) as file: + assert file.read() == expected_contents + @pytest.mark.usefixtures("clean_test_dir") -def test_cli_make(files_make, cwd_as_temp_dir): +def test_cli_make(files_make, cwd_as_temp_dir, filepath_make_rx_opts): """Test calling `create_beanahead_file` via cli. Test based on `test_create_beanahead_file`. @@ -418,6 +440,23 @@ def assertions(expected_path: Path, file_key: str): set_cl_args(f"make {key} -d {dirpath}") cli.main() + # verify can pass --main to define non-default account root names + key = "rx" + filename = "rx_opts" + expected_path = cwd_as_temp_dir / f"{filename}.beancount" + assert not expected_path.is_file() + # NB ledger used to define options has content as expected contents of file + # being made + set_cl_args(f"make {key} --filename {filename} --main {filepath_make_rx_opts}") + cli.main() + + assert expected_path.is_file() + fileobj = get_fileobj(filepath_make_rx_opts) + expected_contents = fileobj.read() + fileobj.close() + with get_fileobj(expected_path) as file: + assert file.read() == expected_contents + def test_verify_path(filepath_ledger, filepath_no_file, filepath_empty_txt_file): f = m.verify_path @@ -489,6 +528,18 @@ def test_get_options(filepath_make_rx): assert m.get_options(filepath_make_rx)["title"] == expected +def test_set_account_root_names(filepath_make_rx_opts, account_root_names_dflt): + rtrn = m.set_account_root_names(filepath_make_rx_opts) + changes = { + "name_assets": "Biens", + "name_income": "Ingresos", + } + expected = account_root_names_dflt | changes + assert rtrn == expected + + config.reset_account_root_names() + + def test_get_verified_file_key(filepaths_make, filepath_no_file, filepath_ledger): """Also tests `get_verified_ledger_file_key`.""" for f in (m.get_verified_file_key, m.get_verified_ledger_file_key):