Dictionaries can't find keys

I have this dictionary

starting_balance=starting_balance=Dict(
	# Starting Balance consists of a dictionary, containing debit and credit dictionaries, containing accounts as empty dictionaries.

	#accounts are organized into credit and debit, then into subledgers based on DEALER acrynym
	
	#Debit Accounts
		#Drawings
		#Expenses
		#Assets
	#Credit Accounts
		#Liabilities
		#Equity
		#Revenue
	
		#Year End Accounts   # These are used to close temporary accounts
			# Gross Revenue
			# Gross Expenses
			# Earned Income
	"debit"=>Dict(
					# balance = Σdebit - Σcredit		
		"drawings"=>Dict(),	#debit normal ledgers
		"expenses"=>Dict(),
		"assets"=>Dict()),
	"credit"=>Dict(  # revenue, liabilities, equtiy, and year_end, are credit normal
					 # balance = Σcredit -  Σdebit
		"liabilities"=>Dict(),
		"equity"=>Dict(),
		"revenue"=>Dict(),
			"retained"=> Dict( #Closing Accounts - No Balance Until Temp Accounts Closed
			"Retained Earnings"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Gross Income"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Gross Expenses"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Net Income"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Total Drawings"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
		)
	)
	)

but when I put in

starting_balance["expenses"]

It says the key expenses is not found, I have the same problem when I add a DataFrame as a value inside that dictionary

julia> starting_balance["debit"]["expenses"]
Dict{Any, Any}()

And for the second question:

df = DataFrame(date="10-Oct-2021", memo= "memo", debit=Vector{Dec64}([1.0, 2.2]),
     credit=Vector{Dec64}([3.0, 4.0]), balance=Vector{Dec64}([0.0, -1.1]))
     
starting_balance["credit"]["retained"]["Net Income"] = df

NB: a MWE should include all packages used, in this case: using DecFP, DataFrames

Ok thanks I’ll include the packages

         if !haskey(general_ledger["debit"][debit_ledger_entries[i]], credit_account_entries[i]) 

        
                if !haskey(general_ledger["credit"][debit_ledger_entries[i]], credit_account_entries[i])
            
                    return "Error -- "*debit_account_entries[i]*" not found in"*debit_ledger_entries[i]*"."
           
				else
                end

        else
        
            debit_amount_entries[i]=round(Dec64(debit_amount_entries[i]),digits=2)					
        
		end

why would I get an error saying that

the same key is not found, with an error number pointing to this row?

here is the whole function

