# Creating an Accounting Program in Julia, for Pluto

**URL:** <https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227>\
**Category:** Finance and Economics\
**Tags:** question, dataframes, function, pluto\
**Created:** [June 1, 2021, 8:38pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227 "2021-06-01T20:38:12Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 8:38pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/1 "2021-06-01T20:38:12Z")

</div>

I keep going in circles, do I use a macro, or do I use a function? How do I a get this

 ![phpx2XoSI](https://global.discourse-cdn.com/julialang/original/3X/3/7/37dec6b7a93441a6be1eb869cb48141ae404fce0.png)  
as a dataframe

and this  
 ![newstyletransactions2](https://global.discourse-cdn.com/julialang/original/3X/9/b/9b96aa2efda0246c9271219380f417fc278dfa82.png)  
as a dataframe

with one line of code.

These examples are from different sources, but the ledger(bottom) has each account as a title. The journal(top) documents one transaction (a row in the ledger), with the Name of each account(the columns of the ledger) that is modified in the transaction.

To process a transaction the sums of credit and debit must match.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 8:46pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/2 "2021-06-01T20:46:41Z")

</div>

This is what I have so far

```julia
using DataFrames

Ledger=DataFrame(
	chequing=[0],
	expenses=[0],
	income=[0])

```

I want to create a function or a macro, which has a journal entry, with a unique identifier, a credited account (one to start but more later), a debited account(again one now, more later), the date of the transaction, and a memo (called description in sample ledger), that describes the transaction, but this is less important.

I’m not sure how to make use of functions or macros (or another type of metaprograming) to accomplish this task.

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [June 1, 2021, 9:03pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/3 "2021-06-01T21:03:49Z")

</div>

This is a good start.  
I have some problems with the english financial terms (ledger,checking,…) , because I am not a finance person, but I think this is less important. More important is patience, we need to go step by step, no shortcuts.  
First: lets cancel macros out of our minds. Why? Metaprogramming is about generating code, special syntax to generate code, in other words “programming programs”, therefore the _meta_. It almost never makes sense to start with that. So: no macros for now.

If I understand it right: can we just concentrate on the ledger(s) for now? A journal can always be added later, isn’t it?

Ok, next step? A function to add an entry to a ledger?

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 9:39pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/4 "2021-06-01T21:39:27Z")

</div>

```julia
ledger=DataFrame(
	date=[""],
	chequing=[0],
	expenses=[0],
	income=[0])

new_row=(date="",chequing=[0],expenses=[0],income=[0])

function ledgertransaction(
		new_date,
		credit_account,
		credit_amount,
		debit_account,
		debit_amount)
		
		push!(ledger,new_row...,
		date=new_date,
		credit_account=credit_amount, 
		debit_account=debit_amount)
end

```

but when I execute :

```julia
ledgertransaction("Jan 1, 2000",expenses,100,chequing,100)

```

It says that expenses is not defined.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [June 1, 2021, 9:50pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/5 "2021-06-01T21:50:50Z")

</div>

Use `"expenses"` not `expenses`.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 9:54pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/6 "2021-06-01T21:54:11Z")

</div>

that works, but if you look at DataFrames, that’s not supposed to be a string.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [June 1, 2021, 9:57pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/7 "2021-06-01T21:57:09Z")

</div>

The account name is always just a string, isn’t it? The same way the amount is always just a number.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 9:58pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/8 "2021-06-01T21:58:48Z")

</div>

Is the column name a string? I’m just trying to add a row to the DataFrame named ‘ledger’.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [June 1, 2021, 10:01pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/9 "2021-06-01T22:01:08Z")

</div>

No, but you’re not trying to use the column name, you’re just specifying the value that goes into the `credit_account` column for this row.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 10:03pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/10 "2021-06-01T22:03:07Z")

</div>

No, I’m specifying the column that column\_amount goes into. This is the ledger, not the journal.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [June 1, 2021, 10:05pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/11 "2021-06-01T22:05:35Z")

</div>

