Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
EricForgy committed Feb 24, 2019
1 parent e76f4a1 commit 5fd694a
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 141 deletions.
81 changes: 44 additions & 37 deletions Manifest.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# This file is machine-generated - editing it directly is not advised

[[AbstractTrees]]
deps = ["Markdown", "Test"]
git-tree-sha1 = "6621d9645702c1c4e6970cc6a3eae440c768000b"
uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
version = "0.2.1"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[BenchmarkTools]]
deps = ["JSON", "Printf", "Statistics", "Test"]
git-tree-sha1 = "5d1dd8577643ba9014574cd40d9c028cd5e4b85a"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "0.4.2"

[[Countries]]
deps = ["DelimitedFiles", "ISOCurrencies"]
git-tree-sha1 = "5a8fd5dd76be1430bb074a29ad2b99d4aa3d3309"
repo-rev = "master"
repo-url = "https://github.com/JuliaFinance/Countries.jl.git"
uuid = "d5396ca0-2cf9-11e9-2c96-2532c40e11ac"
[[Currencies]]
deps = ["DelimitedFiles"]
git-tree-sha1 = "98344a4fcd55f9cd99cc966da276be2fd44e8b06"
uuid = "0fd90b74-7c1f-579e-9252-02cd883047b9"
version = "0.1.0"

[[Dates]]
Expand All @@ -29,29 +27,27 @@ uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[ISOCurrencies]]
git-tree-sha1 = "204b1d228b42b033dca526d607a91fef7f3bafa6"
repo-rev = "master"
repo-url = "https://github.com/JuliaFinance/ISOCurrencies.jl.git"
uuid = "5683cba2-2ced-11e9-0d3f-33b1fe4e9d91"
[[Entities]]
deps = ["Jurisdictions", "Reexport"]
git-tree-sha1 = "45c65c262564c695bc87085016626b6cc0649b07"
uuid = "d68c5960-3734-11e9-0c07-a30dcbe4dda4"
version = "0.1.0"

