C# Code For Making A Double Entry General Ledger Posting - Method 2

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.

General Ledgers
                                                                         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,

description of the initial posting
                                                                                                                        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.

Select data
                                                                                  Figure 3

Verification Mode
                                                                                         Figure 4

table
                                                                                          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:
  1. private void PostTheAmount(object sender, EventArgs e)  
  2. {  
  3.     // declare local variables.  
  4.     string listBox1_String, debit_str, credit_str, previousfiscal;  
  5.     char[] charVal_debit, charVal_credit, charVal_date;  
  6.   
  7.   
  8.     // get current working directory.  
  9.     currdir = Directory.GetCurrentDirectory();  
  10.     currdir = currdir.Substring(0, currdir.Length - 9);  
  11.   
  12.   
  13.     // verify that a ledger has been selected from the Chart Of Accounts  
  14.     // listing before proceeding.  
  15.     if (listBox1.SelectedIndex != -1)  
  16.     {  
  17.   
  18.         // grab the selected general ledger from the Windows form into  
  19.         // a string variable, 'listBox1_String'.  
  20.         listBox1_String = listBox1.Text;  
  21.   
  22.         // if the general ledger that was selected is invalid, then   
  23.         // display a message for this, then abort.  
  24.         if (listBox1_String.Substring(0, 1) == "-" || listBox1_String.Substring(0, 1) == "G") MessageBox.Show("Invalid selection...""Error Mode");  
  25.         // if the general ledger that was selected is valid, then proceed.  
  26.         if (listBox1_String.Substring(0, 1) != "-" && listBox1_String.Substring(0, 1) != "G")  
  27.         {  
  28.   
  29.   
  30.             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);  
  31.   
  32.             if (result == DialogResult.Yes)  
  33.             {  
  34.   
  35.   
  36.                 // grab the Windows form flag for whether or not to add these   
  37.                 // entered amount(s) to the previous fiscal year.  
  38.                 previousfiscal = this.addtoprevfiscal.Text;  
  39.   
  40.                 // grab the debit and credit amount(s) and convert to character arrays  
  41.                 // to prepare for further processing.  
  42.                 debit_str = debitAmount.Text;  
  43.                 credit_str = creditAmount.Text;  
  44.                 charVal_debit = debit_str.ToCharArray(0, debit_str.Length);  
  45.                 charVal_credit = credit_str.ToCharArray(0, credit_str.Length);  
  46.                   
  47.                 // open a file stream to the Chart Of Accounts data file for  
  48.                 // subsequent read operations.  
  49.                 FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");  
  50.                 sizeofdatafile = datafileinfo.Length;  
  51.                 StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");  
  52.                 streamobj.BaseStream.Seek(0, SeekOrigin.Begin);  
  53.   
  54.   
  55.                 // initialize the Chart Of Accounts data file offset to 0.  
  56.                 datafileoffset = 0;  
  57.                 do  
  58.                 {  
  59.   
  60.   
  61.                     // read the next sequential record from the Chart Of Accounts data file.  
  62.                     stringVal = streamobj.ReadLine();  
  63.   
  64.                     // construct a transient general ledger file name for the current Chart  
  65.                     // Of Accounts record and assign it to the variable, 'strfile_temp'.  
  66.                     strfile_temp = stringVal.Substring(45, 8) + "_.txt";  
  67.   
  68.   
  69.                     // compare the general ledger # from the 'stringVal' variable to what was  
  70.                     // selected in the listing on the Windows form. if equal, then proceed with  
  71.                     // the posting of the entered amount(s) to the Windows form.  
  72.                     if (stringVal.Substring(41, 4) == listBox1_String.Substring(0, 4))  
  73.                     {  
  74.   
  75.   
  76.   
  77.                         // clear out the character array, 'recordatavar_transactions', used  
  78.                         // for the Windows form posting operation.  
  79.                         for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;  
  80.   
  81.                         // assign whatever debit and/or credit amount(s) were entered into the  
  82.                         // Windows form to the character array, 'recordatavar_transactions'.  
  83.                         for (a = 0; a < debit_str.Length; a++) recordatavar_transactions[a + 50] = charVal_debit[a];  
  84.                         for (a = 0; a < credit_str.Length; a++) recordatavar_transactions[a + 60] = charVal_credit[a];  
  85.   
  86.                         // grab the date of the alternate date field and assign  
  87.                         // it to the variable for the transaction date, 'dateString'.  
  88.                         dateString = NewXctionDate.Text;  
  89.                         // if no date was entered in the alternate date field, then assign the  
  90.                         // current date to 'dateString'.  
  91.                         if (dateString.Length < 8)  
  92.                         {  
  93.                             DateTime saveNow = DateTime.Now;  
  94.                             dateString = saveNow.ToString(datePatt);  
  95.                         }  
  96.                         // convert 'dateString' to a character array and insert it into the  
  97.                         // character array 'recordatavar_transactions', which also holds any  
  98.                         // debit and/or credit amount(s) entered by the user.  
  99.                         charVal_date = dateString.ToCharArray(0, dateString.Length);  
  100.                         for (a = 0; a < dateString.Length; a++) recordatavar_transactions[a] = charVal_date[a];  
  101.   
  102.                         // if the user chose to add these debit and/or credit amount(s) to the  
  103.                         // previous fiscal year, then use the '^' symbol to denote that in the  
  104.                         // character array, 'recordatavar_transactions'.  
  105.                         if (previousfiscal == "Yes")  
  106.                         {  
  107.                             recordatavar_transactions[2] = '^';  
  108.                         }  
  109.   
  110.                         // append the character array, 'recordatavar_transactions', to the  
  111.                         // transient data file specified by 'strfile_temp'.  
  112.                         FileStream fstreamobj1 = new FileStream(currdir + strfile_temp, FileMode.Append);  
  113.                         StreamWriter writerobj1 = new StreamWriter(fstreamobj1);  
  114.                         writerobj1.WriteLine(recordatavar_transactions);  
  115.                         writerobj1.Close();  
  116.                         fstreamobj1.Close();  
  117.   
  118.   
  119.   
  120.                     }  
  121.   
  122.   
  123.                     // advance the Chart Of Accounts data file offset forward by one  
  124.                     // record to the next sequentially located record.  
  125.                     datafileoffset = datafileoffset + GLMASTERLEN;  
  126.   
  127.   
  128.   
  129.                 } while (datafileoffset < sizeofdatafile);  
  130.                 // close the Chart Of Accounts data file stream.  
  131.                 streamobj.Close();  
  132.   
  133.   
  134.                 // repaint the Windows form to reflect the changes.  
  135.                 UpdateListing();  
  136.   
  137.   
  138.             }  
  139.   
  140.         }  
  141.   
  142.     }  
  143.   
  144.   
  145.     else  
  146.     {  
  147.   
  148.         MessageBox.Show("No general ledger selection was made...please try again.""Error Mode");  
  149.   
  150.     }  
  151.   
  152.   
  153.   
  154. }  
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:
  1. private void AddSupplementalGL(object sender, EventArgs e)  
  2. {  
  3.     // declare local variables.  
  4.     int found_glno;  
  5.     long sizeofdatafile_supplemental;  
  6.     string glno_str, glname_str;  
  7.     char[] charVal_glno, charVal_glname;  
  8.   
  9.   
  10.     result = MessageBox.Show("Do you want to add a supplemental GL account to the current listing?""Verification Mode", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);  
  11.   
  12.     if (result == DialogResult.Yes)  
  13.     {  
  14.   
  15.   
  16.   
  17.         // get the file size of the supplemental cash disbursements  
  18.         // data file, 'cd_ledger.txt'.  
  19.         FileInfo datafileinfo_supplemental = new FileInfo(currdir + "cd_ledger.txt");  
  20.         sizeofdatafile_supplemental = datafileinfo_supplemental.Length;  
  21.   
  22.         // if the number of added supplemental general ledgers  
  23.         // for the current session is less than 5, then proceed.  
  24.         if (sizeofdatafile_supplemental < GLAUXILIARY * 5)  
  25.         {  
  26.   
  27.   
  28.   
  29.            // get the user entered supplemental general ledger # to add to   
  30.            // the Windows form listing.  
  31.            glno_str = AuxiliaryGLNo.Text;  
  32.   
  33.            // if the length of the user entered supplemental general  
  34.            // ledger # is 4, then proceed.  
  35.            if (glno_str.Length == 4)  
  36.             {  
  37.   
  38.   
  39.   
  40.                 // open a file stream to the Chart Of Accounts data file for  
  41.                 // subsequent read operations.  
  42.                 FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");  
  43.                 sizeofdatafile = datafileinfo.Length;  
  44.                 StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");  
  45.                 streamobj.BaseStream.Seek(0, SeekOrigin.Begin);  
  46.   
  47.   
  48.                 // initialize the Chart Of Accounts data file offset to 0.  
  49.                 // set the 'found_glno' flag to its default of 0 to indicate  
  50.                 // the general ledger # to search for is not yet found.  
  51.                 datafileoffset = 0;  
  52.                 found_glno = 0;  
  53.                 do  
  54.                 {  
  55.   
  56.   
  57.                     // read the next sequential record from the Chart Of Accounts data file.  
  58.                     stringVal = streamobj.ReadLine();  
  59.   
  60.   
  61.                     // if the user entered general ledger # has been matched in the Chart Of  
  62.                     // Accounts data file, then proceed.  
  63.                     if (stringVal.Substring(41, 4) == glno_str)  
  64.                     {  
  65.   
  66.   
  67.   
  68.                         // set the 'found_glno' flag to 1 to denote the user  
  69.                         // entered general ledger # has been matched.  
  70.                         found_glno = 1;  
  71.   
  72.   
  73.                         // construct a transient copy the corresponding general  
  74.                         // ledger filename from the Chart Of Accounts record and  
  75.                         // assign it to the variable, 'strfile_temp'.  
  76.                         strfile_temp = stringVal.Substring(45, 8) + "_.txt";  
  77.   
  78.                         // check to see if this transient general ledger filename  
  79.                         // already exists and if so, get rid of it.  
  80.                         if (File.Exists(currdir + strfile_temp))  
  81.                         {  
  82.                             File.Delete(currdir + strfile_temp);  
  83.                         }  
  84.   
  85.                         // clear out the character array, 'recordatavar_transactions',  
  86.                         // used for the supplemental general ledger file addition to the Windows form.  
  87.                         for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;  
  88.   
  89.                         // open a file stream to transient general ledger account filename specified  
  90.                         // by the user and then write the 'recordatavar_transactions' character  
  91.                         // array to it.  
  92.                         FileStream fstreamobj1 = new FileStream(currdir + strfile_temp, FileMode.Create);  
  93.                         StreamWriter writerobj1 = new StreamWriter(fstreamobj1);  
  94.                         writerobj1.WriteLine(recordatavar_transactions);  
  95.                         writerobj1.Close();  
  96.                         fstreamobj1.Close();  
  97.   
  98.   
  99.                         // add the supplemental general ledger # entered by the user as well as its  
  100.                         // descriptive name to character arrays.  
  101.                         charVal_glno = glno_str.ToCharArray(0, glno_str.Length);  
  102.                         glname_str = stringVal.Substring(0, 41);  
  103.                         charVal_glname = glname_str.ToCharArray(0, glname_str.Length);  
  104.   
  105.                         // add the above 2 items to the 'recordatavar_aux_ledger' character array.  
  106.                         for (a = 0; a < 45; a++) recordatavar_aux_ledger[a] = (char)32;  
  107.                         for (a = 0; a < 4; a++) recordatavar_aux_ledger[a] = charVal_glno[a];  
  108.                         for (a = 0; a < 41; a++) recordatavar_aux_ledger[a + 4] = charVal_glname[a];  
  109.   
  110.                         // open a file stream to the supplemental cash disbursements data file,  
  111.                         // and append the 'recordatavar_aux_ledger' character array to it.  
  112.                         FileStream fstreamobj2 = new FileStream(currdir + "cd_ledger.txt", FileMode.Append);  
  113.                         StreamWriter writerobj2 = new StreamWriter(fstreamobj2);  
  114.                         writerobj2.WriteLine(recordatavar_aux_ledger);  
  115.                         writerobj2.Close();  
  116.                         fstreamobj2.Close();  
  117.   
  118.   
  119.   
  120.                     }  
  121.   
  122.   
  123.   
  124.                     // advance the Chart Of Accounts data file offset forward by one  
  125.                     // record to the next sequentially located record.  
  126.                     datafileoffset = datafileoffset + GLMASTERLEN;  
  127.   
  128.   
  129.   
  130.                 } while (datafileoffset < sizeofdatafile && found_glno == 0);  
  131.                 // close the Chart Of Accounts data file stream.  
  132.                 streamobj.Close();  
  133.   
  134.   
  135.                 // reset the supplemental general ledger # control on the Windows form to blank.  
  136.                 this.AuxiliaryGLNo.Text = "";  
  137.   
  138.   
  139.                 // repaint the Windows form to reflect the changes.  
  140.                 UpdateListing();  
  141.   
  142.   
  143.                 if (found_glno == 0)  
  144.                 {  
  145.   
  146.                     MessageBox.Show("The GL number was not found and was not added to the current listing...please try again.""Error Mode");  
  147.   
  148.                 }  
  149.   
  150.   
  151.   
  152.             }  
  153.             else  
  154.             {  
  155.   
  156.                 MessageBox.Show("Invalid GL number...please try again.""Error Mode");  
  157.   
  158.             }  
  159.   
  160.   
  161.   
  162.         }  
  163.         else  
  164.         {  
  165.   
  166.             MessageBox.Show("Unable to add any more supplemental GL accounts...""Error Mode");  
  167.   
  168.         }  
  169.   
  170.   
  171.   
  172.     }  
  173.   
  174.   
  175. }  
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,