Can we go to Zulip’s [data channel](https://julialang.zulipchat.com/#narrow/stream/228756-data), I think it will be easier to use than Discourse for this kind of thing.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 10:12pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/12 "2021-06-01T22:12:14Z")

</div>

OK, [Zulip](https://julialang.zulipchat.com/#narrow/stream/228756-data/topic/Using.20push!.20in.20a.20Function/near/241082255)

---

<div class="post-metadata">

**Author:** ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)\
**Post date:** [June 1, 2021, 10:28pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/13 "2021-06-01T22:28:51Z")

</div>

If you are writing an accounting program using Julia, you should be using Decimal Floating Point instead of Binary Floating Point. This way, you can make sure that your cents add up correctly…

```julia
$ julia
               _
   _ _ _(_)_ | Documentation: https://docs.julialang.org
  (_) | (_) (_) |
   _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` | |
  | | |_| | | | (_| | | Version 1.6.1 (2021-04-23)
 _/ |\ __'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |

julia> 0.1 + 0.1 + 0.1
0.30000000000000004

julia> using DFPs
[Info: Precompiling DFPs [top-level]

julia> d"0.1" + d"0.1" + d"0.1" |> DFP_toCommonString
"0.3000000000000000"

```

You don’t have access to DFPs (because it is my own private module) but there is a package called decimal I think that more or less does the same thing.

[https://github.com/JuliaMath/Decimals.jl](https://github.com/JuliaMath/Decimals.jl)

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 1, 2021, 11:13pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/14 "2021-06-01T23:13:32Z")

</div>

That was low down on my list now, but currently, I’m using integers, this is indeed something I was going to ask about.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 2, 2021, 2:04am UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/15 "2021-06-02T02:04:47Z")

</div>

Here is a function that creates a journal entry and adds a row to the ledger.

```julia
function ledgertransaction(
	#journal_entry,
    date,
    credit_account,
    credit_amount,
    debit_account,
    debit_amount
)

    default_row=Dict("chequing"=>0,"expenses"=>0,"income"=>0)
    spec = Dict("date" => date, credit_account => credit_amount, debit_account => debit_amount)
    row = merge(default_row, spec)
    push!(ledger,row)
	
	journal_entry=DataFrame(
		                   date=["Jan 1, 2000","","",""],
		                   credited_account=["", credit_account,"",""],
						   debited_account=["","",debit_account,""],
		                   credit=[0,credit_amount,0,0],
		                   debit=[0,0,debit_amount,0])

	end
end

```

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [June 2, 2021, 10:34am UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/16 "2021-06-02T10:34:20Z")

</div>

Good Morning, to all.  
Great, something proceeded, but we need to analyze, what happened and whats wrong or confusing.

Therefor we still drop journal\_entry, we are not yet there.  
And currency roundings are also ignored for now, we stay with _Int_, as we are dealing with more basic problems.

The current working code is:

```julia
using DataFrames

ledger=DataFrame(
	date=[""],
	chequing=[0],
	expenses=[0],
	income=[0])

function ledgertransaction(
    date,
    credit_account,
    credit_amount,
    debit_account,
    debit_amount
)
    default_row=Dict("chequing"=>0,"expenses"=>0,"income"=>0)
    spec = Dict("date" => date, credit_account => credit_amount, debit_account => debit_amount)
    row = merge(default_row, spec)
    push!(ledger,row)
end

ledgertransaction("Jan 1, 2000","expenses",100,"chequing",100)

```

It is working but there are some issues:

1. As the amount of the transactions must be equal, there is no need to pass the value 2 times. The function should therefor more look like:  
`ledgertransaction(date,amount,credit_account,debit_account)`

2. As we change `ledger` we should write it as:  
`ledgertransaction!(ledger,...)`

3. We shouldn’t at this point return anything from _ledgertransaction!_ (we should return _nothing_ or _true_ for no error and _false_ for error)

4. If we change the ledger definition, e.g. adding more accounts as columns or adding the description column, we have to change our function, which is error prone. So, the function should be more generic, so that any ledger can be passed. (this is a bit advanced)

5. It is possible to pass accounts, which aren’t present in the ledger. There needs to be some checking for this.

6. If `credit_account` and `debit_account` are given equal, only a single amount is accounted, which is an error. A check that those accounts a different is needed.

7. `default_row` isn’t a default row, it’s only some default values for some columns. It should be named like that (see point 4.: create `default_values` generically)

8. Parameter `date` can be empty: check for not empty (at least)

As my aim is not to provide just something which works but isn’t understood, I would suggest, that at first, we work on these issues before we proceed. This will also avoid those circles of confusion.

If you agree, take the following complete code, where the new function _ledgertransaction!_ has already been changed (issue 1., 2. and 3., check what I have done to adress these issues, please) and comments and suggestions are filled in, but it is up to you, to make it complete (put your code where you see the **#…** ):

```julia
using DataFrames

ledger=DataFrame(
	date=[""],
	chequing=[0],
	expenses=[0],
	income=[0])

function ledgertransaction!(ledger,date,amount,credit_account,debit_account)
	#check if date is not a empty string
	if length(date) == 0
		return false
	end
	
	#check if credit_account is different from debit_account:
	#...

	#check if credit_account exists:
	if !( credit_account in names(ledger) )
		return false
	end
	
	#check if debit_account exists:
	#...
	
	#create a default row more generically:
	# this is advanced stuff, you may skip it for now
	#...

	# skipped for now, stay with the original non-generic code:
	default_values=Dict("chequing"=>0,"expenses"=>0,"income"=>0)
	
	spec = Dict("date" => date, credit_account => amount, debit_account => amount)
	row = merge(default_values, spec)

	push!(ledger,row)
	return true
end

```

The following calls should do fine and return true if an entry was added or false if nothing was added because of any error:

```julia
ledgertransaction!(ledger,"Jan 1, 2000",100,"expenses","chequing")
ledgertransaction!(ledger,"Jan 1, 2000",10,"expenses","expenses")
ledgertransaction!(ledger,"Jan 1, 2000",20,"expenses","cheqing")
ledgertransaction!(ledger,"",30,"expenses","chequing")

```

> ****
>
> If you didn't skip the part with the generic \*default\_values\* (issue 4) the following should do also fine:
> 
> ```julia
> another_ledger=DataFrame(
> date=[""],
> chequing=[0],
> expenses=[0],
> income=[0],
> sum=[0]
> )
> ledgertransaction!(another_ledger,"Jan 1, 2000",100,"expenses","sum")
> 
> ```
> 
> In this example, the additional column _sum_ can be accessed like an account. Of course this is not what a _sum_ is. So this still needs special coding and can not be generic as the meaning of _sum_ is something different.

Give me some feedback, if it’s clear what I did in the code. And of course, the issues may need some discussion.  
Whatever questions you have, let’s get them out of the way before you proceed.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 2, 2021, 3:43pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/17 "2021-06-02T15:43:42Z")

</div>

I want to pass the value 2 times, because that way it’s easier to find a mistake.

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 2, 2021, 4:05pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/18 "2021-06-02T16:05:18Z")

</div>

Other than wanting to have both the credit and debit values, what you did looks really good. I changed the if statements, so that it can find all the errors. I guess lets work through the stuff for issue 4.

```julia
function ledgertransaction(
    date,
    credit_account,
    credit_amount,
    debit_account,
    debit_amount
)
	
	check=credit_amount-debit_amount
	
	if length(date) == 0
		"Error-- no date entered"
	else
	
	
	if !( credit_account in names(ledger) )
		"Error-- credit account not found"
	else
	
	if !( debit_account in names(ledger) )
		"Error--debit account not found"
	else
	
	if check != 0
		"Error -- credit and debit must match." 

	else

		
    default_row=Dict("chequing"=>0,"expenses"=>0,"income"=>0)
    spec = Dict(
			"date" => date, 
			credit_account => credit_amount, 
			debit_account => debit_amount)
		
    row = merge(default_row, spec)
    
	push!(ledger,row)
	
	journal_entry=DataFrame(
		                   date=["Jan 1, 2000","","",""],
		                   credited_account=["", credit_account,"",""],
						   debited_account=["","",debit_account,""],
		                   credit=[0,credit_amount,0,0],
		                   debit=[0,0,debit_amount,0],
			               
							#balance=[0,
							 # sum(credit_account),
				              # sum(add_debit_account),
				               # 0]
							#I need to figure out how to calculate my balance
		)

 
	end
			end
		end
	end
end

```

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [June 2, 2021, 4:37pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/19 "2021-06-02T16:37:43Z")

</div>

Your new function has new issues.  
(Thats how the circles start!)

A major issue is, that this new function returns the error strings in case of an error, but in case of no error, it returns `journal_entry` , which is type instability.  
For details see [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Write-%22type-stable%22-functions)  
(Issue named “type stable”)

Another major issue is, that, as I said (but with not much detail) in issue 2, we are changing _ledger_. Doing it, like you in your newest function, this would need a global _ledger_. We want to avoid global variables, see [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-global-variables)  
(Issue named “global variables”)

The goal for us is to implement your problem in a Julian way. That’s why I still hesitate to adress the `journal_entry`. For this I see a second function, which again should be implemented in Julian style.

If we do this now in a sloppy way (just producing working code) we will have problems later!

Passing the amount twice is ok, but errors must be handled, as you do. Fine.

The above two new issues, “type stable” and “global variables”) must be cleared, before we proceed! I have to insist 🙂

---

<div class="post-metadata">

**Author:** ![brett\_knoss](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brett_knoss/32/13050_2.png) [@brett\_knoss](https://discourse.julialang.org/u/brett_knoss)\
**Post date:** [June 2, 2021, 4:42pm UTC](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227/20 "2021-06-02T16:42:53Z")

</div>

Reading the performance tips i see that mixing types is an issue, the problem is that if it just returns false, it can take longer to find the error, is there a way around this?

[Next page](https://discourse.julialang.org/t/creating-an-accounting-program-in-julia-for-pluto/62227.md?page=2)
