diff --git a/hledger/Hledger/Cli/Commands/Print.hs b/hledger/Hledger/Cli/Commands/Print.hs index 3de850bdf..a2e53fe91 100644 --- a/hledger/Hledger/Cli/Commands/Print.hs +++ b/hledger/Hledger/Cli/Commands/Print.hs @@ -44,6 +44,7 @@ import Hledger.Cli.Utils import Hledger.Cli.Anchor (setAccountAnchor) import qualified Lucid import qualified System.IO as IO +import Data.Maybe (isJust) printmode = hledgerCommandMode $(embedFileRelative "Hledger/Cli/Commands/Print.txt") @@ -186,17 +187,33 @@ entriesReportAsTextHelper showtxn = TB.toLazyText . foldMap (TB.fromText . showt 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 allrealts + opendirectives <> "\n" <> entriesReportAsTextHelper showTransactionBeancount ts3 where - allrealts = [t{tpostings=filter isReal $ tpostings t} | t <- ts] + -- Remove any virtual postings. + ts2 = [t{tpostings=filter isReal $ tpostings t} | t <- ts] + + -- Remove any conversion postings that are redundant with costs. + -- It would be easier to remove the costs instead, + -- but those are more useful to Beancount than conversion postings. + 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. + -- 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 = + matchesPosting (Tag (toRegex' "conversion-posting") Nothing) p + && any (any (isJust.acost) . amounts . pamount) (tpostings t) + ] + opendirectives | null ts = "" | otherwise = TL.fromStrict $ T.unlines [ firstdate <> " open " <> accountNameToBeancount a - | a <- nubSort $ concatMap (map paccount.tpostings) allrealts + | a <- nubSort $ concatMap (map paccount.tpostings) ts3 ] where - firstdate = showDate $ minimumDef err $ map tdate allrealts + firstdate = showDate $ minimumDef err $ map tdate ts3 where err = error' "entriesReportAsBeancount: should not happen" entriesReportAsSql :: EntriesReport -> TL.Text diff --git a/hledger/hledger.m4.md b/hledger/hledger.m4.md index 98d0faac9..02ee69636 100644 --- a/hledger/hledger.m4.md +++ b/hledger/hledger.m4.md @@ -830,12 +830,14 @@ using various utilities like `libreoffice --headless` or This is [Beancount's journal format][beancount journal]. You can use this to export your hledger data to [Beancount], perhaps to query it with [Beancount Query Language] or with the [Fava] web app. + hledger will try to adjust your data to suit Beancount. -If you plan to export often, you may want to follow Beancount's conventions in your hledger data, -to ease conversion. Eg use Beancount-friendly account names, currency codes instead of currency symbols, -and avoid virtual postings, redundant cost notation, etc. -Here are more details -(see also "hledger and Beancount" ). +You should be cautious and check the conversion carefully until you are confident it is good. +If you plan to export to Beancount often, you may want to follow its conventions in your hledger data, to make conversion easier. +Eg use Beancount-friendly account names, currency codes instead of currency symbols, costs instead of equity conversion postings, no virtual postings, etc. + +Here are more details. + #### Beancount account names @@ -866,8 +868,9 @@ if you have any, they will not appear in beancount output. #### Beancount costs -Beancount doesn't allow [redundant cost notation](https://hledger.org/hledger.html#combining-costs-and-equity-conversion-postings) -as hledger does. If you have entries like this, you will need to comment out either the costs or the equity postings. +Beancount doesn't allow [redundant costs and conversion postings](https://hledger.org/hledger.html#combining-costs-and-equity-conversion-postings) as hledger does. +If you have entries like this, the conversion postings will be dropped. +Currently we support at most one cost + conversion postings group per transaction. #### Beancount operating currency diff --git a/hledger/test/print/beancount.test b/hledger/test/print/beancount.test index 6c9002cb3..a77f88c93 100644 --- a/hledger/test/print/beancount.test +++ b/hledger/test/print/beancount.test @@ -59,3 +59,63 @@ $ hledger -f- print -O beancount Assets:A 0 USD >= + +# ** 5. Conversion postings that are not redundant are preserved. +# If the accounts are named after currency symbols, they will look strange. +# (A better conversion would be this, but it seems hard to automate: +# Equity:Conversion:EUR-USD:USD, Equity:Conversion:EUR-USD:EUR.) +< +2000-01-01 + Assets $1 + equity:conversion:€-$:$ -$1 + equity:conversion:€-$:€ €1 + Assets €-1 + +$ hledger -f- print -O beancount +2000-01-01 open Assets:A +2000-01-01 open Equity:Conversion:C20ac-C24:C24 +2000-01-01 open Equity:Conversion:C20ac-C24:C20ac + +2000-01-01 * + Assets:A 1 USD + Equity:Conversion:C20ac-C24:C24 -1 USD + Equity:Conversion:C20ac-C24:C20ac 1 EUR + Assets:A -1 EUR + +>= + +# ** 6. Conversion postings that are redundant with costs are dropped. +< +2000-01-01 + Assets $1 @@ €1 + equity:conversion:€-$:$ -$1 + equity:conversion:€-$:€ €1 + Assets €-1 + +$ hledger -f- print -O beancount +2000-01-01 open Assets:A + +2000-01-01 * + Assets:A 1 USD @@ 1 EUR + Assets:A -1 EUR + +>= + +# ** 7. Multiple cost/conversion groups within a transaction are not supported +# (by hledger generally, apparently ?) +< +2000-01-01 + Assets $1 @@ €1 + equity:conversion:€-$:$ -$1 + equity:conversion:€-$:€ €1 + Assets €-1 + ; + Assets A1 @@ B1 + equity:conversion:€-$:$ -A1 + equity:conversion:€-$:€ B1 + Assets B-1 + +$ hledger -f- print -O beancount +>2 /unbalanced/ +>=1 +