As a general purpose framework, GenHelm is not intended to provide extensive accounting features. The extent of the features you will require will largely depend on the volume of transactions your store will be processing and whether you plan to extend credit to your customers. Let's review some considerations before we describe GenHelm's components related to account management.

Credit Support

If you do not plan to offer credit to your customers, you likely don't need support for any sort of accounting system. Your payment gateway provider will most likely be able to provide you with information about all payments that have been processed. You can use information from your provider to determine when payments have been made so that you know when to ship your products. On the other hand, if you plan to offer credit to your customers you will need a way to keep track of customer account balances.

Transaction Volume

For stores with low online sales volumes, you also may not need any additional accounting processes since you can manually enter sales into whatever accounting system you use to manage your business. For high volume stores you will need a way to manage accounts or integrate your web sales system into your corporate accounting system. Perhaps your system offers an API that can easily be called from the programs used to manage your web store.

Payment Processor

Some payment processors, such as Stripe, offer fairly comprehensive portals and APIs to keep track of your customer data, manage accounts, send invoices, etc. If you don't want to build these types of services as part of your online store, you should consider using one of these comprehensive payment processors. Be sure to pay close attention to the fees charged by these providers since they are often higher than what is charged by more basic processors. If your products are subject to high rates of return be aware that some processors do not refund fees collected on refunded items. For example, if you sell an item for say $300, you will generally have to pay your Payment Processor say about $10 - 12. If the item is returned, not only don't you make any money on the sale but you are also burdened with the cost of the transaction fees if your provider does not refund these.

GenHelm Account Management

The accounting functions offered by GenHelm allow you to keep track of a customer's transaction and balance using a simple tab-delimited text file per account. Typically, you would store these text files under names that coincide with your customer's email addresses or other identifier. As we showed when storing customer data, we recommend dividing accounts into folders based on the first digit of the file name to increase the number of accounts you can store before folders become large and unwieldy. Generally speaking, this system is not intended to manage more than say 50,000 accounts. This is to avoid having the number of files within individual folders reach more than a few thousand files since, when doing so, it can become difficult to work with these folders using FileZilla and other FTP clients.

Instantiating the Account Manager Class

The account manager class is named transaction_manager and resides in the classes/text_cart folder. Therefore we can use the following code to instantiate this class:

// Instantiate the transaction manager and identify the account we want to work with
$this->trans = $this->site->create_object('transaction_manager','',false,'text_cart');
$this->trans->set_email($email);

Accounts are stored in files whose names are derived from our customer's email address so we need to set this value whenever we use this class.

Recording a Sale

In most cases you will want to add an invoice to your customer's account near the end of the checkout process, once the user has confirmed that they want to proceed to pay for their items. If you are using the transaction model to manage the screen navigation during the checkout sequence you will normally have a Validation Class associated with the transaction. This class should define a method named final_checkout_processing. This method is automatically called when the user clicks the transaction_next (or transaction_last) button on the last form of the transaction. Here we see an example of such a function.

function final_checkout_processing() {
  // Use session variables for the information that will be needed to process the credit card payment.
  // 
  // Generate the next invoice number. First invoice will be 100001.
  $_SESSION['invoice_number'] = $this->site->dollar_function('nextnum','next_invoice_number',100001,1);
  $_SESSION['invoice_description'] = 'Heavy Duty Tarps invoice '.$_SESSION['invoice_number'];
  $_SESSION['invoice_paid'] = $_SESSION['invoice_number'];
  //
  // Get the amounts to be invoiced from the cart object (stored in the session)  	  	
  $cart = $this->site->create_object('cart','',true);
  $currency = $cart->get_currency_code();
  $total = $cart->get_cart_total();
  $_SESSION['invoice_total'] = $total;
  $_SESSION['invoice_total_formatted'] = $cart->get_cart_total(true);
  $_SESSION['invoice_currency'] = $cart->get_currency_code();
  $other['products'] = $cart->get_cart_subtotal();
  $other['taxes'] = $cart->get_fee('gst');
  $other['shipping'] = $cart->get_items_total('type','shipping');
  $other['description'] = $_SESSION['invoice_description'];
  //
  // Add the invoice to the user's account file
  $this->trans = $this->site->create_object('transaction_manager','',false,'text_cart');
  $this->trans->set_email($_SESSION['email']);
  if ($this->trans->add_invoice($currency,$_SESSION['invoice_number'],$total,$other)) {
      return true;
  }
  else {
      $this->trans->transfer_your_messages_to_me($this); 
      return false; // There was a problem, don't continue other transaction components like emails
  }
}