[[FinancialInstruments]]
deps = ["Dates", "Entities", "Reexport"]
git-tree-sha1 = "2a09c7d97463415e9d12e72a2601d9b4a278c488"
uuid = "fc5b99d0-3725-11e9-2623-bf561589b708"
version = "0.1.0"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[JSON]]
deps = ["Dates", "Distributed", "Mmap", "Sockets", "Test", "Unicode"]
git-tree-sha1 = "1f7a25b53ec67f5e9422f1f551ee216503f4a0fa"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.20.0"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
[[Jurisdictions]]
deps = ["Markets", "Reexport"]
git-tree-sha1 = "6ce1c2adbfe0421ae11af14049a26deda860346d"
uuid = "044ac1b0-3745-11e9-192d-5d2cecb87306"
version = "0.1.0"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
Expand All @@ -60,9 +56,21 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[Markets]]
deps = ["Currencies", "Reexport"]
git-tree-sha1 = "7738553ae8be6bb2e9b20078b8d0ac60c2a01c79"
uuid = "b44f5480-3750-11e9-03b7-d5e34f572a03"
version = "0.1.0"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[Positions]]
deps = ["FinancialInstruments", "Reexport"]
git-tree-sha1 = "60903a5c32659d913f2eae3c3b7fe83aa116da90"
uuid = "81d999f0-3725-11e9-2196-fd457307c398"
version = "0.1.0"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Expand All @@ -71,20 +79,19 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Reexport]]
git-tree-sha1 = "7b1d07f411bc8ddb7977ec7f377b97b158514fe0"
repo-rev = "master"
repo-url = "https://github.com/EricForgy/Reexport.jl"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "0.2.0+"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[Test]]
deps = ["Distributed", "InteractiveUtils", "Logging", "Random"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
13 changes: 10 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ authors = ["Eric Forgy <[email protected]>"]
version = "0.1.0"

[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
Countries = "d5396ca0-2cf9-11e9-2c96-2532c40e11ac"
ISOCurrencies = "5683cba2-2ced-11e9-0d3f-33b1fe4e9d91"
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Positions = "81d999f0-3725-11e9-2196-fd457307c398"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# GeneralLedgers.jl
83 changes: 6 additions & 77 deletions src/GeneralLedgers.jl
Original file line number Diff line number Diff line change
@@ -1,82 +1,11 @@
module GeneralLedgers

import ISOCurrencies.Currencies: Currency, USD
using Reexport, AbstractTrees
@reexport using Positions

# There should be three types of accounts:
# 1. GeneralLedger - Has no parent. Has children. Cannot post journal entries directly.
# 2. AccountGroup - Has a parent. Has children. Cannot post journal entries directly.
# 3. LedgerAccount - Has a parent. Has no children. Can post journal entries directly.

# What about "Modules"?

# - Financial Reports
# - Audit Controls
# - Inventory Management
# - Invoice / Customer / Purchase Order / Vendor / Receipts Management

# Account types
# - Balance Sheet
# - Income Statement
# - Retained Earnings

abstract type Ledger end
abstract type Account end

struct GeneralLedger <: Ledger
name::String
currency::Currency
children::Dict{String,Union{Ledger,Account}}

GeneralLedger(name::String,currency::Currency,children=Dict{String,Union{Ledger,Account}}()) = new(name,currency,children)
end

struct AccountGroup <: Ledger
parent::Ledger
name::String
code::String
children::Dict{String,Union{Ledger,Account}}

function AccountGroup(parent,name,code)
haskey(parent.children,code) && error("Account code $(code) already exists.")
account = new(parent,name,code,Dict{String,Union{Ledger,Account}}())
parent.children[code] = account
return account
end
end

struct DebitAccount <: Account
parent::Ledger
name::String
code::String

function DebitAccount(parent,name,code)
haskey(parent.children,code) && error("Account code $(code) already exists.")
account = new(parent,name,code)
parent.children[code] = account
return account
end
end

struct CreditAccount <: Account
parent::Ledger
name::String
code::String

function CreditAccount(parent,name,code)
haskey(parent.children,code) && error("Account code $(code) already exists.")
account = new(parent,name,code)
parent.children[code] = account
return account
end
end

include("show.jl")

function example()
ledger = GeneralLedger("NewCo",USD)
assets = DebitAccount(ledger,"Assets","1")
liabilities = CreditAccount(ledger,"Liabilities","2")
return ledger
end
include("account.jl")
include("entries.jl")
include("display.jl")
include("example.jl")

end # module
79 changes: 79 additions & 0 deletions src/account.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
struct GeneralLedger{C} end
struct DebitGroup{C} end
struct CreditGroup{C} end
struct DebitAccount{C} end
struct CreditAccount{C} end

mutable struct Account{C<:Currency}
parent::Union{Account,Nothing}
name::String
code::Union{String,Nothing}
isdebit::Union{Bool,Nothing}
balance::Union{Position{C},Nothing}
subaccounts::Union{Vector{Account},Nothing}
chart::Union{Dict{String,Account},Nothing}

function Account{C}(parent,name,code,isdebit,balance,subaccounts,chart) where C<:Currency
a = new(parent,name,code,isdebit,balance,subaccounts,chart)
if !isnothing(parent)
push!(parent.subaccounts,a)
if isnothing(subaccounts)
add(a)
end
end
return a
end
end

function get_ledger(a::Account)
p = a
while !isnothing(p.parent)
p = p.parent
end
return p
end

function add(a::Account)
ledger = get_ledger(a)
ledger.chart[a.code] = a
end

function accounttype(a::Account{C}) where C
if isnothing(a.parent)
return GeneralLedger{C}()
elseif a.isdebit
if isnothing(a.subaccounts)
return DebitAccount{C}()
else
return DebitGroup{C}()
end
else
if isnothing(a.subaccounts)
return CreditAccount{C}()
else
return CreditGroup{C}()
end
end
end

DebitAccount(p,n,c,b::Position{C}=Position(Currencies.USD,0.)) where C = Account{C}(p,n,c,true,b,nothing,nothing)
CreditAccount(p,n,c,b::Position{C}=Position(Currencies.USD,0.)) where C = Account{C}(p,n,c,false,b,nothing,nothing)
DebitGroup(p,n,c,::C=Currencies.USD) where C = Account{C}(p,n,c,true,nothing,Vector{Account}(),nothing)
CreditGroup(p,n,c,::C=Currencies.USD) where C = Account{C}(p,n,c,false,nothing,Vector{Account}(),nothing)
GeneralLedger(n,::C=Currencies.USD) where C = Account{C}(nothing,n,nothing,true,nothing,Vector{Account}(),Dict{String,Account}())

currency(a::Account{C}) where C = C()

balance(a::Account) = balance(a,accounttype(a))
balance(a::Account{C}, ::Union{DebitAccount{C},CreditAccount{C}}) where C = a.balance
function balance(a::Account{C}, ::Any) where C
b = Position{C}(0.)
for account in a.subaccounts
if isequal(a.isdebit,account.isdebit)
b += balance(account)
else
b -= balance(account)
end
end
return b
end
29 changes: 29 additions & 0 deletions src/display.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
AbstractTrees.printnode(x) = AbstractTrees.printnode(stdout,x)

AbstractTrees.children(a::Account) = _children(a,accounttype(a))
_children(a::Account,::GeneralLedger) = isnothing(a.subaccounts) ? Vector{Account}() : [a.subaccounts;[a.chart]]
_children(a::Account,::Any) = isnothing(a.subaccounts) ? Vector{Account}() : a.subaccounts

AbstractTrees.printnode(io::IO,a::Account) = _printnode(io,a,accounttype(a))
_printnode(io::IO,a::Account,::GeneralLedger{C}) where C = print(io,a.name)
_printnode(io::IO,a::Account,::Union{DebitGroup,CreditGroup}) = print(io,a.name)
_printnode(io::IO,a::Account,::Union{DebitAccount,CreditAccount}) = print(io,"$(a.name): ",balance(a))

AbstractTrees.printnode(io::IO,c::Dict{String,Account}) = print(io,"Chart of Accounts:")

Base.show(io::IO,a::Account) = _show(io,a,accounttype(a))
_show(io::IO,a::Account,::Union{GeneralLedger,DebitGroup,CreditGroup}) = print_tree(io,a)
_show(io::IO,a::Account,t::Union{DebitAccount,CreditAccount}) = _printnode(io,a,t)

Base.show(io::IO,a::DebitGroup{C}) where C = print(io,"DebitGroup{",C(),"}")
Base.show(io::IO,a::CreditGroup{C}) where C = print(io,"CreditGroup{",C(),"}")
Base.show(io::IO,a::DebitAccount{C}) where C = print(io,"DebitAccount{",C(),"}")
Base.show(io::IO,a::CreditAccount{C}) where C = print(io,"CreditAccount{",C(),"}")

AbstractTrees.children(e::Entry) = [e.debit,e.credit,e.amount]
AbstractTrees.printnode(io::IO,c::Entry) = print(io,"Entry")
AbstractTrees.printnode(io::IO,c::Position{C}) where C = print(io,c)

Base.show(io::IO,c::Position{C}) where C<:Currency = print(io,c.amount," ",C())
Base.show(io::IO,e::Entry) = print_tree(io,e)

31 changes: 31 additions & 0 deletions src/entries.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
struct Entry{C<:Currency}
debit::Account{C}
credit::Account{C}
amount::Position{C}
end

debit!(a::Account{C},c::Position{C}) where C = debit!(a,c,accounttype(a))
credit!(a::Account{C},c::Position{C}) where C = credit!(a,c,accounttype(a))

function debit!(a::Account{C},c::Position{C},::DebitAccount{C}) where C
a.balance += c
return a
end
function debit!(a::Account{C},c::Position{C},::CreditAccount{C}) where C
a.balance -= c
return a
end
function credit!(a::Account{C},c::Position{C},::CreditAccount{C}) where C
a.balance += c
return a
end
function credit!(a::Account{C},c::Position{C},::DebitAccount{C}) where C
a.balance -= c
return a
end

function post!(e::Entry)
debit!(e.debit,e.amount)
credit!(e.credit,e.amount)
end

10 changes: 10 additions & 0 deletions src/example.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function example()
ledger = GeneralLedger("NewCo")
assets = DebitGroup(ledger,"Assets","1000000")
liabilities = CreditGroup(ledger,"Liabilities","2000000")
cash = DebitAccount(assets,"Cash","1010000")
payable = CreditAccount(liabilities,"Accounts Payable","2010000")

entry = Entry(cash,payable,Position(Currencies.USD,10.))
return ledger, assets, liabilities, cash, payable, entry
end
Loading

0 comments on commit 5fd694a

Please sign in to comment.