FreeTrade Design Document

Version: 1.0
Created: 08/13/1999
Authors: Leon Atkinson, Monty Gray, Steve Psomas
Copyright (c) 1999 Working Dogs. All rights reserved.


I. Design Overview

II. Architectural Model

III. Structured Design Elements
A. Free Energy Execution Flow
B. Site Directory Structure
IV. Detailed Process Specification
A. Assembly Modules
B. Page Layout Modules
C. Plain
D. With Side Navigation
E. Screen Modules
a-l / m-z
F. Action Modules
A-L / M-Z
G. Detailed Data Dictionary
H. Implementation Hints
1. Comments
2. Function Declarations
3. Compound Statements
4. Naming
5. Constants
6. Variables
7. Long Lines
8. Efficient Database Queries



Design Overview

Freetrade is an Open Source e-commerce toolkit. On its own, it has no graphical design and a basic set of features. Minimally, the implementor must customize the modules of the site that give it a graphical look and load all the catalog information. Most implementors will want to alter many other parts of the system in order to meet client requirements.

This design will attempt to accomodate implementation in any environment, but PHP will be the reference implementation. A Java Servlets version is planned.

The reference database is MySQL, which has proven to be a superior technology. This does imply that commercial use of FreeTrade will require purchasing a license. If developers step forward to create an implementation using another database, Working Dogs may treat it as a branch of the entire project, but we are not interested in abstracting all the database code to allow for plugging in database modules. We feel this is a bad trade of speed for compatibility.

This design strives to keep all functionality within the code and out of the database. That is to say, the system will not rely upon stored procedures or custom functions embedded in the database. MySQL has less support for this than other databases anyway.

Architectural Model

TBD. This section should describe how the Web browser, Web Server and database server interact.

Structured Design Elements

Free Energy Execution Flow

An assembler module performs the task of joining content and layout. Its first task is to execute code common to all pages, such as determining browser brand and version. The application will require the user to have a valid session identifier, and this will be verified very early in the assembler script.

After performing common initiation code, the assembler determines if an action needs to be performed. The assembler links in the module for performing that action. The results of this action are stored in a global memory space so that the layout module may inform the user of action results.

Next, the assembler determines which page layout module to use based on browser and user preferences. Specifically, that is the type of computer they are using, the browser brand and version, and a set of preferences the may administer. Navigator 3 and Internet Explorer 3 are the minimum, but the system will degrade to be useful on older browsers. The site may take advantage of features of the latest browsers.

The layout module chooses a navigation module based on preferences, which layout it has chosen and the screen to be displayed.

Based on form variables, the assembler determines what screen in the site to serve. Each screen may depend on other form variables in order to determine exactly what content to display. For example, the "project details screen" requires a project number.

Each screen may have some dependency on functional elements common to several pages. An example would be a set of form inputs for getting a date from a user.

Site Directory Structure

In order to keep modules outside of the reach of Web browsers, they are stored above the "htdocs" directory. They are stored in a directory named "modules" inside the site's main directory.

FreeTrade


Detailed Process Specification

This section describes the modules used in the assembler.


Assembly Modules

These modules are at the highest level and call the other modules. The one used most often is "index.php3." The others are used in special situations.

Index

  1. Get name of this script
  2. Get root of Web site
  3. Get global settings
  4. Initialize database connection
  5. Make sure sid is still good
  6. Take Action
  7. Include array of page titles
  8. If we aren't given a screen, go home
  9. Set the path to the page body
  10. If screen is bad, go home
  11. Start page
  12. Meta tags
  13. Styles
  14. Layout and navigation may need item info
  15. Include the page body


Page Layout Modules

These are modules used to organize content. The user may choose from two styles of page layout used for most pages in the application. Each of these layout styles is implemented once using tables and once using style sheets. The system chooses an implementation based on browser capabilities.

Each module must choose a screen module and a navigation module. The output of these modules is placed in the appropriate position on the page according to the previously discussed page layout designs.

Plain