Make note of the following features illustrated in the above code:

  1. Normally, the transaction (used to manage navigation) will redirect the user to the payment page after successfully adding the invoice transaction. Therefore, we use session variables to store any information, such as the invoice number and amount to be paid, that will be required by the payment process.
  2. Most of the values needed to write our invoice transaction are already stored within the cart object. Therefore, we need to load the cart object from the session and use cart methods to fetch the values we require.
  3. The last parameter of the add_invoice method is an optional keyed array of additional values. This array may define the following keys:
Key ValueDescription
productsThe total invoice amount associated with products (before taxes and fees).
servicesThe invoice amount associated with services.
shippingAny shipping charges associated with the invoice.
miscOther miscellaneous charges.
taxesThe taxes that were applied to the invoice.
description The invoice description.
costYour cost of goods sold for the items on this invoice.
userThe user who saved this invoice.

Note that the charges defined in the other array must be included in the supplied total parameter.

Recording a Payment

Payments are normally performed in a callback class that is called by the payment process after a payment has been successfully applied.

To record a payment, use the process_payment class found within classes/text_cart. The following code shows how this class can be used:

$invoice = $this->invoice;  // This can be an array if payment is for multiple invoices
$other['payment_fee'] = $this->fees; 
$other['user'] = $this->user; 
$record_payment = $this->site->create_object('process_payment','',false,'text_cart');
$record_payment->set_required_fields($this->email,$this->payment,$this->currency,
                                     $invoice,$this->payment_method,$other);
$result = $record_payment->process_payment();
if ($result === false) {
	$this->message = $record_payment->obtain_message(true,true);
	return false;
}
return true;

When processing payments, the optional other array parameter can define the following keys:

payment_fee Fees associated with the payment such as PayPal charges.
trans_idIf your credit card process returns a transaction Id, this can be added to the payment record.
auth_codeIf your credit card processor returns an authorization code, this can be added to the payment record.
userUse this field when adding manual payments to show the id of the staff member who applied the payment.

Other Accounting Transactions

In most cases, invoices and payments are the only types of transactions that are added programmatically. For other types of transactions GenHelm offers a page named invoice_admin/dashboard. This page is defined within the system pseudo site so it can be inherited by any site. This page can only be accessed by users who are logged in and who belong to the group named staff and the role admin.

User setting to allow access to Invoice Admin functions

Here we show an example of the invoice_admin/dashboard page.

Sample Order Admin page

To use this function you begin by entering an invoice number of interest and then click the Load Invoice button. At this point you can use the other buttons to

Note that these options only change the customer's account balances. No actual monetary transactions take place. Typically you would first refund a customer using your Payment Gateway's portal then you would use the Issue Refund option to record the fact that the refund was paid.

Correcting Email Addresses

In the above invoice example the user mistyped their email address when placing their order. This is a fairly common problem so we need a method of correcting the names of the files that are derived from the customer's email address as well as order logs and other files that refer to the email address.

We can click on the Correct Email Address option to correct this. Doing so will present the following form:

Email correction form

After clicking the Submit button we will see a series of messages showing what updates are performed. In this example, there was a problem sending the customer a copy of their order using the new email address. This is because there is no SMTP server running in the current environment.

Change Email Address Results

Integrating with the Invoice Dashboard

The dashboard page requires certain components to be implemented within the current site to provide data and processing necessary to complete certain functions. In this section we review the components that you are required to implement.

php_class invoice_admin/invoice_api

To create this class begin by launching the the php_class model. Next issue the commands:

example invoice_api
stow invoice_admin/invoice_api

This will create a class named invoice_api within the classes/invoice_admin folder. You will need to change several things within this class then you can re-stow it to save the changes. Let's go through the things that you will need to change.

Order Summary Columns

In the properties section you will find a column definition such as the following:

Order summary column definition

