From 4c6776f545c1d110348e6f72c691814bdab4c20b Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Fri, 3 Apr 2020 19:34:40 +1100 Subject: [PATCH] Implement historical cost accounting for certain commodities --- README.md | 6 +++++- demo/ledger.journal | 5 +++++ ledger_pyreport/model.py | 11 +++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b05381f..cb49d7a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ ledger-pyreport is a lightweight Flask webapp for generating interactive and pri ## Features -* Correctly values assets/liabilities at market value, and income/expenses at cost (pursuant to [AASB 121](https://www.aasb.gov.au/admin/file/content105/c9/AASB121_08-15_COMPfeb16_01-19.pdf)/[IAS 21](https://www.ifrs.org/issued-standards/list-of-standards/ias-21-the-effects-of-changes-in-foreign-exchange-rates/) para 39) +* Correctly values: + * assets/liabilities at fair market value (cf. [AASB](https://www.aasb.gov.au/admin/file/content105/c9/AASB9_12-14_COMPdec17_01-19.pdf)/[IFRS 9](http://eifrs.ifrs.org/eifrs/bnstandards/en/IFRS9.pdf) ¶4.1.4, [AASB 121](https://www.aasb.gov.au/admin/file/content105/c9/AASB121_08-15_COMPfeb16_01-19.pdf)/[IAS 21](http://eifrs.ifrs.org/eifrs/bnstandards/en/IAS21.pdf) ¶23) or historical cost (cf. [AASB 102](https://www.aasb.gov.au/admin/file/content105/c9/AASB102_07-15_COMPdec16_01-19.pdf)/[IAS 2](http://eifrs.ifrs.org/eifrs/bnstandards/en/IAS2.pdf) ¶9), as applicable + * income/expenses at historical cost (cf. [AASB 121](https://www.aasb.gov.au/admin/file/content105/c9/AASB121_08-15_COMPfeb16_01-19.pdf)/[IAS 21](http://eifrs.ifrs.org/eifrs/bnstandards/en/IAS21.pdf) ¶21) * Correctly computes unrealised gains ([even when Ledger does not](https://yingtongli.me/blog/2020/03/31/ledger-gains.html)) * Accounts for both profit and loss, and other comprehensive income * Simulates annual closing of books, with presentation of income/expenses on the balance sheet as retained earnings and current year earnings @@ -48,3 +50,5 @@ ledger-pyreport expects each of assets, liabilities, equity, income and expenses Additionally, ledger-pyreport expects the next level of assets and liabilities to be categories of asset and liability (e.g. *Assets:Current*, *Liabilities:Non-current*). These, too, should contain a zero balance. Ledger-pyreport by default observes the convention that positive amounts in Ledger represent debits, and negative amounts in Ledger represent credits. + +A commodity which has *any* price data in Ledger (including those specified through `@` or `@@`, or explicitly through `P`) will be regarded as a commodity measured at fair market value, and automatically revalued accordingly. A commodity which has *no* price data in Ledger (i.e. lot prices through `{…}` or `{{…}}` only) will be regarded as a commodity measured at historical cost, and will not be subsequently revalued. diff --git a/demo/ledger.journal b/demo/ledger.journal index 9bc470a..61e52c8 100644 --- a/demo/ledger.journal +++ b/demo/ledger.journal @@ -1,6 +1,7 @@ 2019-06-30 Conversion balances Assets:Current:Cash at Bank $1000.00 Assets:Current:Cash on Hand $50.00 + Assets:Current:Inventory 100 Widgets {$5.00} Assets:Non-current:Plant $5000.00 Equity:Retained Earnings @@ -12,6 +13,10 @@ Assets:Current:International Account 100.00 EUR @ $1.10 Assets:Current:Cash at Bank +2019-07-03 Inventory purchases + Assets:Current:Inventory 50 Widgets {$7.00} + Assets:Current:Cash at Bank + 2019-08-01 Interest on personal loan Expenses:Interest $100.00 Liabilities:Non-current:Personal Loan diff --git a/ledger_pyreport/model.py b/ledger_pyreport/model.py index bb56b03..adf31e9 100644 --- a/ledger_pyreport/model.py +++ b/ledger_pyreport/model.py @@ -268,10 +268,17 @@ class Balance: def exchange(self, currency, is_cost, date=None, ledger=None): result = Amount(0, currency) for amount in self.amounts: - if is_cost or amount.currency.name == currency.name and amount.currency.is_prefix == amount.currency.is_prefix: + if is_cost or (amount.currency.name == currency.name and amount.currency.is_prefix == amount.currency.is_prefix): result += amount.exchange(currency, is_cost) else: - result += amount.exchange(currency, is_cost, ledger.get_price(amount.currency, currency, date)) + if any(p[1] == amount.currency.name for p in ledger.prices): + # This currency has price information + # Measured at fair value + result += amount.exchange(currency, is_cost, ledger.get_price(amount.currency, currency, date)) + else: + # This currency has no price information + # Measured at historical cost + result += amount.exchange(currency, True) return result def __neg__(self):