This layout is used by the login page, the feedback page and similar pages where navigation is not displayed. This layout is used for certain pages regardless of user preferences.

With Side Navigation

In addition to displaying the side navigation, this layout module displays the top logo, the horizontal navigation module, the content and the bottom copyright message. The logo is aligned left and the navigation table is aligned to the left. The side navigation provides links to such areas as the home page, store, a search option, an advanced search, login, register, and your basket.

Screen Modules

The screen modules display much of the content of the site. They are stored in modules/screens and are named with all lowercase letters. An underscore is used, if necessary, to separate words (e.g. add_department). Many screens have restricted use. An if statement is used to surround sensitive code.

about_us
Input: None
Description: This screen lists all of the relevant information about your company that the user would like to divulge.

add_attribute
Input:
Description: This screen allows the admin to add an attribute to the specified project. The name, graphic, and display precedence are entered here. User must have administration rights. Others are given an error message.

add_department
Input: Department
Description: This screen allows the admin to create a department. User must have administration rights.

add_item
Input: Department
Description: This form will enable an administrator to enter in all of the relevant information for an item. User must have administration rights.

add_sku
Input: Item
Description: This form will enable the administrator to enter in all of the relevant information for a sku. User must have administration rights.

add_variation
Input:
Description: This form enables administrators to create a variation. User must have administration rights.

admin_attribute
Input:
Description: This form enables administrators to set attributes for administration. User must have administration rights.

admin_departments
Input: Department
Description: This screen allows the admin to edit this particular department ($department), including items and subdepartments. It also gives the admin links to move to the parent department, or any of the children departments. Think recursively.

admin_invoice
Input:
Description: This form allows the admin to edit invoice(s). User must have administration rights.

admin_item
Input:
Description: Everything (hopefully) the admin ever wanted for administrating items (including access to the skus). User must have administration rights.

admin_menu
Input: None
Description: Gives administrator a menu of the forms.

admin_tax_rates
Input:
Description: This is a screen that allows the admin to edit the tax rates for each state. User must have administration rights.

contents
Input:
Description: Enables shopper to review contents of basket and provides a link to completely remove an order. Gives the user a link to return to shopping.

create_account
Input:
Login and password. Description: Allows a shopper to create an account.

department
Input:
Description: This screen queries the database to show departments and items contained in them.

edit_attribute
Input: Item information
Description: This screen allows the administrator to edit an attribute. User must have administration rights.

edit_department
Input: Department information
Description: This screen provides a form for updating a department. User must have administration rights.

edit_ibid
Input: Invoice information
Description: (In invoice_sku, the thing that separates the records is the ID, which has been named ibid –"in-basket ID"). This page allows a user to edit that particular record based on the ibid. The In Basket ID represents one sku that will have at least one and possibly more than one quantities in a basket. User must have administration rights.

edit_invoice
Input: Notes regarding invoice
Description: This page allows company personnel to edit invoices. User must have administration rights.

edit_sku
Input: Item information
Description: This is a form for updating a sku. User must have administration rights.

edit_user
Input: User information
Description: This screen allows admin and shopper to edit the information about a particular user. Admins can use this script to edit anyone, user can only use this script to edit information about self.

edit_users
Input: None
Description: This page, in spreadsheet format, allows the admin to see the list of users (ie. people who sign up to buy stuff). The list will have links to edit each user. User must have administration rights.

edit_variation
Input: Item information
Description: This page allows the admin to edit a variation. User must have administration rights.

item
Input:
Description: This page enables the shopper to view details about an item and to add it to the basket.

item_details
Input:
Description: This page enables the shopper to view a large picture of an item in a new browser window.

login
Input: Name and password
Description: This page enables the shopper to log in by form with name and password. The page provides a link for users who haven't registered yet.

order_address
Input: Address
Description: This page enables the shopper to choose a different shipping address item by item.

order_billing
Input: Credit card information, address
Description: This page enables the shopper to input billing information.

order_confirm
Input:
Description: This page shows the final order information and asks for confirmation from the shopper.