By default, all order data will be saved in a tab-delimited file named orders.txt. You will need to decide what information you want to save in this file. This will depend on what your website sells and what information you want to track. Typically this won't contain details about order items but high-level information about the customer, shipping address, order total, taxes, etc.  Before deciding on this list of fields you should first build your checkout forms since you will normally use the same field names on your forms as column names in the array definition shown above. In addition to the form fields, you will normally capture standard fields such as the date, time, user's IP address, etc.

Writing a New Invoice Record

There are two main ways that you can write new rows to your order file.

  1. Using the Save Reports Option on Your Checkout Transaction
  2. By Defining a Method Within Your Invoice API Class

We showed option 1 in this help page. Option 2 involves adding a method to your invoice_admin/invoice_api class that looks similar to the following:

function save_invoice($invoice_number, $value) {
  foreach (self::$column_names as $key) {
      if (isset($value[$key])) {
          $data[$key] = $value[$key];
      }
  }
  $data['date'] = $this->site->dollar_function('date',null,null,'yyyy-mm-dd');
  $data['time'] = $this->site->dollar_function('time',null,null,'12:mm ap');
  $data['ip'] = $this->site->dollar_function('server','REMOTE_ADDR');
  $data['geo'] = $this->site->dollar_function('geoloc');
  $data['tld'] = $this->site->dollar_function('site','tld'); // Top level domain
  $data['invoice_number'] = $invoice_number;
  if($this->save_record($data) == false) {
      trigger_error('Error saving invoice '.$invoice_number,E_USER_WARNING);
      return false;
  }
  return true;
}

The save_invoice method of your invoice API is normally called from final_checkout_processing method in the Checkout Validation class linked to your checkout transaction. Here is some sample code that shows how to call the save_invoice function.

$_SESSION['invoice_number'] = $this->site->dollar_function('nextnum','next_invoice_number',20143,1);
//
// Get the amounts to be invoiced from the cart object (stored in the session)  	  	
$cart = $this->site->create_object('cart','',true);
$data['currency'] = $cart->get_currency_code();
$data['invoice_total'] = $cart->get_cart_total();
$data['invoice_subtotal'] = $cart->get_cart_subtotal();
$data['taxes'] = $cart->get_fee('gst');
// Get form values from the session
$data['company_name'] = $_SESSION['company_name'];
$data['company_phone'] = $_SESSION['company_phone'];
$data['website'] = $_SESSION['website'];
$data['address'] = $_SESSION['address'];
$data['suite'] = $_SESSION['suite'];
$data['city'] = $_SESSION['city'];
$data['state'] = $_SESSION['state'];
$data['country'] = $_SESSION['country'];
$data['zip_code'] = $_SESSION['zip_code'];
$data['named_developers'] = $_SESSION['named_developers'];
$data['first_name'] = $_SESSION['first_name'];
$data['last_name'] = $_SESSION['last_name'];
$data['title'] = $_SESSION['title'];
$data['phone'] = $_SESSION['phone'];
$data['email'] = $_SESSION['email'];
//
// Add the invoice to the user's account file
$invoice_api = $this->site->create_object('invoice_api','',false,'invoice_admin');
return $invoice_api->save_invoice($_SESSION['invoice_number'],$data);

Correcting Email Addresses

As we have shown, your invoice API will most likely need a way to correct a mistyped email address entered by your customer. This requires two functions:

The change_email_address function will be called by the admin framework passing it the invoice number and the incorrect email address and the correct email address. This function should call the update_file method of the output_file_class. This method is pass an object and a method to which a callback should be performed. In this example, the callback function is named change_email. This callback function can also be passed a parameter that you pass to the output_file_class. In other words we have the following call sequence:

correct_email_address Form Handler → change_email_address → output_file_class → change_email

We show this functionality below.


