Skip to content

Commit b84f7fd

Browse files
author
Eric Forgy
authored
Add AccountGroup and cleanup (#6)
* [DO NOT MERGE] WIP * Add Identifier and AccountNode * Split to multiline and add AccountId()
1 parent 0e844ee commit b84f7fd

File tree

1 file changed

+95
-73
lines changed

1 file changed

+95
-73
lines changed

src/Ledgers.jl

Lines changed: 95 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -18,102 +18,96 @@ import Instruments: instrument, symbol, amount, name, currency
1818
export Credit, Debit, Account, Ledger, Entry, AccountId, AccountInfo
1919
export id, balance, credit!, debit!, post!, instrument, symbol, amount, name, currency
2020

21-
struct AccountId{T}
22-
value::T
21+
abstract type Identifier end
22+
struct AccountId <: Identifier
23+
value::UUID
2324
end
25+
AccountId() = AccountId(uuid4())
2426

25-
Base.show(io::IO, id::AccountId) = print(io, id.value)
27+
struct AccountCode
28+
value::String
29+
end
2630

27-
mutable struct Account{P<:Position,I<:AccountId}
28-
id::I
31+
abstract type AccountType end
32+
struct Credit <: AccountType end
33+
struct Debit <: AccountType end
34+
35+
mutable struct Account{P<:Position}
36+
id::AccountId
2937
balance::P
3038
end
31-
Account(balance::Position) = Account(AccountId(uuid4()), balance)
39+
Account(balance::Position) = Account(AccountId(), balance)
3240

33-
# Identity function (to make code more generic)
34-
account(v::Account) = v
41+
abstract type AccountNode end
42+
struct AccountInfo{AT<:AccountType,A<:Account} <: AccountNode
43+
account::A
44+
code::AccountCode
45+
name::String
3546

36-
id(account::Account) = account.id
37-
balance(account::Account) = account.balance
47+
function AccountInfo(::Type{T}, account, code, name) where {T<:AccountType}
48+
return new{T}(account, code, name)
49+
end
50+
end
3851

39-
instrument(::Account{P}) where {P<:Position} = instrument(P)
40-
symbol(::Account{P}) where {P<:Position} = symbol(P)
41-
currency(::Account{P}) where {P<:Position} = currency(P)
52+
struct AccountGroup{AT<:AccountType} <: AccountNode
53+
code::AccountCode
54+
name::String
55+
parent::Union{Nothing,AccountGroup{<:AccountType}}
56+
subaccounts::Vector{AccountInfo}
57+
subgroups::Vector{AccountGroup}
4258

43-
amount(amt::Account) = amount(amt.balance)
59+
function AccountGroup(::Type{T}, account, name, parent=nothing) where {T<:AccountType}
60+
new{T}(account, code, name, parent, Vector{AccountInfo}(), Vector{AccountGroup}())
61+
end
62+
end
4463

45-
debit!(account::Account, amt::Position) = (account.balance += amt)
46-
credit!(account::Account, amt::Position) = (account.balance -= amt)
64+
# Identity function (to make code more generic)
65+
account(acc::Account) = acc
66+
account(info::AccountInfo) = info.account
4767

48-
Base.show(io::IO, account::Account) = print(io, "$(string(id(account))): $(balance(account)).")
68+
account_type(::Union{AccountInfo{AT},AccountGroup{AT}}) where {AT} = AT
69+
code(acc::Union{<:AccountInfo,<:AccountGroup}) = acc.code
70+
name(acc::Union{<:AccountInfo,<:AccountGroup}) = acc.name
4971

50-
struct Entry{D,C}
51-
debit::D
52-
credit::C
53-
end
72+
parent(group::AccountGroup) = group.parent
73+
subaccounts(group::AccountGroup) = group.subaccounts
74+
subgroups(group::AccountGroup) = group.subgroups
5475

55-
Base.show(io::IO, e::Entry{<:Account,<:Account}) =
56-
print(io, "Entry:\n", " Debit: $(e.debit)\n", " Credit: $(e.credit)")
76+
id(acc::Account) = acc.id
77+
id(info::AccountInfo) = id(account(info))
5778

58-
abstract type AccountType end
59-
struct Credit <: AccountType end
60-
struct Debit <: AccountType end
79+
balance(acc::Account) = acc.balance
80+
balance(info::AccountInfo) = balance(account(info))
81+
balance(group::AccountGroup) =
82+
sum(map(info->balance(info), subaccounts(group))) +
83+
sum(map(grp->balance(grp), subgroups(group)))
6184

62-
Base.show(io::IO, ::Type{Debit}) = print(io, "Debit")
63-
Base.show(io::IO, ::Type{Credit}) = print(io, "Credit")
85+
instrument(::Account{P}) where {P<:Position} = instrument(P)
86+
instrument(info::AccountInfo) = instrument(account(info))
6487

65-
# SPJ: this does not maintain the distinction we'd talked about, of keeping
66-
# all debit accounts and all credit accounts in with separate types.
67-
# This will end up doing a lot of processing at run-time, and will be relatively
68-
# rather slow compared to what we had discussed.
88+
symbol(::Account{P}) where {P<:Position} = symbol(P)
89+
symbol(info::AccountInfo) = symbol(account(info))
6990

70-
struct AccountInfo{T<:AccountType}
71-
account::Account
72-
name::String
73-
parent::Union{Nothing,AccountInfo}
74-
subaccounts::Vector{AccountInfo}
91+
currency(::Account{P}) where {P<:Position} = currency(P)
92+
currency(info::AccountInfo) = currency(account(info))
7593

76-
function AccountInfo(::Type{T}, account, name, parent=nothing) where {T<:AccountType}
77-
ag = new{T}(account, name, parent, Vector{AccountInfo}())
78-
(parent === nothing) || push!(parent.subaccounts, ag)
79-
return ag
80-
end
81-
end
94+
amount(acc::Account) = amount(balance(acc))
95+
amount(info::AccountInfo) = amount(balance(account(info)))
8296

83-
account(info::AccountInfo) = info.account
84-
name(info::AccountInfo) = info.name
85-
parent(info::AccountInfo) = info.parent
86-
subaccounts(info::AccountInfo) = info.subaccounts
97+
debit!(acc::Account, amt::Position) = (acc.balance += amt)
98+
credit!(acc::Account, amt::Position) = (acc.balance -= amt)
8799

88-
id(info::AccountInfo) = id(account(info))
89-
balance(info::AccountInfo{Debit}) =
90-
isempty(subaccounts(info)) ? balance(account(info)) :
91-
balance(account(info)) + sum(map(info->balance(account(info)), subaccounts(info)))
92-
balance(info::AccountInfo{Credit}) =
93-
isempty(subaccounts(info)) ? -balance(account(info)) :
94-
-balance(account(info)) - sum(map(info->balance(account(info)), subaccounts(info)))
100+
struct Entry{D<:Account,C<:Account}
101+
debit::D
102+
credit::C
103+
end
95104

96105
function post!(entry::Entry, amt::Position)
97106
debit!(account(entry.debit), amt)
98107
credit!(account(entry.credit), amt)
99108
entry
100109
end
101110

102-
AbstractTrees.children(info::AccountInfo) =
103-
isempty(subaccounts(info)) ? Vector{AccountInfo}() : subaccounts(info)
104-
AbstractTrees.printnode(io::IO,info::AccountInfo) =
105-
print(io, "$(name(info)) ($(id(info))): $(balance(info))")
106-
107-
Base.show(io::IO,info::AccountInfo) =
108-
isempty(subaccounts(info)) ? printnode(io, info) : print_tree(io, info)
109-
110-
function Base.show(io::IO, e::Entry)
111-
print(io,
112-
"Entry:\n",
113-
" Debit: $(name(e.debit)) ($(id(e.debit))): $(balance(e.debit))\n",
114-
" Credit: $(name(e.credit)) ($(id(e.credit))): $(balance(e.credit))\n")
115-
end
116-
117111
struct Ledger{P<:Position,I<:AccountId}
118112
indexes::Dict{I,Int}
119113
accounts::StructArray{Account{P,I}}
@@ -128,15 +122,14 @@ struct Ledger{P<:Position,I<:AccountId}
128122
end
129123

130124
Base.getindex(ledger::Ledger, ix) = ledger.accounts[ix]
131-
132125
Base.getindex(ledger::Ledger, id::AccountId) =
133126
ledger.accounts[ledger.indexes[id]]
134127
Base.getindex(ledger::Ledger, array::AbstractVector{<:AccountId}) =
135128
ledger.accounts[broadcast(id->ledger.indexes[id], array)]
136129

137-
function add_account!(ledger::Ledger, account::Account)
138-
push!(ledger.accounts, account)
139-
ledger.indexes[id(account)] = length(ledger.accounts)
130+
function add_account!(ledger::Ledger, acc::Account)
131+
push!(ledger.accounts, acc)
132+
ledger.indexes[id(acc)] = length(ledger.accounts)
140133
end
141134

142135
# const chartofaccounts = Dict{String,AccountGroup{<:Cash}}()
@@ -180,4 +173,33 @@ end
180173
# return newaccount
181174
# end
182175

176+
Base.show(io::IO, id::Identifier) = print(io, id.value)
177+
Base.show(io::IO, code::AccountCode) = print(io, code.value)
178+
179+
Base.show(io::IO, ::Type{Debit}) = print(io, "Debit")
180+
Base.show(io::IO, ::Type{Credit}) = print(io, "Credit")
181+
182+
Base.show(io::IO, acc::Account) = print(io, "$(string(id(acc))): $(balance(acc)).")
183+
Base.show(io::IO, info::AccountInfo{Debit}) = print(io, "$(code(info)) - $(name(info)): $(balance(info)).")
184+
Base.show(io::IO, info::AccountInfo{Credit}) = print(io, "$(code(info)) - $(name(info)): $(-balance(info)).")
185+
186+
187+
# AbstractTrees.children(info::AccountInfo) =
188+
# isempty(subaccounts(info)) ? Vector{AccountInfo}() : subaccounts(info)
189+
# AbstractTrees.printnode(io::IO,info::AccountInfo) =
190+
# print(io, "$(name(info)) ($(id(info))): $(balance(info))")
191+
192+
# Base.show(io::IO,info::AccountInfo) =
193+
# isempty(subaccounts(info)) ? printnode(io, info) : print_tree(io, info)
194+
195+
# Base.show(io::IO, e::Entry) =
196+
# print(io, "Entry:\n", " Debit: $(e.debit)\n", " Credit: $(e.credit)")
197+
198+
# function Base.show(io::IO, e::Entry)
199+
# print(io,
200+
# "Entry:\n",
201+
# " Debit: $(name(e.debit)) ($(id(e.debit))): $(balance(e.debit))\n",
202+
# " Credit: $(name(e.credit)) ($(id(e.credit))): $(balance(e.credit))\n")
203+
# end
204+
183205
end # module Ledgers

0 commit comments

Comments
 (0)