order_history
Input:
Description: This page enables the shopper to view the invoices for this user. Each invoice should have a link to allow the user to view that particular invoice. Notice, this file is 'conspicuously' similar to admin_invoice, which is the Admin version of this script.

order_info
Input: Shipping information
Description: This page enables the shopper to view the basket and input shipping information.

order_thankyou
Input: None
Description: Gives a thank you message for placing an order.

order_view_ibid
Input:
Description: (In invoice_sku, the thing that separates the records is the ID, which has been named ibid –"in-basket ID"). The user can view this screen during the order confirmation process (for instance, he may want to check to see that a particular item is being shipped to the correct place).

relate_item
Input:
Description: This page allows an administrator to relate an item to other items. User must have administration rights.

report_inventory
Input:
Description: This page gives the admin an inventory report. User must have administration rights.

search_form
Input: Description or keyword
Description: This page enables the shopper to perform a search by item or over the entire site.

search_results
Input:
Description: This page enables the shopper to view the results of a search.

view_ibid
Input:
Description: (In invoice_sku, the thing that separates the records is the ID, which has been named ibid –"in-basket ID"). This page allows a user to view that particular record based on the ibid.

view_invoice
Input:
Description: This page enables the shopper to view one of his past invoices. Checks to make sure userID corresponds to this invoice's userID.

welcome
Input:
Description: This is the default screen for a FreeTrade site.

wishlist
Input:
Description: This page enables the shopper to view the wishlist and move items to the basket for checkout.



Action Modules

These modules most often change information in the database. They are named by forms on screens. Sometimes they change the variable SCREEN based on the results of the functions they perform. Most of them set the variable ActionResults. This variable is used in the layout module to display the results of the action.

The titles in this section are the exact names of both the actions and their filenames. A short description is followed by a list of expected input fields. Security for these actions needs to match the checks made on the screens they are called by. In most cases the actions simply perform a database function like adding or updating a row.

ADD_ATTRIBUTE
Add an attribute to the database. Only an administrator may add an attribute.

ADD_BASKET
This action adds an item to the basket.

ADD_DEPARTMENT
This action adds a department.

ADD_FROM_WISHLIST
This action adds a sku from the wishlist, then removes it from wishlistinput_division_name. This is accomplished by adding the product to a basket through a query which will input the Session, SKU, Quantity, and Notes. Once the query is executed, the item(s) will then be added to the basket, and the second query, which will remove the item from the wishlist, begins. The query simply deletes the relevent data from the user_sku table.

ADD_ITEM
This action adds an item to the database. Only administrators may add items. When adding an item there are a couple of things to consider: The user must select a department and give the item a name. Any other entries are optional. Then a query is run to determine if there are any duplicate items. The item must then be added to the item record.

ADD_SKU
This action adds a SKU to an item. Only administrators may add skus.

ADD_STATUS
This action allows company personnel to add records to the invoice_status table in connection with a particular invoice.

ADD_USER
This action adds a user to the system.

ADD_VARIATION
This action adds a variation to the database. The user must have admin rights.

CLEAN_INVOICE
This action removes shipping/billing records for active invoice. This is done through a series of steps that are executed in various queries: get the ID of the incomplete invoice for this user, get shipping IDs for the invoice, delete addresses, delete shipping, delete billing, and update shipping in invoice_sku.

CLEAN_INVOICE_FULL
This action removes shipping/billing/fees for active invoice. Similar to the clean_invoice module, this is done through a series of steps that are executed in various queries: get the ID of the incomplete invoice for this user, erase previous fees, get shipping IDs for the invoice, delete addresses, delete shipping, delete billing, and update shipping in invoice_sku.

CREATE_INVOICE
This action will create a blank invoice, with no SKUs, and set to inactive. The user will create an invoice row that will enable the user to enter relevant information.

DELETE_ATTRIBUTE
This action removes an attribute from the database. In order to completely remove the attribute it has to be removed from the attribute table along with the sku_variation table.