Verify the amounts
                                                                                       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).

Post the displayed
                                                                                    Figure 7

The code for this operation is shown here:
  1. private void PostToChartOfAccounts(object sender, EventArgs e)  
  2. {  
  3.     // declare local variables.  
  4.     string stringAutoNumber, strfile_orig, transaction_str;  
  5.     long autonum_var;  
  6.     char[] charVal_auto_number = new char[3];  
  7.     char[] put_in_orig_ledger, charVal_tranaction;  
  8.   
  9.   
  10.     // get current working directory.  
  11.     currdir = Directory.GetCurrentDirectory();  
  12.     currdir = currdir.Substring(0, currdir.Length - 9);  
  13.   
  14.   
  15.     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);  
  16.   
  17.     if (result == DialogResult.Yes)  
  18.     {  
  19.   
  20.         Cursor.Current = new Cursor(currdir + "Busy_l.cur");  
  21.   
  22.   
  23.         // auto generate the next general ledger transaction number in sequence  
  24.         // to be included with the permananet general ledger postings to be used  
  25.         // for future operations and save this in a small data file, 'autonumber.txt'.  
  26.         StreamReader streamobj3 = new StreamReader(currdir + "autonumber.txt");  
  27.         streamobj3.BaseStream.Seek(0, SeekOrigin.Begin);  
  28.         stringAutoNumber = streamobj3.ReadLine();  
  29.         streamobj3.Close();  
  30.   
  31.         for (a = 0; a < 3; a++)  
  32.         {  
  33.             convert_to_number[a] = 0;  
  34.             if (stringAutoNumber.Substring(a, 1) == "0") convert_to_number[a] = 0;  
  35.             if (stringAutoNumber.Substring(a, 1) == "1") convert_to_number[a] = 1;  
  36.             if (stringAutoNumber.Substring(a, 1) == "2") convert_to_number[a] = 2;  
  37.             if (stringAutoNumber.Substring(a, 1) == "3") convert_to_number[a] = 3;  
  38.             if (stringAutoNumber.Substring(a, 1) == "4") convert_to_number[a] = 4;  
  39.             if (stringAutoNumber.Substring(a, 1) == "5") convert_to_number[a] = 5;  
  40.             if (stringAutoNumber.Substring(a, 1) == "6") convert_to_number[a] = 6;  
  41.             if (stringAutoNumber.Substring(a, 1) == "7") convert_to_number[a] = 7;  
  42.             if (stringAutoNumber.Substring(a, 1) == "8") convert_to_number[a] = 8;  
  43.             if (stringAutoNumber.Substring(a, 1) == "9") convert_to_number[a] = 9;  
  44.         }  
  45.         autonum_var = ((convert_to_number[0] * 100) + (convert_to_number[1] * 10) + (convert_to_number[2] * 1));  
  46.         autonum_var++;  
  47.         if (autonum_var > 999)  
  48.         {  
  49.             autonum_var = 0;  
  50.         }  
  51.   
  52.         for (a = 0; a < 3; a++) charVal_auto_number[a] = (char)48;  
  53.         countervar = 2;  
  54.         do  
  55.         {  
  56.             longresult = Math.DivRem(autonum_var, 10, out long2);  
  57.             autonum_var = longresult;  
  58.             if (long2 == 0) charVal_auto_number[countervar] = (char)48;  
  59.             if (long2 == 1) charVal_auto_number[countervar] = (char)49;  
  60.             if (long2 == 2) charVal_auto_number[countervar] = (char)50;  
  61.             if (long2 == 3) charVal_auto_number[countervar] = (char)51;  
  62.             if (long2 == 4) charVal_auto_number[countervar] = (char)52;  
  63.             if (long2 == 5) charVal_auto_number[countervar] = (char)53;  
  64.             if (long2 == 6) charVal_auto_number[countervar] = (char)54;  
  65.             if (long2 == 7) charVal_auto_number[countervar] = (char)55;  
  66.             if (long2 == 8) charVal_auto_number[countervar] = (char)56;  
  67.             if (long2 == 9) charVal_auto_number[countervar] = (char)57;  
  68.             countervar--;  
  69.         } while (autonum_var > 0);  
  70.   
  71.         if (File.Exists(currdir + "autonumber.txt"))  
  72.         {  
  73.             File.Delete(currdir + "autonumber.txt");  
  74.         }  
  75.   
  76.         FileStream fstreamobj2 = new FileStream(currdir + "autonumber.txt", FileMode.Create);  
  77.         StreamWriter writerobj2 = new StreamWriter(fstreamobj2);  
  78.         writerobj2.WriteLine(charVal_auto_number);  
  79.         writerobj2.Close();  
  80.         fstreamobj2.Close();  
  81.   
  82.   
  83.   
  84.         // open a file stream to the Chart Of Accounts data file for  
  85.         // subsequent read operations.  
  86.         FileInfo datafileinfo = new FileInfo(currdir + "mastcoa.txt");  
  87.         sizeofdatafile = datafileinfo.Length;  
  88.         StreamReader streamobj = new StreamReader(currdir + "mastcoa.txt");  
  89.         streamobj.BaseStream.Seek(0, SeekOrigin.Begin);  
  90.   
  91.         // open a file stream to the supplemental cash disbursements data file,  
  92.         // 'cd_ledger.txt', for subsequent read operations.  
  93.         FileInfo datafileinfo_auxiliary = new FileInfo(currdir + "cd_ledger.txt");  
  94.         sizeofdatafile_auxiliary = datafileinfo_auxiliary.Length;  
  95.         StreamReader streamobj_auxiliary = new StreamReader(currdir + "cd_ledger.txt");  
  96.   
  97.         // initialize the Chart Of Accounts data file offset to 0.  
  98.         datafileoffset = 0;  
  99.         do  
  100.         {  
  101.   
  102.   
  103.             // read the next sequential record from the Chart Of Accounts data file.  
  104.             stringVal = streamobj.ReadLine();  
  105.   
  106.             // extract the transient general ledger file name from the just read  
  107.             // Chart Of Accounts record and assign it to the transient general ledger  
  108.             // filename, 'strfile_temp'.  
  109.             strfile_temp = stringVal.Substring(45, 8);  
  110.             strfile_temp = strfile_temp + "_.txt";  
  111.             // extract the permanent general ledger file name from the just read  
  112.             // Chart Of Accounts record and assign it to the permanent general ledger  
  113.             // filename, 'strfile_orig'.  
  114.             strfile_orig = stringVal.Substring(45, 8);  
  115.             strfile_orig = strfile_orig + ".txt";  
  116.   
  117.   
  118.             // match the general ledger # of the current record from the Chart Of  
  119.             // Accounts data file stream to one of those from the listing  
  120.             // in the Windows form and set a flag, 'calc_flag', upon matching it.  
  121.             calc_flag = 0;  
  122.   
  123.             if (stringVal.Substring(41, 4) == "1000")  
  124.             {  
  125.                 calc_flag = 1;  
  126.             }  
  127.             if (stringVal.Substring(41, 4) == "1010")  
  128.             {  
  129.                 calc_flag = 1;  
  130.             }  
  131.             if (stringVal.Substring(41, 4) == "1040")  
  132.             {  
  133.                 calc_flag = 1;  
  134.             }  
  135.             if (stringVal.Substring(41, 4) == "1070")  
  136.             {  
  137.                 calc_flag = 1;  
  138.             }  
  139.             if (stringVal.Substring(41, 4) == "1080")  
  140.             {  
  141.                 calc_flag = 1;  
  142.             }  
  143.             if (stringVal.Substring(41, 4) == "2100")  
  144.             {  
  145.                 calc_flag = 1;  
  146.             }  
  147.             if (stringVal.Substring(41, 4) == "2110")  
  148.             {  
  149.                 calc_flag = 1;  
  150.             }  
  151.             if (stringVal.Substring(41, 4) == "2120")  
  152.             {  
  153.                 calc_flag = 1;  
  154.             }  
  155.             if (stringVal.Substring(41, 4) == "2160")  
  156.             {  
  157.                 calc_flag = 1;  
  158.             }  
  159.             if (stringVal.Substring(41, 4) == "2210")  
  160.             {  
  161.                 calc_flag = 1;  
  162.             }  
  163.             if (stringVal.Substring(41, 4) == "2400")  
  164.             {  
  165.                 calc_flag = 1;  
  166.             }  
  167.             if (stringVal.Substring(41, 4) == "3030")  
  168.             {  
  169.                 calc_flag = 1;  
  170.             }  
  171.             if (stringVal.Substring(41, 4) == "4200")  
  172.             {  
  173.                 calc_flag = 1;  
  174.             }  
  175.             if (stringVal.Substring(41, 4) == "4400")  
  176.             {  
  177.                 calc_flag = 1;  
  178.             }  
  179.             if (stringVal.Substring(41, 4) == "5000")  
  180.             {  
  181.                 calc_flag = 1;  
  182.             }  
  183.             if (stringVal.Substring(41, 4) == "6500")  
  184.             {  
  185.                 calc_flag = 1;  
  186.             }  
  187.             if (stringVal.Substring(41, 4) == "7300")  
  188.             {  
  189.                 calc_flag = 1;  
  190.             }  
  191.             if (stringVal.Substring(41, 4) == "7400")  
  192.             {  
  193.                 calc_flag = 1;  
  194.             }  
  195.             if (stringVal.Substring(41, 4) == "8200")  
  196.             {  
  197.                 calc_flag = 1;  
  198.             }  
  199.             if (stringVal.Substring(41, 4) == "8300")  
  200.             {  
  201.                 calc_flag = 1;  
  202.             }  
  203.             if (stringVal.Substring(41, 4) == "9100")  
  204.             {  
  205.                 calc_flag = 1;  
  206.             }  
  207.   
  208.   
  209.             // attempt to match the general ledger # of the current record from the Chart Of  
  210.             // Accounts to any of the general ledger #'s in the supplemental cash disbursements  
  211.             // data file, and set a flag, 'calc_flag', upon matching it.  
  212.             streamobj_auxiliary.BaseStream.Seek(0, SeekOrigin.Begin);  
  213.             datafileoffset_auxiliary = 0;  
  214.             do  
  215.             {  
  216.   
  217.                 stringVal_auxiliary = streamobj_auxiliary.ReadLine();  
  218.   
  219.                 if (stringVal.Substring(41, 4) == stringVal_auxiliary.Substring(0, 4))  
  220.                 {  
  221.                     calc_flag = 1;  
  222.                     auxiliary_ledger_count++;  
  223.                 }  
  224.   
  225.                 datafileoffset_auxiliary = datafileoffset_auxiliary + GLAUXILIARY;  
  226.   
  227.             } while (datafileoffset_auxiliary < sizeofdatafile_auxiliary);  
  228.   
  229.   
  230.   
  231.             // if the general ledger # of the current record from the Chart Of  
  232.             // Accounts has been matched and the transient general ledger file,  
  233.             // 'strfile_temp', does exist, then proceed.  
  234.             if (calc_flag == 1 && File.Exists(currdir + strfile_temp))  
  235.             {  
  236.   
  237.   
  238.   
  239.                 // open a file stream to the transient general ledger file,  
  240.                 // 'strfile_temp', for subsequent read operations.  
  241.                 FileInfo datafileinfo2 = new FileInfo(currdir + strfile_temp);  
  242.                 sizeofdatafile2 = datafileinfo2.Length;  
  243.                 StreamReader streamobj2 = new StreamReader(currdir + strfile_temp);  
  244.                 streamobj2.BaseStream.Seek(0, SeekOrigin.Begin);  
  245.   
  246.                 // initialize the transient general ledger filename, 'strfile_temp', offset to 0.  
  247.                 datafileoffset2 = 0;  
  248.                 do  
  249.                 {  
  250.   
  251.   
  252.                     // read a sequential record from the transient general ledger data file.  
  253.                     stringVal = streamobj2.ReadLine();  
  254.   
  255.   
  256.                     // if there are a debit and/or credit amount(s) in the 'stringVal' variable,  
  257.                     // then proceed with appending the amount(s) to the permanent general ledger  
  258.                     // data file.  
  259.                     if (stringVal.Substring(50, 10) != "          " || stringVal.Substring(60, 10) != "          ")  
  260.                     {  
  261.   
  262.   
  263.                         // set the transaction description to 'CD Transaction' and convert it to a   
  264.                         // character array. assign the current record from the transient general ledger  
  265.                         // data file, 'strfile_temp', to a character array.  
  266.                         transaction_str = "CD Transaction";  
  267.                         charVal_tranaction = transaction_str.ToCharArray(0, transaction_str.Length);  
  268.                         put_in_orig_ledger = stringVal.ToCharArray(0, stringVal.Length);  
  269.   
  270.                         // clear out the character array used for the posting operation to the permanent   
  271.                         // general ledger data file.  
  272.                         for (a = 0; a < GLDETAILEN - 2; a++) recordatavar_transactions[a] = (char)32;  
  273.   
  274.                         // assign record from the transient general ledger data file to the  
  275.                         // 'recordatavar_transactions' character array as well as 'CD' for  
  276.                         // the transaction type and the transaction description and also the  
  277.                         // auto generated transaction number.  
  278.                         for (a = 0; a < stringVal.Length; a++) recordatavar_transactions[a] = put_in_orig_ledger[a];  
  279.                         recordatavar_transactions[8] = 'C';  
  280.                         recordatavar_transactions[9] = 'D';  
  281.                         for (a = 0; a < transaction_str.Length; a++) recordatavar_transactions[a + 10] = charVal_tranaction[a];  
  282.                         for (a = 0; a < 3; a++) recordatavar_transactions[a + 70] = charVal_auto_number[a];  
  283.   
  284.                         // append the above mentioned data in the 'recordatavar_transactions' character array  
  285.                         // to the permanent general ledger file.  
  286.                         FileStream fstreamobj1 = new FileStream(currdir + strfile_orig, FileMode.Append);  
  287.                         StreamWriter writerobj1 = new StreamWriter(fstreamobj1);  
  288.                         writerobj1.WriteLine(recordatavar_transactions);  
  289.                         writerobj1.Close();  
  290.                         fstreamobj1.Close();  
  291.   
  292.   
  293.                     }  
  294.   
  295.   
  296.                     // advance the supplemental cash disbursements data file offset forward by one  
  297.                     // record to the next sequentially located record.  
  298.                     datafileoffset2 = datafileoffset2 + GLDETAILEN;  
  299.   
  300.   
  301.                 } while (datafileoffset2 < sizeofdatafile2);  
  302.                 // close the file stream for the transient general ledger data file.  
  303.                 streamobj2.Close();  
  304.   
  305.   
  306.   
  307.                 // if the transient general ledger data file exists,  
  308.                 // then get rid of it since it is no longer needed.  
  309.                 if (File.Exists(currdir + strfile_temp))  
  310.                 {  
  311.                     File.Delete(currdir + strfile_temp);  
  312.                 }  
  313.   
  314.   
  315.   
  316.             }  
  317.   
  318.   
  319.   
  320.             // advance the Chart Of Accounts data file offset forward by one  
  321.             // record to the next sequentially located record.  
  322.             datafileoffset = datafileoffset + GLMASTERLEN;  
  323.   
  324.   
  325.   
  326.         } while (datafileoffset < sizeofdatafile);  
  327.         // close the file stream for the supplemental cash disbursements data file.  
  328.         streamobj_auxiliary.Close();  
  329.         // close the Chart Of Accounts data file stream.  
  330.         streamobj.Close();  
  331.   
  332.   
  333.         // if the supplemental cash disbursements data file exists, then  
  334.         // get rid of it and recreate a new one with a blank record.  
  335.         if (File.Exists(currdir + "cd_ledger.txt"))  
  336.         {  
  337.             File.Delete(currdir + "cd_ledger.txt");  
  338.   
  339.             for (a = 0; a < 45; a++) recordatavar_aux_ledger[a] = (char)32;  
  340.   
  341.             FileStream fstreamobj_auxiliary = new FileStream(currdir + "cd_ledger.txt", FileMode.Create);  
  342.             StreamWriter writerobj_auxiliary = new StreamWriter(fstreamobj_auxiliary);  
  343.             writerobj_auxiliary.WriteLine(recordatavar_aux_ledger);  
  344.             writerobj_auxiliary.Close();  
  345.             fstreamobj_auxiliary.Close();  
  346.   
  347.         }  
  348.   
  349.   
  350.   
  351.         // repaint the Windows form to reflect the changes.  
  352.         UpdateListing();  
  353.   
  354.   
  355.   
  356.         Cursor.Current = Cursors.Default;  
  357.   
  358.   
  359.     }  
  360.   
  361.   
  362. }  
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.