function transaction(
    memo,
	date,
	debit_ledger_entries=[],
	debit_account_entries=[],
    debit_amount_entries=[],
	credit_ledger_entries=[],
    credit_account_entries=[],
    credit_amount_entries=[],
	general_ledger=general_ledger
	)
	
	
	if length(credit_ledger_entries) != length(credit_account_entries)
		
		return "Error--there must be the same number of credit legders and accounts"
		
	else
		
		if length(credit_account_entries) != length(credit_amount_entries)
			
			return "Error-- each account needs a value and vice versa"
			
		else
			
			if length(debit_ledger_entries) != length(debit_account_entries)
		
			    return "Error--there must be the same number of debit legders and accounts"
		
			else
		
				if length(debit_account_entries) != length(debit_amount_entries)
			
					return "Error-- each debit account needs a value and vice versa"
			
				else
					
					#test that debit amounts are balanced with credit amounts
					#totals are converted to Dec64 rounded to two decimals, to ensure that computer arithmetic, does not create a false imbalance
					
					#IMPORTANT when testing, revise code if imbalances are a problem
					
					if (round(Dec64(sum(debit_amount_entries)),digits=2)
					  -round(Dec64(sum(credit_amount_entries)),digits=2))!=0
						
						#there might be a problem, that the amounts no longer balance  I can move this test after the while loop, to ensure that is not a problem, but it may hurt performance, and it would mean adding invalid values to accounts
		
						return "Error-total credits does not match total debits"
					else
						
					journal_entry=DataFrame(Date=[date], 
											DebitedAccounts=[""],
											CreditedAccounts=[""],
											Debits=Vector{Dec64}([0.00]),
											Credits=Vector{Dec64}([0.00]),
											Balance=Vector{Dec64}([0.00]))
					i=1
                    end
                end
            end
        end
    end
	
	
	
	
 while i <= length(debit_amount_entries)	
		"""Test to see that for each DEBIT entry, the ledger and account exists"""
		
        if !haskey(general_ledger["debit"], debit_ledger_entries[i])
    
    
            if !haskey(general_ledger["credit"], debit_ledger_entries[i])
            
                return "Error -- "*debit_ledger_entries[i]*" not found"
            
			else
            end
		else
		end

            if !haskey(general_ledger["debit"][debit_ledger_entries[i]], credit_account_entries[i]) 

        
                if !haskey(general_ledger["credit"][debit_ledger_entries[i]], credit_account_entries[i])
            
                    return "Error -- "*debit_account_entries[i]*" not found in"*debit_ledger_entries[i]*"."
           
				else
                end

        else
        
            debit_amount_entries[i]=round(Dec64(debit_amount_entries[i]),digits=2)					
        
        	i+=1
		end
    end
	
 while i <= length(credit_amount_entries)	
		"""a test for each CREDIT Entry, that the ledger and account exist"""
        if !haskey(general_ledger["debit"], credit_ledger_entries[i])
    
    
            if !haskey(general_ledger["credit"], credit_ledger_entries[i])
            
                return "Error -- "*credit_ledger_entries[i]*" not found"
            
			else
            end
		else	
        end

            if !haskey(general_ledger["debit"][credit_ledger_entries[i]], credit_account_entries[i]) 

        
                if !haskey(general_ledger["credit"][credit_ledger_entries[i]], credit_account_entries[i])
            
                    return "Error -- "*credit_account_entries[i]*" not found in"*credit_ledger_entries[i]*"."
           

                end

        else
        """ after the accounts are shown to exist, the CREDIT values are converted to Dec64, rounded to two digits."""
            credit_amount_entries[i]=round(Dec64(credit_amount_entries[i]),digits=2)					
        
        	i+=1
		end
    end
	
	
   while i <= length(debit_ledger_entries)
						
        #values in arrays are identified with variables, then passed to other functions, to add information to accounts and the journal_entry
        
        #debit values are converted
            
        debit_ledger_name=debit_ledger_entries[i]
        debit_amount = round(debit_amount_entries[i];digits=2)
        debit_account=debit_account_entries[i]
            
        calc_debit_balance!(
                    general_ledger,
                    journal_entry,
                    date,
                    debit_ledger_name,
                    debit_account,
                    debit_amount,
                    memo)

        i+=1											
    end
        
    i=1
        
    while i <= length(credit_ledger_entries)
        
        #credit values are converted and added, after debit values
            
        credit_ledger_name=credit_ledger_entries[i]
        credit_account=credit_account_entries[i]
        credit_amount=floor(credit_amount_entries[i];digits=2)
        
                
        calc_credit_balance!(
                    general_ledger,
                    journal_entry,
                    date,
                    credit_ledger_name,
                    credit_account,
                    credit_amount,
                    memo)
    
        i+=1
            
    end
    
    #after these values are added to the journal entry in individual while loops, these the total debits and credits are added to and  this is added to the journal entry.
    
        
    push!(journal_entry,["","Total","Transaction",
                round(sum(journal_entry.Debits); digits=2),
                round(sum(journal_entry.Credits); digits=2),0])
    
        #finally the journl entry and table are outputed
        
    return (journal_entry, memo)
    
	
end;	

Not answering your questions, but…

  • are you sure nested Dicts are the best data structure for this purpose? If the fields are always the same, nested structs might be clearer / more robust.

  • it would be easier to provide an answer if your working example were truly minimal.

6 Likes

I was thinking of using DataFrames, I could look into structs. I’d like to provide a clear MWE, but I’m really lost about what is going wrong.

