Introduction
This is the second method I created for performing a double entry posting to Chart Of Accounts. The first one involved “coloring” the Chart Of Accounts listing displayed in the Windows form to discern the difference between the initial postings and the offsetting postings to the user. That was my own idea for making the double entry posting for the application and it worked well, but the customer had another idea. It was based on how he manually performed double entry postings with pen and paper. His idea is also very good and it will be the subject of this article.
Here's my first article:
C# Code For Making a Double Entry General Ledger Posting - Method 1 Moving Forward Figure 1 is the pop up menu from this program for performing double entry postings to Chart Of Accounts. The option titled,
“Add And Remove Double Entry Postings” has already been described in the article I wrote by the same name as this one for “
Method 1”. “
Add And Remove General Ledgers” is for adding and removing general ledgers from Chart Of Accounts. It does not involve the double entry posting process.
Figure 1 The other options described as “
CD Ledgers Maintenance” (cash disbursements), “
CR Ledgers Maintenance” (cash receipts), “
GL Ledgers Maintenance” (general ledger), “
J Ledgers Maintenance” (journal entry), “
PR Ledgers Maintenance” (payroll) and “
ST Ledgers Maintenance” (standard transaction) are double entry posting utilities, which are the subject of this article. In terms of programming, they are all mechanically identical, though the listing of general ledgers within each of these utilities differs. For the purpose of not being redundant, I will describe in detail the functions of the “
CD Ledgers Maintenance” Windows form.
A description of the initial posting procedure,
Figure 2 A listing of pre-determined general ledger accounts along with their DR (
debit) and CR (
credit) columns showing the total debit and credit amounts to be posted to each account are displayed in a list box above in Figure 2. The text boxes located directly below are for entering debit and credit amounts. When you enter an amount in either or both of two text boxes and then click the “
Post The Debit And/Or Credit Amounts Entered For The Highlighted GL#” button immediately to the right, the program will post the debit and credit amount(s) entered in the corresponding column in whatever general ledger account in the list box you had previously highlighted with the mouse. There is also a “
Yes or No” dropdown for adding the entered amount(s) to the previous fiscal year if desired. And there is a text box for allowing the user to override the current date for this transaction with an alternate date to be entered by the user (the current date is auto entered by default upon loading the form). Figures 3, 4 and 5 below illustrate the initial posting procedure.
Figure 3 Figure 4
Figure 5 We have not actually posted to the Chart Of Accounts yet. These postings are only being added to a sort of staging area as a list box on the Windows form. Here is the C# code that details how the “
Post The Debit And/Or Credit Amounts Entered For The Highlighted GL#” button works:
- private void PostTheAmount(object sender, EventArgs e)
- {
-
- string listBox1_String, debit_str, credit_str, previousfiscal;
- char[] charVal_debit, charVal_credit, charVal_date;
-
-
-
- currdir = Directory.GetCurrentDirectory();
- currdir = currdir.Substring(0, currdir.Length - 9);
-
-
-
-
- if (listBox1.SelectedIndex != -1)
- {
-
-
-
- listBox1_String = listBox1.Text;
-
-
-
- if (listBox1_String.Substring(0, 1) == "-" || listBox1_String.Substring(0, 1) == "G") MessageBox.Show("Invalid selection...", "Error Mode");
-
- if (listBox1_String.Substring(0, 1) != "-" && listBox1_String.Substring(0, 1) != "G")
- {
-
-
- result = MessageBox.Show("Do you want to post the debit and/or credit amount(s) to this highlighted general ledger?", "Verification Mode", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
-
- if (result == DialogResult.Yes)
- {
-
-
-
-
- previousfiscal = this.addtoprevfiscal.Text;
-
-
-
- debit_str = debitAmount.Text;
- credit_str = creditAmount.Text;
- charVal_debit = debit_str.ToCharArray(0, debit_str.Length);
- charVal_credit = credit_str.ToCharArray(0, credit_str.Length);
-
-
-
- FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");
- sizeofdatafile = datafileinfo.Length;
- StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");
- streamobj.BaseStream.Seek(0, SeekOrigin.Begin);
-
-
-
- datafileoffset = 0;
- do
- {
-
-
-
- stringVal = streamobj.ReadLine();
-
-
-
- strfile_temp = stringVal.Substring(45, 8) + "_.txt";
-
-
-
-
-
- if (stringVal.Substring(41, 4) == listBox1_String.Substring(0, 4))
- {
-
-
-
-
-
- for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;
-
-
-
- for (a = 0; a < debit_str.Length; a++) recordatavar_transactions[a + 50] = charVal_debit[a];
- for (a = 0; a < credit_str.Length; a++) recordatavar_transactions[a + 60] = charVal_credit[a];
-
-
-
- dateString = NewXctionDate.Text;
-
-
- if (dateString.Length < 8)
- {
- DateTime saveNow = DateTime.Now;
- dateString = saveNow.ToString(datePatt);
- }
-
-
-
- charVal_date = dateString.ToCharArray(0, dateString.Length);
- for (a = 0; a < dateString.Length; a++) recordatavar_transactions[a] = charVal_date[a];
-
-
-
-
- if (previousfiscal == "Yes")
- {
- recordatavar_transactions[2] = '^';
- }
-
-
-
- FileStream fstreamobj1 = new FileStream(currdir + strfile_temp, FileMode.Append);
- StreamWriter writerobj1 = new StreamWriter(fstreamobj1);
- writerobj1.WriteLine(recordatavar_transactions);
- writerobj1.Close();
- fstreamobj1.Close();
-
-
-
- }
-
-
-
-
- datafileoffset = datafileoffset + GLMASTERLEN;
-
-
-
- } while (datafileoffset < sizeofdatafile);
-
- streamobj.Close();
-
-
-
- UpdateListing();
-
-
- }
-
- }
-
- }
-
-
- else
- {
-
- MessageBox.Show("No general ledger selection was made...please try again.", "Error Mode");
-
- }
-
-
-
- }
Adding supplemental general ledger accounts to the initial posting process This next part will discuss the coding I use to add supplemental general ledger accounts to those ledger accounts displayed in the list box by default. This is a flexible feature that allows the user to add as many as 4 ledgers that may need to be incorporated into the initial posting process for any number of reasons. Here is the code that details how the “Add A Supplemental GL Account To The Current List” button functions:
- private void AddSupplementalGL(object sender, EventArgs e)
- {
-
- int found_glno;
- long sizeofdatafile_supplemental;
- string glno_str, glname_str;
- char[] charVal_glno, charVal_glname;
-
-
- result = MessageBox.Show("Do you want to add a supplemental GL account to the current listing?", "Verification Mode", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
-
- if (result == DialogResult.Yes)
- {
-
-
-
-
-
- FileInfo datafileinfo_supplemental = new FileInfo(currdir + "cd_ledger.txt");
- sizeofdatafile_supplemental = datafileinfo_supplemental.Length;
-
-
-
- if (sizeofdatafile_supplemental < GLAUXILIARY * 5)
- {
-
-
-
-
-
- glno_str = AuxiliaryGLNo.Text;
-
-
-
- if (glno_str.Length == 4)
- {
-
-
-
-
-
- FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");
- sizeofdatafile = datafileinfo.Length;
- StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");
- streamobj.BaseStream.Seek(0, SeekOrigin.Begin);
-
-
-
-
-
- datafileoffset = 0;
- found_glno = 0;
- do
- {
-
-
-
- stringVal = streamobj.ReadLine();
-
-
-
-
- if (stringVal.Substring(41, 4) == glno_str)
- {
-
-
-
-
-
- found_glno = 1;
-
-
-
-
-
- strfile_temp = stringVal.Substring(45, 8) + "_.txt";
-
-
-
- if (File.Exists(currdir + strfile_temp))
- {
- File.Delete(currdir + strfile_temp);
- }
-
-
-
- for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;
-
-
-
-
- FileStream fstreamobj1 = new FileStream(currdir + strfile_temp, FileMode.Create);
- StreamWriter writerobj1 = new StreamWriter(fstreamobj1);
- writerobj1.WriteLine(recordatavar_transactions);
- writerobj1.Close();
- fstreamobj1.Close();
-
-
-
-
- charVal_glno = glno_str.ToCharArray(0, glno_str.Length);
- glname_str = stringVal.Substring(0, 41);
- charVal_glname = glname_str.ToCharArray(0, glname_str.Length);
-
-
- for (a = 0; a < 45; a++) recordatavar_aux_ledger[a] = (char)32;
- for (a = 0; a < 4; a++) recordatavar_aux_ledger[a] = charVal_glno[a];
- for (a = 0; a < 41; a++) recordatavar_aux_ledger[a + 4] = charVal_glname[a];
-
-
-
- FileStream fstreamobj2 = new FileStream(currdir + "cd_ledger.txt", FileMode.Append);
- StreamWriter writerobj2 = new StreamWriter(fstreamobj2);
- writerobj2.WriteLine(recordatavar_aux_ledger);
- writerobj2.Close();
- fstreamobj2.Close();
-
-
-
- }
-
-
-
-
-
- datafileoffset = datafileoffset + GLMASTERLEN;
-
-
-
- } while (datafileoffset < sizeofdatafile && found_glno == 0);
-
- streamobj.Close();
-
-
-
- this.AuxiliaryGLNo.Text = "";
-
-
-
- UpdateListing();
-
-
- if (found_glno == 0)
- {
-
- MessageBox.Show("The GL number was not found and was not added to the current listing...please try again.", "Error Mode");
-
- }
-
-
-
- }
- else
- {
-
- MessageBox.Show("Invalid GL number...please try again.", "Error Mode");
-
- }
-
-
-
- }
- else
- {
-
- MessageBox.Show("Unable to add any more supplemental GL accounts...", "Error Mode");
-
- }
-
-
-
- }
-
-
- }
Verify the amounts before posting to chart of accounts When you scroll to the bottom of the list box on the Windows form, you will see grand totals at the bottom. This is a convenience that tells the user if the debits and credits are equal (in balance and ready for posting to Chart Of Accounts). See the following figure 6,
Figure 6
Post the displayed amounts in the list box to chart of accounts The last step is to post the amounts from the list box on the Windows form to Chart Of Accounts. Click the button, “Append The Displayed Amounts To Their Ledgers”, to perform this task (see Figure 7).
Figure 7 The code for this operation is shown here:
- private void PostToChartOfAccounts(object sender, EventArgs e)
- {
-
- string stringAutoNumber, strfile_orig, transaction_str;
- long autonum_var;
- char[] charVal_auto_number = new char[3];
- char[] put_in_orig_ledger, charVal_tranaction;
-
-
-
- currdir = Directory.GetCurrentDirectory();
- currdir = currdir.Substring(0, currdir.Length - 9);
-
-
- result = MessageBox.Show("Do you want to proceed with this permanent double entry posting transaction for all the general ledgers displayed?", "Verification Mode", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
-
- if (result == DialogResult.Yes)
- {
-
- Cursor.Current = new Cursor(currdir + "Busy_l.cur");
-
-
-
-
-
- StreamReader streamobj3 = new StreamReader(currdir + "autonumber.txt");
- streamobj3.BaseStream.Seek(0, SeekOrigin.Begin);
- stringAutoNumber = streamobj3.ReadLine();
- streamobj3.Close();
-
- for (a = 0; a < 3; a++)
- {
- convert_to_number[a] = 0;
- if (stringAutoNumber.Substring(a, 1) == "0") convert_to_number[a] = 0;
- if (stringAutoNumber.Substring(a, 1) == "1") convert_to_number[a] = 1;
- if (stringAutoNumber.Substring(a, 1) == "2") convert_to_number[a] = 2;
- if (stringAutoNumber.Substring(a, 1) == "3") convert_to_number[a] = 3;
- if (stringAutoNumber.Substring(a, 1) == "4") convert_to_number[a] = 4;
- if (stringAutoNumber.Substring(a, 1) == "5") convert_to_number[a] = 5;
- if (stringAutoNumber.Substring(a, 1) == "6") convert_to_number[a] = 6;
- if (stringAutoNumber.Substring(a, 1) == "7") convert_to_number[a] = 7;
- if (stringAutoNumber.Substring(a, 1) == "8") convert_to_number[a] = 8;
- if (stringAutoNumber.Substring(a, 1) == "9") convert_to_number[a] = 9;
- }
- autonum_var = ((convert_to_number[0] * 100) + (convert_to_number[1] * 10) + (convert_to_number[2] * 1));
- autonum_var++;
- if (autonum_var > 999)
- {
- autonum_var = 0;
- }
-
- for (a = 0; a < 3; a++) charVal_auto_number[a] = (char)48;
- countervar = 2;
- do
- {
- longresult = Math.DivRem(autonum_var, 10, out long2);
- autonum_var = longresult;
- if (long2 == 0) charVal_auto_number[countervar] = (char)48;
- if (long2 == 1) charVal_auto_number[countervar] = (char)49;
- if (long2 == 2) charVal_auto_number[countervar] = (char)50;
- if (long2 == 3) charVal_auto_number[countervar] = (char)51;
- if (long2 == 4) charVal_auto_number[countervar] = (char)52;
- if (long2 == 5) charVal_auto_number[countervar] = (char)53;
- if (long2 == 6) charVal_auto_number[countervar] = (char)54;
- if (long2 == 7) charVal_auto_number[countervar] = (char)55;
- if (long2 == 8) charVal_auto_number[countervar] = (char)56;
- if (long2 == 9) charVal_auto_number[countervar] = (char)57;
- countervar--;
- } while (autonum_var > 0);
-
- if (File.Exists(currdir + "autonumber.txt"))
- {
- File.Delete(currdir + "autonumber.txt");
- }
-
- FileStream fstreamobj2 = new FileStream(currdir + "autonumber.txt", FileMode.Create);
- StreamWriter writerobj2 = new StreamWriter(fstreamobj2);
- writerobj2.WriteLine(charVal_auto_number);
- writerobj2.Close();
- fstreamobj2.Close();
-
-
-
-
-
- FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");
- sizeofdatafile = datafileinfo.Length;
- StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");
- streamobj.BaseStream.Seek(0, SeekOrigin.Begin);
-
-
-
- FileInfo datafileinfo_auxiliary = new FileInfo(currdir + "cd_ledger.txt");
- sizeofdatafile_auxiliary = datafileinfo_auxiliary.Length;
- StreamReader streamobj_auxiliary = new StreamReader(currdir + "cd_ledger.txt");
-
-
- datafileoffset = 0;
- do
- {
-
-
-
- stringVal = streamobj.ReadLine();
-
-
-
-
- strfile_temp = stringVal.Substring(45, 8);
- strfile_temp = strfile_temp + "_.txt";
-
-
-
- strfile_orig = stringVal.Substring(45, 8);
- strfile_orig = strfile_orig + ".txt";
-
-
-
-
-
- calc_flag = 0;
-
- if (stringVal.Substring(41, 4) == "1000")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "1010")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "1040")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "1070")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "1080")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2100")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2110")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2120")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2160")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2210")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "2400")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "3030")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "4200")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "4400")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "5000")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "6500")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "7300")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "7400")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "8200")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "8300")
- {
- calc_flag = 1;
- }
- if (stringVal.Substring(41, 4) == "9100")
- {
- calc_flag = 1;
- }
-
-
-
-
-
- streamobj_auxiliary.BaseStream.Seek(0, SeekOrigin.Begin);
- datafileoffset_auxiliary = 0;
- do
- {
-
- stringVal_auxiliary = streamobj_auxiliary.ReadLine();
-
- if (stringVal.Substring(41, 4) == stringVal_auxiliary.Substring(0, 4))
- {
- calc_flag = 1;
- auxiliary_ledger_count++;
- }
-
- datafileoffset_auxiliary = datafileoffset_auxiliary + GLAUXILIARY;
-
- } while (datafileoffset_auxiliary < sizeofdatafile_auxiliary);
-
-
-
-
-
-
- if (calc_flag == 1 && File.Exists(currdir + strfile_temp))
- {
-
-
-
-
-
- FileInfo datafileinfo2 = new FileInfo(currdir + strfile_temp);
- sizeofdatafile2 = datafileinfo2.Length;
- StreamReader streamobj2 = new StreamReader(currdir + strfile_temp);
- streamobj2.BaseStream.Seek(0, SeekOrigin.Begin);
-
-
- datafileoffset2 = 0;
- do
- {
-
-
-
- stringVal = streamobj2.ReadLine();
-
-
-
-
-
- if (stringVal.Substring(50, 10) != " " || stringVal.Substring(60, 10) != " ")
- {
-
-
-
-
-
- transaction_str = "CD Transaction";
- charVal_tranaction = transaction_str.ToCharArray(0, transaction_str.Length);
- put_in_orig_ledger = stringVal.ToCharArray(0, stringVal.Length);
-
-
-
- for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;
-
-
-
-
-
- for (a = 0; a < stringVal.Length; a++) recordatavar_transactions[a] = put_in_orig_ledger[a];
- recordatavar_transactions[8] = 'C';
- recordatavar_transactions[9] = 'D';
- for (a = 0; a < transaction_str.Length; a++) recordatavar_transactions[a + 10] = charVal_tranaction[a];
- for (a = 0; a < 3; a++) recordatavar_transactions[a + 70] = charVal_auto_number[a];
-
-
-
- FileStream fstreamobj1 = new FileStream(currdir + strfile_orig, FileMode.Append);
- StreamWriter writerobj1 = new StreamWriter(fstreamobj1);
- writerobj1.WriteLine(recordatavar_transactions);
- writerobj1.Close();
- fstreamobj1.Close();
-
-
- }
-
-
-
-
- datafileoffset2 = datafileoffset2 + GLDETAILEN;
-
-
- } while (datafileoffset2 < sizeofdatafile2);
-
- streamobj2.Close();
-
-
-
-
-
- if (File.Exists(currdir + strfile_temp))
- {
- File.Delete(currdir + strfile_temp);
- }
-
-
-
- }
-
-
-
-
-
- datafileoffset = datafileoffset + GLMASTERLEN;
-
-
-
- } while (datafileoffset < sizeofdatafile);
-
- streamobj_auxiliary.Close();
-
- streamobj.Close();
-
-
-
-
- if (File.Exists(currdir + "cd_ledger.txt"))
- {
- File.Delete(currdir + "cd_ledger.txt");
-
- for (a = 0; a < 45; a++) recordatavar_aux_ledger[a] = (char)32;
-
- FileStream fstreamobj_auxiliary = new FileStream(currdir + "cd_ledger.txt", FileMode.Create);
- StreamWriter writerobj_auxiliary = new StreamWriter(fstreamobj_auxiliary);
- writerobj_auxiliary.WriteLine(recordatavar_aux_ledger);
- writerobj_auxiliary.Close();
- fstreamobj_auxiliary.Close();
-
- }
-
-
-
-
- UpdateListing();
-
-
-
- Cursor.Current = Cursors.Default;
-
-
- }
-
-
- }
Conclusion Although my first method worked well and I thought it was relatively easy to use, it still wasn’t acceptable to the customer. I have spent years learning this reality. That’s why it is always important to listen to what customers really want and cater to that want with
software that will keep them happy. Just because something looks good on the drawing board doesn’t necessarily guarantee people will be satisfied with it, even if it does work correctly. Most people don’t realize just how subjective this business can be - it isn’t like going out and selling 10,000 widgets. That’s why it’s called
custom software.