DELETE_DEPARTMENT
This action removes a department and all items/SKUs in the department. When first running this module, it will determine whether the department variable is set. Once it is determined, it will check to see whether or not the department exists and whether or not there are items in the department. If there are items, then it will not continue and will display the appropriate message. If there are no items, the department will be deleted.

DELETE_ITEM
This action Removes an item and all SKUs that are related to the respective item. A series of queries are executed to ensure that all relevant SKUs are deleted to its corresponding item.

DELETE_SKU
Removes a SKU from both the SKU table and the inventory table.

DELETE_VARIATION
This action Removes a variation from the variation and sku_variation tables respectively by deleting the attribute and the sku_variation.

GENERATE_SID
This action creates a sid and creates a row in the session table. The sid is randomly generated from a defined charpool.

LOGIN_USER
This action will verify the user and create a session. To verify the user it will then check whether the user is allowed to login and whether the password given is correct.

LOGOUT_USER
This action will remove the user from the session table.

PURGE_INVOICE
This action will delete a user's incomplete invoice, all SKUs, and all address for SKUs. This does not require admin rights.

REMOVE_FROM_WISHLIST
This action will remove a SKU from the users wishlist.

SAVE_BASKET
This action saves all SKUs in the basket to the wishlist.

SET_SHIPPING
This action sets shipping address for given SKUs on the incomplete invoice.

SET_SHIPPING_ALL
This action sets shipping address for all SKUs on the incomplete invoice. There will be three main functions executed: createAddress, createShipping, and ShippingByTotal.

UPDATE_VARIATION
This action updates information about a variation.

UPDATE_TAX_RATES
This action allows the admin to update the tax rates for all of the states. Expected Input: Array, Rates, TaxShipping

UPDATE_SKU
This action updates a SKU. The following valid data is required:

UPDATE_SHIPPING
This action updates the contents of one record from the "shipping" table. Expected input:

UPDATE_LOGIN_PASSWORD
This action updates the login and password in the "user" table. Expected input:

UPDATE_ITEM
This action updates information about an item.

UPDATE_INVOICE_SKU
This action updates quantity and giftwrap for items on an invoice.

UPDATE_IBID
This action updates the contents of one of the records in the "invoice_sku" table. Expected input:

UPDATE_DEPARTMENT
This action updates information about a department. Expected input:

UPDATE_BASKET
This action updates the quantities for basket.

UPDATE_ATTRIBUTE
This action updates information about an attribute Expected input:

UPDATE_ADDRESS
This action updates an address record in the "address" table. Expected input:

SUBMIT_ORDER
This action creates an invoice. Here the invoice is set active as the lists of respective SKUs are retrieved. At the end of the function a confirmation email is then sent.

VALIDATE_ORDER
This action checks the billing info for validity, then adds it to the invoice. Here, we're only checking that the credit card number is valid, not authorizing the charge. The three main functions that will be executed are the "createAddress", "get credit card validation", and "Is everything okay to proceed" function.



Detailed Data Dictionary

The following is a description of every table in the database. The SQL for creating the tables is listed here with notes.

CREATE TABLE attribute (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  Graphic varchar(255),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);


CREATE TABLE billing_method (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);

INSERT INTO billing_method VALUES (1,'Visa',1);
INSERT INTO billing_method VALUES (2,'Mastercard',2);
INSERT INTO billing_method VALUES (3,'American Express',3);



CREATE TABLE department (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  Graphic varchar(255),
  Parent int(11),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);

#test data
INSERT INTO department VALUES(1, 'Books', 'books.gif', 0, 1);
INSERT INTO department VALUES(2, 'Music', 'music.gif', 0, 2);
INSERT INTO department VALUES(3, 'Videos', 'video.gif', 0, 3);
INSERT INTO department VALUES(4, 'Hardcover', 'hardcover.gif', 1, 1);
INSERT INTO department VALUES(5, 'Softcover', 'softcover.gif', 1, 2);
INSERT INTO department VALUES(6, 'VHS', 'vhs.gif', 3, 1);
INSERT INTO department VALUES(7, 'DVD', 'dvd.gif', 3, 2);
INSERT INTO department VALUES(8, 'CD', 'cd.gif', 2, 1);
INSERT INTO department VALUES(9, 'Vinyl', 'vinyl.gif', 2, 2);
INSERT INTO department VALUES(10, 'Cassette', 'cassette.gif', 2, 3);