OK, let us start with a not working example then: if I include your function in Julia I get

transaction (generic function with 8 methods)

How do I call the function transaction then to reproduce your problem?

transaction("Weird Example",
	"Jan 2 2021",
	["retained"],
	["Gross Income"],
	[100.00],
				["retained"],
				["Net Income"],
				[100.00])

Now I get

ERROR: LoadError: UndefVarError: general_ledger not defined

general_ledger is the default for the parameter we did not specify in the call and has to exist therefore.

function transaction(
    memo,
	date,
	debit_ledger_entries=[],
	debit_account_entries=[],
    debit_amount_entries=[],
	credit_ledger_entries=[],
    credit_account_entries=[],
    credit_amount_entries=[],
	general_ledger=general_ledger
	)

Did you define it somewhere else?

general_ledger=deepcopy(starting_balance)

or

transaction("Weird Example",
	"Jan 2 2021",
	["retained"],
	["Gross Income"],
	[100.00],
				["retained"],
				["Net Income"],
				[100.00],
general_ledger)

So things start coming together. I assume you are using

using DataFrames, DecFP

somewhere. After installing the packages I now get

ERROR: LoadError: KeyError: key "retained" not found

Is this the problem you are also facing?

yes, that’s where I’m having an error.

Now a question of understanding regarding

return "Error -- "*debit_ledger_entries[i]*" not found"

and

return "Error -- "*debit_account_entries[i]*" not found in"*debit_ledger_entries[i]*"."

Do these entries have to exist in one of general_ledger["debit"] or general_ledger["credit"] or in both?

If the ledger name (the outer dictionary) is misspelled then it should show “Error – “debit_ledger_entries[i]” not found”
when the ledger name is correct,but the account is misspelled (the inner DataFrame), but the ledger name is spelled corretly, it’s supposed to return “Error – “debit_account_entries[i]” not found in"debit_ledger_entries[i]”."

If both names are matched to a key, then it’s supposed to move on to the next function. Currently, I’m not getting any error message involving calc_debit_balance! or calc_credit_balance! so I don’t think calling those functions is an issue right now.

I believe your checking logic

        if !haskey(general_ledger["debit"], debit_ledger_entries[i])
            if !haskey(general_ledger["credit"], debit_ledger_entries[i])
                return "Error -- "*debit_ledger_entries[i]*" not found"

is questionable and should be

        if !haskey(general_ledger["debit"], debit_ledger_entries[i]) ||
           !haskey(general_ledger["credit"], debit_ledger_entries[i])
            return "Error -- "*debit_ledger_entries[i]*" not found"

instead.

Please check the following complete example:

using DataFrames, DecFP

starting_balance=starting_balance=Dict(
	"debit"=>Dict(
		"drawings"=>Dict(),	#debit normal ledgers
		"expenses"=>Dict(),
		"assets"=>Dict()),
	"credit"=>Dict(
		"liabilities"=>Dict(),
		"equity"=>Dict(),
		"revenue"=>Dict(),
		"retained"=> Dict( #Closing Accounts - No Balance Until Temp Accounts Closed
			"Retained Earnings"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Gross Income"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Gross Expenses"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Net Income"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}()),
			"Total Drawings"=>DataFrame(
        date=Vector{String}(),
		memo=Vector{String}(),
        debit=Vector{Dec64}(),
        credit=Vector{Dec64}(),
		balance=Vector{Dec64}())))
)

