Julie MacAller
Microsoft Corporation
January 1999
The Island Hopper News application is an automated classified ads system created by a fictitious company, Island Hopper Publishing, as a test project to evaluate converting the current paper-based weekly newspaper into an online newspaper. The design team consists of the Island Hopper News editor, the Classified Ads and Accounting department heads, and two developers.
This paper describes how the code for the account activity function in the Island Hopper News application fits together and how it works.
The Account Activity function provides a way for Island Hopper Publishing employees to view invoices and payments for a customer. Employees need to retrieve a customer record from the database before viewing account activity.
Island Hopper Publishing employees view account activity by starting the Island Hopper Publishing Microsoft® Windows-based client and selecting the Account Activity function.
Viewing account activity uses the bus_CustomerC and bus_InvoiceC business components and the db_CustomerC, db_CustomerPasswordC, db_InvoiceC and db_PaymentC data access components.
These components expose the following methods:
Component | Methods |
bus_CustomerC | Add, GetByEmail, IbusCustomerChange_Add, IbusCustomerChange_Delete, IbusCustomerChange_Update, IbusCustomerLookup_GetByEmail, IbusCustomerLookup_GetByID, IbusCustomerLookup_ListByLastName, Validate |
bus_InvoiceC | AddHeader, AddDetail, GetByID, GetByCustID |
db_CustomerC | IcustomerChange_Add, IcustomerChange_Delete, IcustomerChange_Update, ICustomerLookup_GetByEmail, ICustomerLookup_GetByID, ICustomerLookup_ListByLastName, UpdateBalance |
db_CustomerPasswordC | IcustomerPasswordChange_Add, IcustomerPasswordChange_Delete, IcustomerPasswordChange_Update, ICustomerPasswordLookup_GetByID |
db_InvoiceC | AddDetail, AddHeader, GetByCustID, GetByID, GetDetailByID |
db_PaymentC | AddPayment, GetByCustID |
Employees start the Island Hopper Publishing Windows-based client by clicking the Start menu, pointing at Programs, pointing at Island Hopper, and selecting Island Hopper C. The application's main screen is displayed. Employees then click Account Activity to view the Account Activity form (frmInvoiceC), where they can retrieve a customer record from the database, view invoice details, and see a list of payments made by the customer.
The following figure shows the Account Activity form.
If employees double-click a particular invoice, they see the Invoice Details form, shown in the following figure.
From a developer's point of view, there are three main parts to the account activity process:
Each of these parts is discussed in this white paper.
After an employee accesses the Account Activity screen, he or she needs to retrieve a customer record from the database. Employees can retrieve records using the customer ID or e-mail address; they can also search for a customer by last name and select the appropriate customer record from the returned list. If an employee knows the invoice number, he or she can type it into the Invoice ID field and press Enter; however, the form will display the Customer Search form, and the employee will need to retrieve the customer by last name. Each retrieval method is described later in this document.
All customer maintenance operations require the retrieval of a customer record from the database. Even the Add operation attempts to retrieve a customer record containing the customer information in the form to make sure it doesn't already exist. Although retrieving by customer ID and retrieving by e-mail address are nearly identical operations, retrieving by last name is a little different, so it is described separately.
The retrieval operation starts when the customer clicks the appropriate button on the Account Activity form (cmdRetrieveID, cmdRetrieveEmail, or cmdSearchCustomer).
When a customer requests the retrieval of a customer record by ID or e-mail address, the following process occurs in the code:
If the rsCustomer recordset is empty, the retrieval method displays a message that no customer record was found and calls the cmdCancel_Click procedure to clear the form fields and prepare the form for the next operation.
If the rsCustomer recordset contains a record, the retrieval method fills the Customer ID, Email, First Name, and Last Name fields with the information from the rsCustomer recordset.
When an employee requests the retrieval of a customer record by last name, the following process occurs:
At this point, the employee types in the last name, if it isn't already present, and clicks the Search button, which calls the cmdSearch_Click procedure.
If the rsCustomer Recordset is empty, the cmdSearch_Click procedure displays a message that no customer was found.
If the rsCustomer Recordset is not empty, the cmdSearch_Click procedure loops through the Recordset to fill the lstCustomers listbox control with name and e-mail address for each retrieved customer and saves the customer ID numbers in an array for easy retrieval when the employee selects a customer record to work with.
Employees can now click the customer they want and then click Retrieve or double-click on the customer they want (which has the same effect). Clicking Retrieve calls cmdRetrieve_Click, which calls lstCustomers_DblClick; double-clicking a customer also calls lstCustomers_DblClick.
Now, the selected customer record is retrieved from the database using the get by customer ID retrieval method.
After retrieving the customer from the database, the cmdRetrieveEmail or cmdRetrieveID procedures call the FillFields procedure to fill the customer information text fields with information about the customer. After filling the customer information text fields, the FillFields procedure calls the FillInvoiceList procedure to populate the list of invoices and payments (a grid control). Processing for this stage consists of the following steps:
These steps are described later in this document.
In this step, the FillInvoiceList procedure uses the bus_InvoiceC component to retrieve a list of the invoices for this customer from the database. The following steps summarize the process.
The bus_InvoiceC component is marked as "requires a transaction," so it enlists in the current transaction.
The db_InvoiceC component is marked as "requires a transaction," so it enlists in the current transaction.
In this step, the FillInvoiceList procedure uses the db_PaymentC component to retrieve a list of the payments made by this customer from the database. The following steps summarize the process.
In this step, the grid control that contains the list of invoices and payments is populated. As long as there is at least one invoice or payment for the customer, the grid control will be populated. The FillInvoiceList procedure contains code to handle adding payment information if there are no more invoices or vice versa.
The FillInvoiceList procedure in frmInvoiceC.frm first checks both returned recordsets—the one containing invoices and the one containing payments—to make sure that at least one invoice or payment is found and then starts a loop to begin populating the grid.
The loop moves through the recordsets containing the invoices and payments until it reaches the end of each recordset. It writes each invoice and payment to a separate row in the grid. Invoices and payments are written by date, with invoices first.
Two procedures, AddPaymentRow and AddInvoiceRow, do the work of adding a row and populating it with the appropriate information.
The FillInvoiceList procedure in frmInvoiceC.frm includes code that handles adding payments when there are no more invoices and vice versa. The following steps summarize this process.
When the loop reaches the end of both recordsets, the FillInvoiceList procedure sets some display properties on the grid control, gives it focus, cleans up the recordsets, and exits.
After the grid control has been populated, employees can double-click any invoice to view details about it. Available details include the invoice number and date, as well as the IDs and descriptions of the ads on that invoice.
Double-clicking a particular invoice triggers the flxInvoiceList_dblClick procedure in frmInvoiceC.frm. This procedure does the following:
Showing the Invoice Details form triggers the Form_Load and Form_Activate procedures in frmInvoiceDetailsC. The Form_Load procedure creates an instance of the data access component, db_InvoiceC, which is used to get invoice details from the database.
The db_InvoiceC component is marked as "requires a transaction," so it enlists in the current transaction.
The Form_Activate procedure calls the RetrieveDetails procedure (also in frmInvoiceDetailsC) to get the details for the invoice using the db_InvoiceC object.
The RetrieveDetails procedure contains the following steps:
These steps are described later in this document.
This step consists of resetting several properties on the grid control that contains the invoice details.
In this step, the RetrieveDetails procedure in frmInvoiceDetailC calls the GetByID method of the db_InvoiceC object to retrieve the information about the selected invoice from the database. The GetByID method of the db_InvoiceC object does the following:
In this step, the RetrieveDetails procedure in frmInvoiceDetailC calls the GetDetailByID method of the db_InvoiceC object to retrieve details—that is, the IDs and descriptions of the ads—for the selected invoice. The GetDetailByID method does the following:
In this step, the RetrieveDetails procedure in frmInvoiceDetailC loops through the recordsets containing the invoice and invoice details information and writes each ad ID and description to a separate row in the grid control. When the code reaches the end of the recordsets, it exits the loop, disables the Next or Previous buttons if necessary, and exits the procedure.
Note If the invoice for which details are being displayed is the first or last invoice in the list on frmInvoiceC, the RetrieveDetails procedure in frmInvoiceDetailC disables the Previous or Next buttons, respectively, on the Invoice Details form. Employees can use these buttons to move through the list of invoices, displaying details on each one.