CREATE TABLE department_item (
  Department int(11),
  Item int(11)
);


CREATE TABLE invoice ( //This is hopelessly out of date.
  ID int(11) NOT NULL AUTO_INCREMENT,

  Bill_FirstName varchar(255),
  Bill_LastName varchar(255),
  Bill_Company varchar(255),
  Bill_Address1 varchar(255),
  Bill_Address2 varchar(255),
  Bill_City varchar(255),
  Bill_State varchar(255),
  Bill_Country varchar(255),
  Bill_ZIP varchar(255),
  Bill_Method int(11),
  Bill_CreditCardNumber varchar(255),
  Bill_CreditCardExpiration varchar(255),

  Order_ItemCost float(11,2),
  Order_Tax float(11,2),
  Order_Shipping float(11,2),
  Order_Created datetime,
  Order_Shipped datetime,
  Order_OnHold datetime,
  Order_OnHoldComment blob,

  Ship_FirstName varchar(255),
  Ship_LastName varchar(255),
  Ship_Company varchar(255),
  Ship_Address1 varchar(255),
  Ship_Address2 varchar(255),
  Ship_City varchar(255),
  Ship_State varchar(255),
  Ship_Country varchar(255),
  Ship_ZIP varchar(255),
  Ship_Method int(11),
  User int(11),
  PRIMARY KEY(ID)
);



CREATE TABLE invoice_sku (
  Invoice int(11),
  SKU int(11),
  Quantity int(11),
  ExternalSKU varchar(255),
  Name varchar(255),
  ListPrice float(11,2),
  SalePrice float(11,2),
  Shipping float(11,2)
);



CREATE TABLE item (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  Description blob,
  Keywords blob,
  Thumbnail varchar(255),
  Graphic varchar(255),
  LargeGraphic varchar(255),
  DisplayPrecedence int(11),
  Active char(1),
  PRIMARY KEY(ID)
);



CREATE TABLE item_item (
  Item int(11),
  Related_Item int(11),
  Relationship int(11)
);



CREATE TABLE relationship (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);



CREATE TABLE sku (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Item int(11),
  ExternalSKU varchar(255),
  Name varchar(255),
  ListPrice float(11,2),
  SalePrice float(11,2),
  Shipping float(11,2),
  DisplayPrecedence int(11),
  Active char(1),
  PRIMARY KEY(ID)
);



CREATE TABLE sku_variation (
  SKU int(11),
  Variation int(11)
);


CREATE TABLE seed (
	seed int(11)
);

INSERT INTO seed VALUES (123123123);


CREATE TABLE session (
  ID varchar(24) NOT NULL,
  User int(11),
  LastAction datetime,
  PRIMARY KEY(ID)
);



CREATE TABLE session_sku (
  Session varchar(24),
  SKU int(11),
  Quantity int(11)
);



CREATE TABLE shipping_method (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);


INSERT INTO shipping_method VALUES (1,'USPS',1);
INSERT INTO shipping_method VALUES (2,'UPS',2);
INSERT INTO shipping_method VALUES (3,'FedEx',3);



CREATE TABLE user (
  ID int(11) NOT NULL AUTO_INCREMENT,
  FirstName varchar(255),
  LastName varchar(255),
  Login varchar(255),
  Password varchar(255),
  Email varchar(255),
  Company varchar(255),
  AddressLine1 varchar(255),
  AddressLine2 varchar(255),
  City varchar(255),
  State varchar(255),
  Country varchar(255),
  ZIP varchar(255),
  Phone varchar(255),
  Fax varchar(255),
  PRIMARY KEY(ID)
);