function transaction(memo, date,
	debit_ledger_entries=[], debit_account_entries=[],
	debit_amount_entries=[], credit_ledger_entries=[],
	credit_account_entries=[], credit_amount_entries=[],
	general_ledger=general_ledger)

	if length(credit_ledger_entries) != length(credit_account_entries)
		return "Error--there must be the same number of credit legders and accounts"
	end
	if length(credit_account_entries) != length(credit_amount_entries)
		return "Error-- each account needs a value and vice versa"
	end
	if length(debit_ledger_entries) != length(debit_account_entries)
	    return "Error--there must be the same number of debit legders and accounts"
	end
	if length(debit_account_entries) != length(debit_amount_entries)
		return "Error-- each debit account needs a value and vice versa"
	end
	if (round(Dec64(sum(debit_amount_entries)),digits=2)
	  -round(Dec64(sum(credit_amount_entries)),digits=2))!=0
		return "Error-total credits does not match total debits"
	end

	journal_entry=DataFrame(Date=[date],
							DebitedAccounts=[""],
							CreditedAccounts=[""],
							Debits=Vector{Dec64}([0.00]),
							Credits=Vector{Dec64}([0.00]),
							Balance=Vector{Dec64}([0.00]))

	i=1
	while i <= length(debit_amount_entries)
		if !haskey(general_ledger["debit"], debit_ledger_entries[i]) ||
           !haskey(general_ledger["credit"], debit_ledger_entries[i])
        	return "Error -- "*debit_ledger_entries[i]*" not found"
		end
		if !haskey(general_ledger["debit"][debit_ledger_entries[i]], credit_account_entries[i]) ||
           !haskey(general_ledger["credit"][debit_ledger_entries[i]], credit_account_entries[i])
        	return "Error -- "*debit_account_entries[i]*" not found in"*debit_ledger_entries[i]*"."
        end

        debit_amount_entries[i]=round(Dec64(debit_amount_entries[i]),digits=2)
    	i+=1
    end

	i=1
	while i <= length(credit_amount_entries)
        if !haskey(general_ledger["debit"], credit_ledger_entries[i]) ||
           !haskey(general_ledger["credit"], credit_ledger_entries[i])
            return "Error -- "*credit_ledger_entries[i]*" not found"
        end
        if !haskey(general_ledger["debit"][credit_ledger_entries[i]], credit_account_entries[i]) ||
            !haskey(general_ledger["credit"][credit_ledger_entries[i]], credit_account_entries[i])
            return "Error -- "*credit_account_entries[i]*" not found in"*credit_ledger_entries[i]*"."
        end

        credit_amount_entries[i]=round(Dec64(credit_amount_entries[i]),digits=2)
    	i+=1
    end

	i=1
  	while i <= length(debit_ledger_entries)
        debit_ledger_name=debit_ledger_entries[i]
        debit_amount = round(debit_amount_entries[i];digits=2)
        debit_account=debit_account_entries[i]
        calc_debit_balance!(
                    general_ledger,
                    journal_entry,
                    date,
                    debit_ledger_name,
                    debit_account,
                    debit_amount,
                    memo)
        i+=1
    end

    i=1
	while i <= length(credit_ledger_entries)
        credit_ledger_name=credit_ledger_entries[i]
        credit_account=credit_account_entries[i]
        credit_amount=floor(credit_amount_entries[i];digits=2)
        calc_credit_balance!(
                    general_ledger,
                    journal_entry,
                    date,
                    credit_ledger_name,
                    credit_account,
                    credit_amount,
                    memo)
        i+=1
    end

    push!(journal_entry,["","Total","Transaction",
                round(sum(journal_entry.Debits); digits=2),
                round(sum(journal_entry.Credits); digits=2),0])
    return (journal_entry, memo)
end;

transaction("Weird Example", "Jan 2 2021",
	["retained"], ["Gross Income"], [100.00], ["retained"],
	["Net Income"], [100.00], starting_balance)

Fixing the questionable logic changed the message to

"Error -- retained not found"

I believe this is intended. I’ll now debug the problem.

Instrumenting the four while loops with something like

	i=1
	while i <= length(debit_amount_entries)
		println("step1")
		println(keys(general_ledger["debit"]))
		println(keys(general_ledger["credit"]))
		println(debit_ledger_entries[i])

shows

step1
["drawings", "expenses", "assets"]
["equity", "revenue", "liabilities", "retained"]
retained

So either "retained" should be contained in "debit" or both versions of the checking logic are wrong.

Now, the problem is that “retained” is a correct value, so it should pass these tests.