Designing A Point of Sales App
Volume Number: 13 (1997)
Issue Number: 11
Column Tag: Custom Applications
Designing a Point of Sales Application
by Evan Trent
Finding the hardware and writing the software to set up a Macintosh as a cash register
A Brief Introduction
"If this thing beeps again, I want you to throw it out the window," I remember one of my mother's employees murmuring through his teeth. This was hardly the first indication that the cash register system we were using was eventually going to be replaced. Yet, I really hadn't expected that I would be responsible for creating the new system.
A Unique Solution
I realized that several of the flaws inherent in a terminal-based cash register are related to its such poor user interface. On other side of that spectrum lies the Macintosh, providing a graphical user interface which enables even the novice user to perform a variety of tasks with great ease. The Mac is the ultimate "idiot proof" machine, that was exactly what we needed: a system that could provide a simple user interface but wouldn't let the user do something illogical. As I thought more about it, I came to the conclusion that I could write a point-of-sales (POS) application for the Macintosh that would provide all of the features we needed and at the same time make use of the Macintosh GUI. It was to be a match made in custom application heaven.
A Journey Into POS
While the software I wrote is an essential element in the point-of-sales system we currently use, MacTech readers certainly have little difficulty writing their own software. What is arguably of more importance is the hardware, and I intend to discuss the issues I encountered in dealing with the hardware in great depth. However, to better understand how the hardware functions, it makes sense to discuss the software design. As is the case with many applications, but especially in the case of a POS application, of foremost importance is the user interface.
Designing the User Interface
While the user interface is fairly simple, it is exactly this simplicity which makes it so flexible. We had previously been using a programmable keyboard with a Panasonic 5000 cash register system. You've probably seen similar systems in supermarkets or cafeterias. To charge a customer for an item, the employee presses the button on the keyboard corresponding to that item. Nearly all such systems then proceed by beeping loudly for some unknown reason. (The customer doesn't think much of this, but the employee is either going deaf, or insane, or both.) To prevent an awkward transition from occurring between our old system and the new Macintosh based system, I decided to place the programmable keyboard in a window on the Macintosh screen (Figure 1). This may seem odd, but it works very well for a variety of reasons.
Figure 1. The on-screen programmable keyboard.
The biggest advantage over the old "physical" programmable keyboard approach is the increased ease of changing item attributes. No longer does the employee have to reprint a keyboard template and tape it down. (This proved to be absolutely impossible on the old system, because the little boxes on the template never properly overlapped the buttons on the keyboard; don't ask me why.) The "virtual" (on-screen) programmable keyboard is comprised of 100 square buttons, arranged in a 10x10 grid. Each row is color coded to ease strain on the eyes when searching for a particular item. Typically items are placed in rows with other items in their respective, colored subgroups (sandwiches on one row, beverages on another) and thus the employee associates each type of item with a color. This reduces the time it takes to find any given item on the screen.
To the right of the on screen keyboard, there is a scrollable list. This list provides a running queue of items in the pending sale. The first column contains the quantity of the item, the second column contains the name of the item, and the third column contains the net price of the item. This list proved to be the most applauded enhancement over the old system.
Underneath the programmable keyboard there are two rows of buttons. The first button, labeled "Void", removes an item from the queue, or if there is a quantity greater than one of that item, it decreases the quantity by one. "Void Many" removes the item from the queue regardless of quantity. "Void All" removes all items from the queue. "Return", which is intended to be used when a customer brings back damaged or lame goods, will negate the price of the selected item. "Tax" will tax an item, or "untax" an item if it already has been taxed. "Drawer" simply opens the cash drawer. "Print Receipt" will print a receipt for the last sale, even if it has already been processed. The user can define which payment methods automatically print receipts and which don't. For example, most customers don't want a receipt for cash or check transactions, but do for credit cards. If the customer does want a receipt for a cash or check transaction, the user simply can press the Print Receipt button. This saves a lot of paper.
Underneath the queue of items, there is a running total, and underneath that is an edit text box labeled "Quantity". This text field will only accept numbers, and will set the quantity for the next item to that number it contains. For example, to add 99 Espressos to the queue, the user would type 99 (which would be entered into the edit text field) and then press the Espresso button. After an item is added to the queue the quantity text field is automatically reset to 1 and the text is selected such that any number typed will replace the 1. This proved to be an efficient method of entering multiple items with a minimum of fuss.
Form Follows Function
There were several other employee interaction problems with the previous system, but the most serious design flaws occurred within the managerial functions of the cash register. To change an item's attributes, the employee had to retrieve the "manager's key" and turn the register into "manager" mode. This also only could be done from one register (the master register, as opposed to the other slave registers). From this point on the English language ceased to exist. There were code numbers for everything. Why is an employee (or manager) supposed to know that to add meals tax to an item, he must set "Special Flag 2" to 0010? This was completely absurd. Our employees invest their time in learning about food, not special code numbers. When items needed to be changed, I was the only person who could change them, and it took forever because the items had to be changed one at a time.
I disposed of the old approach to editing item attributes and decided upon a better method. Because the employees were already familiar with the on screen keyboard, why not have that be preserved throughout the editing mode? When the employee selects "Change Item Attributes" from the "Register Functions" menu, a new dialog box appears (Figure 2) presenting the on screen keyboard.
Figure 2. A similar interface is used for editing item attributes.
Where the item list used to be, there is a new set of dialog items accepting input for the item's name, price, subgroup and other options. Three checkboxes are visible. The first toggles the "open" status of an item. If an item is "open," it does not have an assigned price, rather it asks for a price every time it is added to the queue. An example of an "open" item is a cheese which is weighed on the scale. After the scale prints a label, the user presses "Open Fromage" and types in the price which appears on the label. If the "open" checkbox is checked, no item price may be entered. Likewise if an item has a price and the user checks the "open" checkbox, the price is removed. The old system allowed a price to exist even if an item was an "open" item. This created a lot of confusion. Additionally, there are two checkboxes, one for sales tax and one for meals tax. While an item can be taxed at any time, certain items always carry a tax with them (sandwiches for example) and thus it saves time to pre-tax them. Any item which has the meals or sales tax checkbox checked will automatically add the appropriate tax to its price.
Changing an Item's Attributes
Changing an item's attributes is a trivial task. The employee clicks an item's button, and then edits the content of each of the dialog items containing the appropriate attributes. He can then click another item's button to go on changing that items' attributes, or simply click the Okay button to save changes for that one item (or Cancel to revert to the previous attributes). This allows items to be edited very quickly, and in a batch manner. The user will always know what item he is editing because the name of the item is displayed in the window's title bar. Thus if a user changes an item's name and forgets which item he is editing, he can glance up at the title bar. This proved to be very well received.
Let Me Speak to the Manager
Additional managerial functions were improved. Tracking, polling and report generation were preserved but were executed in more logical manners. The production staff wanted to check on how many sandwiches had been sold, for example, at 3:00 PM without closing out for the day. The old system required a key and a slew of codes to acquire this information. The new system made this simple. Closing out for the day on the old system took an eternity because the system was printing all kinds of ridiculous reports that were uninformative and essentially useless. About half of the reports generated were of use to us. Those were the reports I carried over to the new system. Additionally, new reports were added to the system. One such report was the price range report, which breaks down the number of sales by total. For example, it might inform us that ten sales were between $0 and $5 and fifty were between $5 and $10. Other reports provide information on totals by item, subgroup, tax, and hour of the day (as well as day of the month when closing out a month). The new system takes about ten seconds to close (probably because it's PowerPC native) and for each day saves a report in a file named after the date. The old system printed one report, and that was it. You couldn't print it ever again.
Put That On My Tab
A feature we added from scratch was house accounts. We wanted the ability to run up a tab for each of our regular customers, keeping track of what they had purchased. Here we used the List Manager to list accounts in alphabetical order by last name. (Figure 3.)
Figure 3. This dialog lists house accounts in alphabetical order.
From the dialog shown in Figure 3, the user can "Add" a new account, or "Delete" or "Modify" an existing account. Of course, the user cannot delete an account with an outstanding balance. Clicking the "Print BTD" button will print a "Balance to Date" report, which contains a list of every item purchased in reverse chronological order since the balance was last paid. Thus, a customer can at any time ask for their balance and will receive a full statement. Clicking the "Pay Out" button will print two copies of that statement, with the words "Balance Paid in Full" at the bottom. This serves as the customer's proof of payment. The account balance is reset to $0.00 and the drawer opens to accept payment. Clicking the "Done" button simply dismisses the dialog.
Modifying an Account
Additional information (such as address and phone number) is added when an account is created, and can be modified at any time. (Figure 4.)
Figure 4. An account holder's personal information
may be altered through this dialog.
"House Account" is considered a payment method just like cash or check except that obviously the money is not in the drawer at the end of the day. When a transaction is made, if the employee chooses house charge as the method of payment, he must pick from a list of house accounts (Figure 5), or he can create a new one at that time.
Figure 5. This dialog requires the user to either choose an account to charge, or create a new one.
He then receives two receipts, identical except that one provides a space for a signature from the customer. This prevents a customer from questioning his or her purchase of an item or items. We simply keep all the signed receipts until the balance has been paid. Every month we mail out a statement. At the end of the day the daily report lists a figure for House Accounts as a payment method. When the money in the drawer is counted, the figure listed under the "House Accounts Total Charged" heading can be subtracted from the Net Sale figure on the report, and the drawer should match that number.
Set In Stone
After dealing with the List Manager for a short period of time I discovered what I'm sure many veteran Macintosh programmers have long since known: The List Manager is somewhat of a joke. While it offers a host of useful features, it leaves a lot to be desired. The most obvious limitation is its inability to have differing widths among columns. Also, there can be only one style definition per list. In the case of my application, it was very difficult to have three columns in the queue and have more than a few characters of the item's name visible. To see more of the item's name, I had to enlarge that column and shrink another one (such as the quantity column, which needed only two or three characters). The only way to do this easily was to use StoneTable from StoneTablet Publishing. StoneTable also enabled me to use different styles for each cell. In particular, I wanted to align the price column flush right, yet I wanted the rest of the columns to align flush left. StoneTable proved to be a great enhancement to the user interface.
Without question, the most appreciated feature was the new on-screen queue of items. Even employees who previously had little experience with the cash register (production staff, for example) found it easy to wait on customers if the store was so busy that we needed extra hands. The user interface proved to be incredibly intuitive and enabled a variety of functions to be performed on an item (return, discount, void, etc.) merely by selecting the item from the list and clicking the appropriate button. Additionally, employees mentioned how they appreciated that every time they clicked a button to add an item to the queue, it was automatically selected, thus they could perform a function on the most recent addition without having to make extra clicks. The greatest enhancement the list offered was scrolling, which was an inefficient and inhibiting task on the old system. Scrolling was now fast, and intuitive. Furthermore, there was now a method of determining if there were items above or below the "viewrect" because of the existence of the scroll bar.
In truth, the most intimidating part of this endeavor was learning to communicate with point-of-sales hardware devices. I had no experience with hardware related issues, so there was an entire world of unconquered code awaiting me. I hadn't used the Device Manager or even OpenSerial() before. The three devices I needed to get my software to communicate with were receipt printers, cash drawers, and pedestal displays. I was very lucky that the manuals that came with each of these devices were thorough and certain sections were clearly written with programmers in mind.
In truth, communicating with the receipt printer wasn't as difficult as I had expected. The hard part was making the receipts look nice. The particular printer we chose was the Star TSP200, a thermal printer with an auto cutter. It's very quiet, very fast, and it can print bitmaps. It has a host of control characters that enable printing modes such as bold, inverse, underline, double width, double height etc. This enabled me to format the receipts to look very snazzy. Much thanks to Charles Rentmeesters (who wrote a Chooser level driver for the TSP200 and proved to be and endless source for information ) I was able to print the logo for our store at the top of every receipt and report. Unfortunately, using the Chooser level driver was not possible because it did not provide a method for sending control characters to the printer. I was forced to send text directly to the printer via the serial port.
A few tidbits were added to the receipt that were not printed by the old setup such as the store's address and phone number, the payment method, cash tendered and change (if it's a cash transaction) and the account holder's profile (if it's a house charge). I spent even more time formatting the reports on the receipt printer because they make use of several columns, and with a 3" wide roll of paper, things can get a bit tight.
The cash drawer proved to be a cinch to use. The TSP200 has a pass through modular jack that connects to most cash drawers, among them the Loyal Cash Drawer we purchased. To open the drawer, you send a control character to the TSP200 and it in turn opens the drawer. It's that easy.
The device that was the most fun to work with was the pedestal display. These devices are little LCDs mounted atop a pole with a base. You've no doubt seen them integrated into cash registers at the supermarket. They provide the customer with information for each item entered into the register, and typically display the total sale amount when the items have all been entered. Our pedestal display was manufactured by ID Technologies. This unit connects to a serial port and can be operated in one of two modes: pass through or stand alone. When in pass through mode, the device displays data only when the data is prefixed with a user defined control character. The rest of the data is passed on to the next device in the chain (typically the receipt printer). Because the Macintosh has two serial ports this mode was not necessary. However, certain features, such as scrolling messages, were available only in pass through mode. Thus, while I had a serial port available, I used pass-through mode. (See Listing 1 later in the article.)
As with the receipt printer, communicating with the pedestal display was essentially just a matter of streaming text through the serial port, but it was fun to use the control characters and to spice things up with scrolling messages among other things. The unit has two lines with 16 characters on each line. I designed the output to show the last item entered into the queue on the first line and the running total on the second line. The old system displayed only the price of the last item entered and wouldn't show the total until you opened the drawer. It also displayed only numbers.
Bigger Isn't Always Better
The icing on the cake was the monitor. We didn't really have room for a CRT, so I investigated LCD flat screens. I've always been charmed by the flat panel displays on laptops, but I didn't think of using one until I realized that we were going to have to make this system fit on a countertop (an afterthought for a software engineer). We ended up with CTX 12.4" LCD displays. After adapting them for touch sensitivity, we had a three inch deep screen with a very nice tilt base. Better yet, these screens could run at 800x600 (which gave us plenty of room for the on screen keyboard, etc.). The touch screen is perfect for the user interface; it ties everything together. The keyboard sits right on top of the cash drawer in front of the screen and receipt printer. Luckily, the dimensions worked out perfectly. (See Figure 6.)
Figure 6. This is one of our cash registers. This computer is stored on a shelf below the counter.
Some Assembly Required
I spent more time researching the hardware for this system than I did writing the software. This is primarily because most POS systems are integrated "all in one" systems. These systems have many advantages, however they are typically very costly. It is much cheaper to assemble a system by hand, but finding the right retailers can be a time consuming process. After spending many hours in Yahoo and other search engines, I did find a number of POS retailers who were willing to sell individual components such as receipt printers, pedestal displays, cash drawers, barcode scanners, magnetic strip readers and supplies. Finding the right retailer is the key. In particular, I was looking for one that was familiar with and, more importantly, focused on integrating POS hardware with the Macintosh.
Finding an LCD monitor manufacturer also proved to be an arduous task. I communicated with at least three or four companies. I actually drove to visit one manufacturer and almost purchased their screens. That was before I found another manufacturer who provided me with almost identical screens for half the price. Watch out, it's easy to get burned when building a system piece by piece.
For those readers interested in putting together a similar setup, here are some prices you can use as a frame of reference. A cash drawer shouldn't be more than $200 - $300. Receipt printers can vary in price based upon their printing mechanisms. Dot matrix printers are obviously much cheaper than thermal printers. A dot matrix machine should cost $400 - $500. Thermal printers are typically about $700 and can jump up into the $1000 range. Pole displays vary in price depending upon the number of characters and rows they display. In general, prices are between $300 and $400. As is typically the case, purchasing in bulk will almost always yield lower prices.
The glue that holds the system together obviously is the computer itself. Now that clones are available there are some choices, but the field is fairly limited and prices are almost identical among mail order companies. We bought the cheapest machine available. Speed certainly isn't an issue for a POS system, and no fancy features are necessary. The slowest and most obsolete machine available could still run a POS system with no noticeable loss of performance.
Let's Get Technical
All right, enough with all the talk. It's time to blow away some of the smoke and reveal how to make a Macintosh work with all of this hardware. Listing 1 demonstrates how to send data to a serial device such as the pedestal display. Communicating with a receipt printer is an almost identical process, but obviously it requires formatting the page with tabs and other control characters ('\t' doesn't work). There is nothing earth shattering here for programmers experienced with the Device Manager or Serial Drivers. Mere mortals like me, however, have little experience with device communication outside of the Chooser; thus this may shed some light on the basics.
Listing 1: PDisplay.c
This routine displays the last item added to the queue on the first line of the pedestal display. On the second line it displays the current total for the pending sale. This routine is designed to work with the display unit when it is in "pass through" mode. In "stand alone" mode, simply precede the desired output string with '"\r\r" to clear both lines of the display, and then send both lines one and two separated by a '\r' as one string rather than sending one line at a time with "!#1" and "!#2" preceding each string. This routine takes a character pointer item_name, and a double current_total as parameters. It returns TRUE if it successfully displays the item and total, and FALSE if it is unable to communicate with the device.
Boolean PD_Item(char *item_name, double current_total)
char buffer; //leave room for a 16 characters plus a
//few extra control characters
err = OpenDriver("\p.aout",&aout); //open the modem port
//for data output
//pedestal displays usually use 2 stop bits as opposed to 1
//and can only communicate at 9600 baud
err = SerReset(aout,baud9600+stop20+noParity+data8);
sprintf(buffer, "!#1%.16s", item_name);
//"!#1" tells the unit to clear the first line of the
//display and then set it to the following 16
count = strlen(buffer);
err = FSWrite(aout,&count,buffer);
//send the data out to the port, for async communication,
//PBWrite is better, but this isn't a time consuming
//transfer of data, so FSWrite is adequate
sprintf(buffer, "!#2Total - $%.2f", current_total);
//as before "!#2" tells the display to set the second line
//of the display to the next 16 characters that follow
count = strlen(buffer);
err = FSWrite(aout,&count,buffer); //send the data
CloseDriver(aout); //close the modem port
I don't see my software as a particularly marketable product, it's far too customized and doesn't facilitate the needs of a large business. It was designed for a small business that sells goods they either produce or package themselves. I suppose that's why most of the other software I looked at didn't seem right for us. I looked around for a piece of software that could accommodate our needs, but all I found were applications designed to be used with barcode scanners and PLU numbers. Clearly we have a different type of operation. Of course, few "mom and pop" stores have an in-house programmer who works for free. The point is that if there's anything I learned from this, it's that the old adage is true: use the right tool for the right job, even if it means building the tool yourself. Oh yeah, I did learn one more thing: no good piece of software beeps on a regular basis.
For those readers interested in assembling a similar setup, here are several web links which should offer helpful information. Please feel free to contact me for further information or more online resources if you need them.
- POS Direct, http://www.posdirect.com/
Not the greatest web site I've seen, but they have excellent customer service and a good downloadable catalog. Very helpful with Macintosh implementation.
- Direct POS, http://www.directpos.com/
A bigger selection of equipment, but less tailored to use on the Macintosh.
- Star Micronics, http://www.starmicronics.com/product/receipt/index.htm
Star is without question the most popular manufacturer of receipt printers, and they offer a very nice line of printers from entry level to high quality thermal printers. Macintosh Chooser level drivers are available from POS Direct for a steal.
Touchscreens -- LCD & CRT
- Pixel Touch, http://www.pixeltouch.com
Good selection of both LCD & CRT screens with good customer service. Reasonably priced.
- PixelVision, http://www.pixelvision.com
Cutting edge LCD innovation, but at a price. The only available 16" LCD screen on the market is manufactured by these folks (and boy is it nice).
- ID Technologies, http://www.idt-net.com/1800.htm
ID Technologies has a very reasonably priced pedestal display, as well as other products such as magnetic strip and barcode scanners.
Evan Trent, firstname.lastname@example.org, is the 18 year old son of Alice and Walter Trent, owners of Alice's Bakery and Café in Norwich, VT. He has been programming as a hobby for several years, and recently wrote a Macintosh-based point-of-sales application for his parents' business. He is currently a senior at Governor Dummer Academy, the nation's oldest boarding school, located in Byfield, MA.