CREATE TABLE variation (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(255),
  Attribute int(11),
  Description varchar(255),
  Graphic varchar(255),
  DisplayPrecedence int(11),
  PRIMARY KEY(ID)
);


CREATE TABLE permission
(
	ID INT NOT NULL AUTO_INCREMENT,
	Name VARCHAR(255),
	PRIMARY KEY(ID)
);

INSERT INTO permission VALUES (1, 'Login');
INSERT INTO permission VALUES (2, 'Administrate');


CREATE TABLE user_permission
(
	User INT,
	Permission INT
);



Implementation Hints

Coding Style Guideline

Comments
Every file should start with a comment block describing its purpose, version, author and a copyright message. The comment block should be a block comment in the style below.

/*
** File: test
** Description:  This is a test program
** Version: 1.0
** Created: 1/1/2000
** Author: Leon Atkinson
** Email: leon@clearink.com
**
** Copyright (c) 1999 Working Dogs.  All rights reserved.
*/

Every function should have a block comment specifying name, input/output, and what the function does.

/*
** Function: doAdd
** Input:  INTEGER a, INTEGER b
** Output: INTEGER
** Description:  Adds two integers
*/
function doAdd($a, $b)
{
	return(a+b);
}

Ideally, every while, if, for or similar block of code should be preceded by a comment explaining what happens in the block. Sometimes this is unnecessary.

// get input from user char by char
while(getInput($inputChar))
{
	storeChar($inputChar);
}

Explain sections of code that aren't obvious.

//TAB is ASCII 9
define(TAB, 9);

// change tabs to spaces in userName
while($index=0; $index < count($userName); $index++)
{
	$userName[$index] = ereg_replace(TAB, " ", $userName[$index]);
}

Function Declarations
As previously stated, functions should have a comment block explaining what they do and their input/output. The function block should align starting at one tab from the left margin unless the function is part of a class definition. Opening and closing braces should also be one tab from the left margin. The body of the function should be indented two tabs.

<?php
	/*
	** doAdd
	** Adds two integers
	** Input:  $a, $b
	** Output: sum of $a and $b
	*/
	function doAdd($a, $b)
	{
		return(a+b);
	}
?>

Compound Statements
Flow control primitives (if, while, for, ...) should be compound statements, even if they only contain one instruction. Like functions, compound statements should have opening braces that start at column zero relative to scope.

Code within the braces forms a new scope and should be indented.

// tell the user if a is equal to ten
if($a==10)
{
	printf("a is ten.\n");
}
else
{
	printf("a is not ten.\n");
}

Naming
The names of variables, constants, and functions are to begin with a lowercase letter. In names which consist of more than one word, the words are written together and each word starts with an uppercase letter.

Constants
Values that are treated as constants, that is, not changed by the program, should be declared in the beginning of the scope in which they are used. In PHP this is done with the define function. Each of these constants should be paired with a comment that explains use. They should be named exclusively with uppercase letters, with underscores to separate words. You should use constants in place of any arbitrary values to improve readability.

// maximum length of a name to accept
define("MAX_NAME_LENGTH",  32);
print("Maximum name length is " . MAX_NAME_LENGTH);

Variables
Variables are to be declared with the smallest possible scope. This means using function parameters when it's appropriate.

Long Lines
Lines should not exceed 78 characters. Break long lines at common separators and align the fragments in an indented block.

if(($size < 0) OR
	($size > max_size) OR
	(isSizeInvalid($size))) 
{
	print("Invalid size");
}
Expressions
Idioms
Following are idioms you ought to use when appropriate. Often there are multiple ways to perform a task. Using an idiom will make the code instantly familiar.

Looping over associative arrays

//print all address fields
reset($AddressInfo);
while(list($key, $value) = each($AddressInfo))
{
	print("$key is $value<br>\n");
}

Efficient Database Queries
The mysql_result function should not be used due to it's inefficiency. The mysql_fetch_row has been used extensively, but mysql_fetch_object may be the preferred method going forward.