From 3fa8f8a829e6d3b8aac8c5e1c3a8f15ab11582d8 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sat, 4 Apr 2020 04:28:43 +1100 Subject: [PATCH] Centralise commodity tracking logic Per Ledger behaviour, commodities considered equivalent if same name regardless of whether prefix or suffix Commodity display drawn from Ledger data, no longer explicitly specified in config --- config.example.yml | 2 +- demo/config.yml | 2 +- ledger_pyreport/__init__.py | 22 +++++++++------------- ledger_pyreport/ledger.py | 6 +++++- ledger_pyreport/model.py | 17 ++++++++++++----- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/config.example.yml b/config.example.yml index 3c44fc2..2c92c9b 100644 --- a/config.example.yml +++ b/config.example.yml @@ -1,7 +1,7 @@ # Set up how we will call Ledger ledger_file: /path/to/ledger.journal ledger_args: ['--pedantic', '--recursive-aliases'] -report_commodity: ['$', True] # True if prefix, False if suffix +report_commodity: '$' # Tell ledger-pyreport about the top-level account categories assets_account: Assets diff --git a/demo/config.yml b/demo/config.yml index 98e5a26..16eae18 100644 --- a/demo/config.yml +++ b/demo/config.yml @@ -1,7 +1,7 @@ # Set up how we will call Ledger ledger_file: demo/ledger.journal ledger_args: [] -report_commodity: ['$', True] # True if prefix, False if suffix +report_commodity: '$' # Tell ledger-pyreport about the top-level account categories assets_account: Assets diff --git a/ledger_pyreport/__init__.py b/ledger_pyreport/__init__.py index bc43202..b649fb5 100644 --- a/ledger_pyreport/__init__.py +++ b/ledger_pyreport/__init__.py @@ -40,11 +40,10 @@ def trial(): compare = int(flask.request.args['compare']) cash = flask.request.args.get('cash', False) - report_commodity = Commodity(*config['report_commodity']) - if compare == 0: # Get trial balance l = ledger.raw_transactions_at_date(date) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) trial_balance = accounting.trial_balance(l, date, pstart, report_commodity) @@ -67,6 +66,7 @@ def trial(): pstarts = [pstart.replace(year=pstart.year - i) for i in range(0, compare + 1)] l = ledger.raw_transactions_at_date(date) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) trial_balances = [accounting.trial_balance(l.clone(), d, p, report_commodity) for d, p in zip(dates, pstarts)] @@ -89,8 +89,8 @@ def balance(): dates = [date.replace(year=date.year - i) for i in range(0, compare + 1)] pstarts = [pstart.replace(year=pstart.year - i) for i in range(0, compare + 1)] - report_commodity = Commodity(*config['report_commodity']) l = ledger.raw_transactions_at_date(date) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) balance_sheets = [accounting.balance_sheet(accounting.trial_balance(l.clone(), d, p, report_commodity)) for d, p in zip(dates, pstarts)] @@ -122,8 +122,8 @@ def pandl(): dates_beg = [date_beg.replace(year=date_beg.year - i) for i in range(0, compare + 1)] dates_end = [date_end.replace(year=date_end.year - i) for i in range(0, compare + 1)] - report_commodity = Commodity(*config['report_commodity']) l = ledger.raw_transactions_at_date(date_end) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) pandls = [accounting.trial_balance(l.clone(), de, db, report_commodity) for de, db in zip(dates_end, dates_beg)] @@ -146,8 +146,8 @@ def cashflow(): dates_beg = [date_beg.replace(year=date_beg.year - i) for i in range(0, compare + 1)] dates_end = [date_end.replace(year=date_end.year - i) for i in range(0, compare + 1)] - report_commodity = Commodity(*config['report_commodity']) l = ledger.raw_transactions_at_date(date_end) + report_commodity = l.get_commodity(config['report_commodity']) cash_accounts = [a for a in l.accounts.values() if a.is_cash] @@ -193,10 +193,9 @@ def transactions(): cash = flask.request.args.get('cash', False) commodity = flask.request.args.get('commodity', False) - report_commodity = Commodity(*config['report_commodity']) - # General ledger l = ledger.raw_transactions_at_date(date_end) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) @@ -240,10 +239,9 @@ def transaction(): cash = flask.request.args.get('cash', False) commodity = flask.request.args.get('commodity', False) - report_commodity = Commodity(*config['report_commodity']) - # General ledger l = ledger.raw_transactions_at_date(None) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) @@ -326,9 +324,8 @@ def debug_noncash_transactions(): pstart = datetime.strptime(flask.request.args['pstart'], '%Y-%m-%d') account = flask.request.args.get('account') - report_commodity = Commodity(*config['report_commodity']) - l = ledger.raw_transactions_at_date(date) + report_commodity = l.get_commodity(config['report_commodity']) account = l.get_account(account) transactions = [t for t in l.transactions if any(p.account == account for p in t.postings)] @@ -343,9 +340,8 @@ def debug_imbalances(): pstart = datetime.strptime(flask.request.args['pstart'], '%Y-%m-%d') cash = flask.request.args.get('cash', False) - report_commodity = Commodity(*config['report_commodity']) - l = ledger.raw_transactions_at_date(date) + report_commodity = l.get_commodity(config['report_commodity']) if cash: l = accounting.ledger_to_cash(l, report_commodity) diff --git a/ledger_pyreport/ledger.py b/ledger_pyreport/ledger.py index 2655df8..d5a9938 100644 --- a/ledger_pyreport/ledger.py +++ b/ledger_pyreport/ledger.py @@ -104,7 +104,11 @@ def raw_transactions_at_date(date): if ';' in comment: comment = comment[comment.index(';')+1:].strip() - posting = Posting(transaction, ledger.get_account(account_str), parse_amount(amount_str), comment=comment) + amount = parse_amount(amount_str) + posting = Posting(transaction, ledger.get_account(account_str), amount, comment=comment) transaction.postings.append(posting) + + if amount.commodity.name not in ledger.commodities: + ledger.commodities[amount.commodity.name] = amount.commodity.strip_price() return ledger diff --git a/ledger_pyreport/model.py b/ledger_pyreport/model.py index baa6edf..e936ffc 100644 --- a/ledger_pyreport/model.py +++ b/ledger_pyreport/model.py @@ -27,6 +27,7 @@ class Ledger: self.accounts = {} self.transactions = [] + self.commodities = {} self.prices = [] def clone(self): @@ -51,6 +52,9 @@ class Ledger: return account + def get_commodity(self, name): + return self.commodities[name] + def get_price(self, commodity_from, commodity_to, date): prices = [p for p in self.prices if p[1] == commodity_from.name and p[2].commodity == commodity_to and p[0].date() <= date.date()] @@ -89,7 +93,7 @@ class Posting: return ''.format(self.account.name, self.amount.tostr(False)) def exchange(self, commodity, date): - if self.amount.commodity.name == commodity.name and self.amount.commodity.is_prefix == commodity.is_prefix: + if self.amount.commodity.name == commodity.name: return Amount(self.amount) return self.amount.exchange(commodity, True) # Cost basis @@ -235,10 +239,10 @@ class Amount: return Amount(other - self.amount, self.commodity) def exchange(self, commodity, is_cost, price=None): - if self.commodity.name == commodity.name and self.commodity.is_prefix == commodity.is_prefix: + if self.commodity.name == commodity.name: return Amount(self) - if is_cost and self.commodity.price and self.commodity.price.commodity.name == commodity.name and self.commodity.price.commodity.is_prefix == commodity.is_prefix: + if is_cost and self.commodity.price and self.commodity.price.commodity.name == commodity.name: return Amount(self.amount * self.commodity.price.amount, commodity) if price: @@ -268,7 +272,7 @@ class Balance: def exchange(self, commodity, is_cost, date=None, ledger=None): result = Amount(0, commodity) for amount in self.amounts: - if is_cost or (amount.commodity.name == commodity.name and amount.commodity.is_prefix == amount.commodity.is_prefix): + if is_cost or amount.commodity.name == commodity.name: result += amount.exchange(commodity, is_cost) else: if any(p[1] == amount.commodity.name for p in ledger.prices): @@ -338,7 +342,10 @@ class Commodity: def __eq__(self, other): if not isinstance(other, Commodity): return False - return self.name == other.name and self.is_prefix == other.is_prefix and self.price == other.price + return self.name == other.name and self.price == other.price + + def strip_price(self): + return Commodity(self.name, self.is_prefix) class TrialBalance: def __init__(self, ledger, date, pstart):