function change_email_address($invoice_number, $old_email, $new_email){
  $change[] = array('from' => "\t".$old_email."\t",
                    'to'  => "\t".$new_email."\t",
                    'file' => $this->get_short_filename(false));
  $change[] = array('from' => $old_email,
                    'to'  => $new_email,
                    'file' =>$this->get_invoice_filename($invoice_number,false));
  $file_handler = $this->site->create_object('output_file_class');
  $return = true;
  foreach ($change as $info) {
      $success = false;
      if ($file_handler->set_filename($info['file'])) {
          if ($file_handler->update_file($this,'change_email',$info)) {
            $success = true;
          }
      }
      if (!$success) {
           $this->assign_message('!invoice_admin',1013,$info['file'],'Unable to update :1:',__LINE__.' '.__CLASS__);
           $return = false;
      }
  }
  return $return;
}
function change_email($original_contents, $change_info){
	$count = 0;
 	$new_contents = str_replace($change_info['from'],$change_info['to'],$original_contents,$count);
 	if ($count === 0){
		$this->assign_message('!invoice_admin',1008,array($change_info['from'],$change_info['file']),
                              'No occurrences of :1: were found in :2:',__LINE__.' '.__CLASS__);
		return false;
 	}
	$this->assign_message('!invoice_admin',1103,
                          array($count,$change_info['from'],$change_info['to'],$change_info['file']),
                          ':1: occurrences of :2: were successfully changed to :3: in :4:.',__LINE__.' '.__CLASS__);
	return $new_contents;
}

You can see that the code is used to update two separate files. One will be the orders.txt file and the other file is the html files used to save the contents of the order.

Sending Orders Via Email

Normally order emails are sent to the customer using the mailform feature of the checkout transaction. If the user supplied an invalid email address, it will be necessary to resend the order to the customer as part of the email correction process. This is done by calling the invoice API's email_invoice_to_customer method. If you plan to use this method you will need to change the following lines in the supplied example code:

$sales_email = 'sales@YOURCOMPANY.com';
$sales_name = 'YOUR COMPANY NAME';

Getting the Email Address Associated with an Order

When the dashboard page loads an invoice it makes a call to the invoice API's get_invoice_customer method. This method is responsible for returning the email address associated with an order. It can do this by reading the order.txt file but this file can get rather large if you have a lot of orders. An alternative method of obtaining the email address is to parse the generated order HTML and extract the invoice number from there. This extraction method will depend on the format of the invoices you create. Here is an example of the code that you will need to adapt to your invoice structure.

$contents = file_get_contents($filename);
$search_for = 'Email:</td><td >'; // Search for the email label in your invoice
$pos = strpos($contents,$search_for);
if ($pos) {
  $email_start = $pos + strlen($search_for);
  $email = substr($contents,$email_start,100);
  $end = strpos($email,'<');
  $this->email = substr($email,0,$end);
  return $this->email;
}
else {
  $this->assign_message('!invoice_admin',1009,$filename,'Could not fild email address in :1:',__LINE__.' '.__CLASS__);
  return false;
}

Cancelling Invoices

If you need to send a notice to certain departments, such as your billing, production or shipping departments, when an invoice is cancelled this would be done in the cancel_invoice method of the invoice API. In addition to the invoice number, this method is passed an array that may contain the following keys:

userThe user who issued the cancel request
reason 
The reason that the order was cancelled

Paying Invoices

Invoices can be paid directly by the customer using a credit card. This can be done at the time of checkout or later using the bill-payment form. Invoices can also be marked as paid by your admin staff based on the arrival of a check or a bank transfer. In either case, a call will be made to the invoice API's process_payment method. This method will often trigger a notice to your order fulfilment staff. This method is passed the following parameters.

paymentThe amount that was paid.
currencyThe payment currency.
invoicesThis can be a scalar if one invoice was paid or an array if multiple invoices were paid.
payment_method The method of payment (paypal, credit-card, check, credit)
otherThis is an array which may contain the following keys: user, auth_code, trans_id, payment_fee

Showing the Customer's Account History

To view the customer's accounting transactions, use the Show Account History button. This will show all of the transactions associated with this customer as we see here:

Account history

Collecting Payment

Now that we have shown how to add invoice records to your customer account, let's review how customers can pay for their order and adjust the amount owned.

Ecommerce Help Index

E-Commerce Overview Features and components used to build an online store.
Cart Items Defining products and services.
Shopping Cart Interacting with a shopping cart.
Working with Text Files How to store and process transactional data using text files.
Working with Databases Saving and retrieving database table data.
Transaction Numbers Generating identifiers for invoices and other transactions.
Taxes and Fees Configuring sales taxes and other cart fees.
Saving Customer Information Reading and writing customer information.
Accounting Data Managing account records.
Collecting Payments Processing credits cards as order payments.