fix: handle account type declarations in multiple files correctly [#2202]

Tags and types declared in account directives in sibling files or
included files are now combined more carefully.

In particular, when merging two Journals into one,

- jdeclaredaccounttags and jdeclaredaccounttypes no longer lose information;
  any duplicated/conflicting tag/type values are preserved.

- jaccounttypes now prefers the last type declared in case of
  conflict, not the first.
This commit is contained in:
Simon Michael 2024-06-10 08:20:40 +01:00
parent 7804685b09
commit e89bea8563
5 changed files with 45 additions and 6 deletions

View File

@ -255,12 +255,32 @@ journalConcat j1 j2 =
,jdeclaredpayees = jdeclaredpayees j1 <> jdeclaredpayees j2
,jdeclaredtags = jdeclaredtags j1 <> jdeclaredtags j2
,jdeclaredaccounts = jdeclaredaccounts j1 <> jdeclaredaccounts j2
,jdeclaredaccounttags = jdeclaredaccounttags j1 <> jdeclaredaccounttags j2
,jdeclaredaccounttypes = jdeclaredaccounttypes j1 <> jdeclaredaccounttypes j2
,jaccounttypes = jaccounttypes j1 <> jaccounttypes j2
,jglobalcommoditystyles = jglobalcommoditystyles j1 <> jglobalcommoditystyles j2
,jcommodities = jcommodities j1 <> jcommodities j2
,jinferredcommodities = jinferredcommodities j1 <> jinferredcommodities j2
--
-- The next six fields are Maps, which need be merged carefully for correct semantics,
-- especially the first two, which have list values. These are not all fully tested.
--
-- ,jdeclaredaccounttags :: M.Map AccountName [Tag]
-- jdeclaredaccounttags can have multiple duplicated/conflicting values for an account tag.
,jdeclaredaccounttags = M.unionWith (<>) (jdeclaredaccounttags j1) (jdeclaredaccounttags j2)
--
-- ,jdeclaredaccounttypes :: M.Map AccountType [AccountName]
-- jdeclaredaccounttypes can have multiple duplicated/conflicting values for an account's type.
,jdeclaredaccounttypes = M.unionWith (<>) (jdeclaredaccounttypes j1) (jdeclaredaccounttypes j2)
--
-- ,jaccounttypes :: M.Map AccountName AccountType
-- jaccounttypes always has a single type for a given account. When there are multiple type declarations, it is the last/rightmost.
,jaccounttypes = M.unionWith (const id) (jaccounttypes j1) (jaccounttypes j2)
--
-- ,jglobalcommoditystyles :: M.Map CommoditySymbol AmountStyle
,jglobalcommoditystyles = (<>) (jglobalcommoditystyles j1) (jglobalcommoditystyles j2)
--
-- ,jcommodities :: M.Map CommoditySymbol Commodity
,jcommodities = (<>) (jcommodities j1) (jcommodities j2)
--
-- ,jinferredcommodities :: M.Map CommoditySymbol AmountStyle
,jinferredcommodities = (<>) (jinferredcommodities j1) (jinferredcommodities j2)
--
--
,jpricedirectives = jpricedirectives j1 <> jpricedirectives j2
,jinferredmarketprices = jinferredmarketprices j1 <> jinferredmarketprices j2
,jtxnmodifiers = jtxnmodifiers j1 <> jtxnmodifiers j2

View File

@ -58,3 +58,17 @@ $ hledger print -f personal.journal -f ../journal/a.timeclock -f ../journal/b.ti
$ hledger -f a.j -f b.j reg
2018-01-01 a1 (a) 1 1
2018-01-01 b1 (b) 1 2
# ** 5. Declaring another account with same type in a child file works properly. [#2202]
$ hledger -f types1.j accounts --types
A ; type: C
B ; type: C
# ** 6. With different account types declared for an account in different files, the last wins. [#2202]
$ hledger -f types2.j -f types3.j accounts --types
B ; type: X
# ** 7. With different account types declared for an account in different files, the last wins. [#2202]
$ hledger -f types3.j -f types2.j accounts --types
B ; type: C

View File

@ -0,0 +1,3 @@
account A ; type: Cash
include types2.j

View File

@ -0,0 +1 @@
account B ; type: Cash

View File

@ -0,0 +1 @@
account B ; type: Expense