imp:print:beancount: generate operating_currency directives from cost currencies

This commit is contained in:
Simon Michael 2024-11-09 09:08:47 -10:00
parent f5e97e2f92
commit 17332c75f9
4 changed files with 59 additions and 8 deletions

View File

@ -10,6 +10,7 @@ module Hledger.Write.Beancount (
-- postingAsLinesBeancount,
-- showAccountNameBeancount,
accountNameToBeancount,
commodityToBeancount,
-- beancountTopLevelAccounts,
-- * Tests

View File

@ -44,7 +44,8 @@ import Hledger.Cli.Utils
import Hledger.Cli.Anchor (setAccountAnchor)
import qualified Lucid
import qualified System.IO as IO
import Data.Maybe (isJust)
import Data.Maybe (isJust, catMaybes)
import Hledger.Write.Beancount (commodityToBeancount)
printmode = hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Print.txt")
@ -183,11 +184,17 @@ entriesReportAsTextHelper :: (Transaction -> T.Text) -> EntriesReport -> TL.Text
entriesReportAsTextHelper showtxn = TB.toLazyText . foldMap (TB.fromText . showtxn)
-- This transforms transactions in various ways (see Beancount.hs) to make them Beancount-compatible.
-- It also generates an account open directive for each account used (on their earliest transaction dates).
-- It also generates an account open directive for each account used (on their earliest transaction dates),
-- and operating_currency directives based on currencies used in costs.
entriesReportAsBeancount :: EntriesReport -> TL.Text
entriesReportAsBeancount ts =
-- PERF: gathers and converts all account names, then repeats that work when showing each transaction
opendirectives <> "\n" <> entriesReportAsTextHelper showTransactionBeancount ts3
TL.concat [
TL.fromStrict operatingcurrencydirectives
,TL.fromStrict openaccountdirectives
,"\n"
,entriesReportAsTextHelper showTransactionBeancount ts3
]
where
-- Remove any virtual postings.
ts2 = [t{tpostings=filter isReal $ tpostings t} | t <- ts]
@ -198,7 +205,7 @@ entriesReportAsBeancount ts =
ts3 =
[ t{tpostings=filter (not . isredundantconvp) $ tpostings t}
| t <- ts2
-- XXX But how to do it ? conversion-posting tag is on non-redundant postings too.
-- XXX But conversion-posting tag is on non-redundant postings too, so how to do it ?
-- Assume the simple case of no more than one cost + conversion posting group in each transaction.
-- Actually that seems to be required by hledger right now.
, let isredundantconvp p =
@ -206,9 +213,48 @@ entriesReportAsBeancount ts =
&& any (any (isJust.acost) . amounts . pamount) (tpostings t)
]
opendirectives
-- https://fava.pythonanywhere.com/example-beancount-file/help/beancount_syntax
-- https://fava.pythonanywhere.com/example-beancount-file/help/options
-- "conversion-currencies
-- When set, the currency conversion select dropdown in all charts will show the list of currencies specified in this option.
-- By default, Fava lists all operating currencies and those currencies that match ISO 4217 currency codes."
-- http://furius.ca/beancount/doc/syntax
-- http://furius.ca/beancount/doc/options
-- "This option may be supplied multiple times ...
-- A list of currencies that we single out during reporting and create dedicated columns for ...
-- we use this to display these values in table cells without their associated unit strings ...
-- This is used to indicate the main currencies that you work with in real life"
-- We use: all currencies used in costs.
operatingcurrencydirectives
| null basecurrencies = ""
| otherwise = T.unlines (map (todirective . commodityToBeancount) basecurrencies) <> "\n"
where
todirective c = "option \"operating_currency\" \"" <> c <> "\""
basecurrencies = allcostcurrencies
where
allcostcurrencies = nubSort $ map acommodity costamounts
where
costamounts =
map (\c -> case c of
UnitCost a -> a
TotalCost a -> a
) $
catMaybes $
map acost $
concatMap (amounts . pamount) $
concatMap tpostings
ts3
-- http://furius.ca/beancount/doc/syntax
-- "there exists an “Open” directive that is used to provide the start date of each account.
-- That can be located anywhere in the file, it does not have to appear in the file somewhere before you use an account name.
-- You can just start using account names in transactions right away,
-- though all account names that receive postings to them will eventually have to have
-- a corresponding Open directive with a date that precedes all transactions posted to the account in the input file."
openaccountdirectives
| null ts = ""
| otherwise = TL.fromStrict $ T.unlines [
| otherwise = T.unlines [
firstdate <> " open " <> accountNameToBeancount a
| a <- nubSort $ concatMap (map paccount.tpostings) ts3
]

View File

@ -875,8 +875,9 @@ Currently we support at most one cost + conversion postings group per transactio
#### Beancount operating currency
Declaring an operating currency improves Beancount and Fava reports.
You can do this manually by adding a line like this to the beancount journal:
Declaring an operating currency (or several) improves Beancount and Fava reports.
Currently hledger will declare each currency used in cost amounts as an operating currency.
If needed, replace these with your own declaration, like
```beancount
option "operating_currency" "USD"
```

View File

@ -85,6 +85,7 @@ $ hledger -f- print -O beancount
>=
# ** 6. Conversion postings that are redundant with costs are dropped.
# And when there are costs, operating_currency directives are added for the cost currencies.
<
2000-01-01
Assets $1 @@ €1
@ -93,6 +94,8 @@ $ hledger -f- print -O beancount
Assets €-1
$ hledger -f- print -O beancount
option "operating_currency" "EUR"
2000-01-01 open Assets:A
2000-01-01 *