PAYROLL A Small Business Payroll Program Requirements: 256K Amiga, printer. (EDITOR'S NOTE: JUMPDISK gratefully acknowledges permission given by CodeWorks publisher Irv Schmidt to adapt this article and the program to Amiga Basic. The article is generally given here as originally printed in the March-April 1986 edition of CodeWorks. Before using the program, you should transfer it to a blank, initialized Amiga disk. That means loading it into the computer from JUMPDISK, then saving it to the new disk. When selecting this program from the Program Menu, you will not get the program itself, but a reminder that it should be run only with a data disk in the drive, not JUMPDISK, plus instructions on how to LOAD it from JUMPDISK and SAVE it to that data disk on which it will run. The beginner should not be discouraged from using this program. There are a few variables to plug in near the start but the program run is generally self-explanatory. The article deals greatly with understanding how the program works so that other programmers may tinker with it, and most of the article refers to automatic computations. However, you should read the entire article to understand how the program works. - - - - - - - - - - - Reprinted with permission of CodeWorks magazine. A free sample of Codeworks may be obtained by writing to CodeWorks, 3838 South Warner St., Tacoma, WA 98409 or leaving a request for one on its download system (206) 475-2356 (800,N,8,1). STAFF PROJECT. THE DIVERSITY OF RULES, REGULATIONS AND TAX LAWS IN THE VARIOUS STATES MAKES A GENERALIZED PAYROLL PROGRAM A CHALLENGE. THIS PROGRAM IS A SIMPLE STARTING POINT FROM WHICH YOU CAN CUSTOMIZE ONE AS YOU WISH. IT USES SEQUENTIAL FILES THROUGHOUT, AND THE STRUCTURE OF THE PROGRAM MAY LEND ITSELF TO USES OTHER THAN PAYROLLS. In the 1880's the stagecoach would race through the foothills with a strongbox strapped to its top. At least two tough looking hombres with rifles would ride "shotgun." After arriving at the mining camp, the strongbox would be opened and all the workers would be paid in gold coin. They would then head for the nearest town, presumably to squander their gold on whiskey, women and poker -- not necessarily in that order. Payrolls had their own problems then. In 1913, immediately after the 16th Amendment became effective, Congress enacted a personal income tax, with a normal rate of 1% on incomes over $3,000 for a single person and $4,000 for a married person, and surtax rates on taxable incomes in excess of $20,000 ranged from 1% to 6%. The corporate rate was then 1%. With minor exceptions, all employers were required to withhold tax on a current basis from employees' paychecks and transmit the sums to the government. By 1960, this country obtained 82% of its total revenue through income taxes. The national system of social security established by the Social Security Act of 1935 was part of President Franklin D. Roosevelt's "New Deal." This resulted in another contribution from the employee, this time matched by his employer. Since the Internal Revenue Service had already been set up to administer the income tax program, the social security (FICA) deduction was conveniently included with the IRS-required deposit on IRS form 941. If it had all stopped there, writing a payroll program for a computer today would be a snap. But it didn't stop there. State agencies, labor unions and others all get their "cut" of a paycheck. Unfortunately (or fortunately, however you want to look at it), the state and local deductions are not as uniform as the federal deductions. Some states (Washington State is one) do not have a personal income tax. Even in states that do, the amount differs and the income against which the tax is levied differs. In addition, most income taxes, both state and federal, are levied in a graduated basis. Many people who are not employers or directly connected with the collection of taxes assume that the government gets paid on April 15 of each year. Nothing could be further from the truth. An employer withholds income taxes and FICA amounts, and if the amount is less than minimal, deposits them in a designated bank quarterly. If the amount is more than minimal, the deposit must be made monthly, and if the amount amounts to anything, the deposits must be made on what the IRS calls an "eighth monthly basis." What that means in practical terms is that the deposit must be made eight times a month or twice a week. What follows is a description of a payroll program that will handle up to 10 employees. It is designed for small businesses and has been used in various incarnations over a period of about eight years. Because of that, it gets right down to what you really need to fill out the required forms and keep acceptable records of employees. It provides each employee with a pay stub for each pay period, a list of employees and, most important, a report of accumulated quarterly earnings and deductions needed to make proper deposits and complete the required quarterly forms. It also provides information for W-2 Forms at the end of the year and allows both quarterly and year-end clearing. THE OVERALL VIEW The program establishes a sequential disk file for each employee. Every time you do anything with an employee, that file is loaded from disk, operated on and then written back to the disk. One other sequence file is established, containing only the FILE NAMES of all the active employee files. When you do the payroll, or clearing, it is this file which automatically points to and gets the proper employee files. It is also this file which will tell you whom your employees are when you type in a wrong name. The program is menu-oriented, with options to do the payroll, edit a pay record, print reports, add or delete employees, clear records, and end the session. Let's start at the beginning of the program and explain what's happening top to bottom. PROGRAM DETAILS In line 170 we dimension two arrays; E() is the number of elements in each employee record and E$() is an array of the file names of up to 10 employees. Line 180 asks for a date which will be posted on the pay stubs and your reports. You can enter it any way you like. If your computer keeps the date internally (it's usually called DATE$), simply change line 180 to: 180 D$=DATE$. That way, you won't even be asked for the date, it will pick it up from the system. Lines 200 through 340 are remark lines that identify some important variables. In line 350 we read in the employee file name file, and then immediately write it out again. This happens many times with this program. Whenever we add or delete an employee we update this file right away so that during one session where we might add one employee and delete another, the file is always exactly current. Lines 370 through 400 establish some of the variables that are apt to change with the dictates of the IRS or the state in which you live. Putting them up front makes them easy to find and change, and making variables of them makes the change global. Some of these have a nasty habit of changing every year. In line 410, we define FNI(X) as a defined function. This is a rounding function, so we don't end up with paychecks with $125.100234 or something equally ridiculous. Your company name and address are hard coded into lines 420 through 440. They will appear at the top center of your reports, and as a one-line entry across the top of each pay stub. The menu comes next and is straightforward. INKEY$ is used to limit the choices to only those available. DO THE PAYROLL MODULE The first module we encounter is the payroll module. It goes from line 620 through line 1040, and takes one employee at a time (per the pay names file), calculates the current pay period, updates the quarterly and year-to-date totals, prints the pay stub and writes the updated record back to the disk. If you have five or fewer employees, the pay stub will fit on a standard 8x11 sheet of paper; if you have more than five then two sheets will be required. Don't worry about it if you have a single sheet printer. The program will stop at each employee in any case to ask for hours worked and vacation, which will give you the opportunity to change the paper if necessary. Entering zero for hours worked will skip over an employee. This was added so that if an employee takes a week off without pay, for example, you can exclude him or her from the current payroll. Let's go to line 720 and see what hapens. N1 is always the number of names in the pay names file, and because of what we said earlier, should always be the current number of active employees. Let's say that the first name in the pay names file is John. There will then be a file on disk with the filename John, and in that file his full name might be JOHN Q. PUBLIC. In line 730 we then equate E$ to E$(1). E$(1) equals JOHN and now E$ equals JOHN. We then go to the "open employee file and read subroutine" at line 2830. While we are there, we will open the sequential file for input and get John's full name, E1$ and his social security number. We then go into a little loop and read in 19 items (from 0 to 18) of information concerning John. After that, we close the file and return. We now have John's record in memory. We then ask how many hours John worked and if vacation time were taken and then calculate his current pay. This all happens from 740 through 840. While in those lines, we also update his quarterly and year-to-date totals. In line 850 we go through a one-line loop and round all the calculated values, using the defined function we set earlier in the program. Line 860 prints your company name, address, city, state and ZIP in one line across the top of the pay stub. The following lines through 980 print the remainder of the pay stub. We are now finished with John, so in line 1000 we go to the subroutine that writes John's updated record back to the disk. Upon returning, we check to see if this was the fifth pay stub we have printed. If so, we tell the printer to form feed to the next page. We then go on to get the next employee record from the pay names array E$(2). After we have cycled through all the valid pay names, we end up at line 1030, which forces a form feed to the printer, and then we return to the main menu -- the payroll is done. You can now slice up the page of pay stubs and insert them into the pay envelope with the paycheck, or if you like, make a photo copy of it for your records. EDIT OR REVIEW A PAY RECORD This module allows you to examine a pay record and if necessary, make changes to it. In line 1080 we enter the file name of the person whose record we wish to see. The very next thing that happens is that we go to a subroutine at 3090 to see if this is a valid name. That subroutine compares the name we just typed in with those in the pay names file (remember that they were read into memory and into array E$() early on in the program?) and if an exact comparison is not found, it tells you so and gives you a list of the valid pay names and a chance to try again. This prevents mixups and also a lot of "file not found" errors and "bad file name" errors. Here is also a good place to mention that you may not have the same file name for more than one employee. If you have two people named Bob, for example, call one BOB and the other BOB1 or BOB plus the first letter of his last name. Having found a valid employee, we then go (in line 1100) to the read employee record subroutine. The information is then displayed on the screen in lines 1120 through 1240. Lines 1250 through 1350 need some explanation. First off, if we choose to correct nothing, we enter zero in line 1250. The next line, 1260, will not operate because X2$ is now a null string. So in line 1270 we go through a loop to clear all the variables of the record at which we just looked from memory. Yes, they are still there, and they are on the disk too, but since we have made no changes, there is no point in writing them back. The reason we have to clear this record from memory is that if you first look at one employee record and then go on to create a new pay record and then go on to create a new pay record for someone else, the new record would pick up all the data from the record just viewed. Now, after clearing the data from memory, we go back to the main menu. Now let's assume we want to make a change to the record. In line 1250 we enter the item number. Since XX is now equal to something other than zero, line 1260 will be skipped again, and so will line 1270. In line 1280 we check to see if the number is in the allowable range of numbers and if not, go back and ask for it again. Now in line 1290 we enter the correct information as X$. We use a string here because two of the items in each pay record are strings, the name and social security number. They are items 1 and 2. In lines 1300 and 1310, if XX is 1 or 2, we exchange X$ with the name or social security number. But the remainder of the items in the pay record are all integers, and they start with zero after the name and social security number. So in line 1320, if XX is greater than 2, we simply subtract 3 from XX and make that array element in the pay record equal to the value of X$. Lines 1330, 1340 and 1260 allow us to make multiple changes to the record before writing it back to the disk or going back to the main menu. If the answer in line 1330 is anything but Y or y, we write the record to disk in line 1350, then clear X2$ and go to line 1110 where the updated record is re-displayed. From there we can choose zero to get back to the main menu. If we do want to make more changes, line 1340 sends us to line 1250, where we select the number and make the change. If we had noted we wanted to make a change and then at line 1250 selected zero, line 1260 finally comes into play and forces us to change something. PRINT PAYROLL REPORTS The reports module is between lines 1360 and 1900. Two different reports are provided. The second is simply a list of your employees with their full names, social security numbers and those items which are fixed, like withholding percentage and medical deductions. The first report is the one that will be used most often, as it keeps a running total of amounts paid and withheld. It also calculates accumulated income tax and FICA liability for the current quarter. As we did earlier, the pay names array is read to find whom the current employees are. Then each pay record is read in and the appropriate values are summed in variables T1 through T8. Tax liability is figured in line 1720, and consists of two times the withheld FICA plus the income tax withheld. Depending on which state you live in, it also provides most of the information needed in filling out quarterly reports for state employment security and for whatever form of state workman's compensation you have. There is certainly nothing exotic about the code in this section. It simply totals data and prints it out in report form. ADD OR DELETE EMPLOYEES The add employee module runs from line 1900 through 2220. The sub-menu in this section allows you to add, delete or return to the main menu. The usual error trapping at the menu is provided for. Making a new employee record consists of nothing more than entering six pieces of information. See lines 2010 to 2100. The rest of that new employee record will contain zeroes until the first time the worker is included in a payroll, when the zeroes will change to other values. After the basic information for the new employee is entered, we ask for a first (or file) name for that employee. In lines 2130 through 2150, we check the name just entered against those already in the pay names array. If the name is already being used, we get the chance to give another, different name. If it is unique, we go on to line 2170, which sends us to the "open file and write" subroutine at 2750. That will place the new employee record on disk. But now we need to tell our little index file, the pay names file, that we have a file name to add to it. The three lines of code that do this are at 2180 through 2200. What they do is read the pay names file and look for the first blank space, then put out new names into that blank. The other part of line 2190, where E$(I)="ONE" is for the first-time initialization of the program, when there are no names at all in the pay names file. If we try to run this program with no files initialized, we will get a "file not found" error. So the first time we find it, (and this is the only time we need to do this), we load the program, then type, in command mode, this statement: E$="ONE":GOTO 2920 and press Return. The program will then create the pay names file on disk. It will contain the word "ONE" and there will be a "return without gosub" error on your screen. Ignore the error and simply run the program. From here on in, you will never need to worry about it again. Oh yes, at this point you should immediately go to the add employee menu and put at least one employee into the system. Because of line 2190, the "ONE" in the pay names file will then be replaced by that first employee file name. Keep this little procedure in mind. We will use it again in a slightly different way to re-activate a previously deleted employee later. The delete section is covered from lines 2230 through 2390. It is very easy to do. We simply give the file name of the employee to delete, find it in the pay name file and change it to a null string. In line 2390, we then go to the subroutine which writes the pay names file to disk, and when it finds the null string it skips over it so that the names will be contiguous in the file. It then reads the pay names file back into memory. Now, that employee will no longer be included in payrolls or reports, but the employee file is still on the disk with all its data. Let's suppose Tom, Dick and Harry all work for you and all employed since January. In June, Harry decides to take off three months to go fishing in Alaska. When he goes, you carry him till the end of the quarter (end of June) by entering a zero for hours worked when you do the payroll. After you have cleared the quarter at the end of June, you can delete Harry and not worry about him until he comes back from Alaska in September. Then, before you do the first payroll on which he will be paid, you load the program and in command mode (assuming you still have Tom and Dick), you type E$(3)="HARRY":goto 2920 and press Return. Ignore the "return without gosub" error and run the program. Harry will be reinstated as an employee with all of his year-to-date information intact. Note that this is very similar to starting the program for the first time. Only this time the E$() subscript is three, because Tom is 1 and Dick is 2. Always reinstate an employee at the end of the list of pay names, regardless of where he or she was in the lineup before being deleted. END OF QUARTER/YEAR CLEARING This module resides between lines 2400 through 2670. Once again, we read the pay names file and cycle through the pay names array to fetch the individual pay records. If the quarter is being cleared, only items 11 through 18 in each pay record are set to zero, since these are all quarterly items. If year-end clearing is selected, then items 5 through 18 are cleared, which clears the year-to-date totals as well as the current quarter. This selection is made in line 2570 and executed in line 2610. Other than that, the clearing module is easy code to follow. To prevent clearing anything by mistake, the words (in capital letters) QUARTER or YEAR must be typed into effect the clearing; otherwise, line 2560 will send you back to the main menu. After all records for all active employees have been cleared, line 2670 will return you to the main menu. END SESSION MODULE The end session module is the shortest and easiest. It resides betwen lines 2680 and 2730 and consists of nothing more than a reminder to back up your files. It then simply runs into an END statement in line 2740 and gives the BASIC OK prompt. SUBROUTINES There are four subroutines which are called repeatedly from the main program. The first is the "Write employee pay record" subroutine from lines 2740 through 2810. The next subroutine, from lines 2820 through 2900, is the "Read employee pay record" subroutine. The next subroutine both writes and then reads back the pay names sequential file. Notice that there is no RETURN or END at the end of the write portion; it goes directly to the file and then is read back immediately. This keeps the valid pay names as up to date as possible during operation of the program. Also note in line 2950 that when writing the pay names to disk, if a null string is found (presumably because of a deletion), the null is not written to the disk but goes to the NEXT I instead. This insures that the valid pay names are at the beginning of the pay names file with no gaps. THE WHO IS REAL? SUBROUTINE The last subroutine of the program, starting at line 3080 and continuing through 3220, is used any time you ask for any employee pay name. It checks through the pay name file and looks for a match, and if it finds one, it returns to wherever you came from. In line 3100 it also checks to see if you simply pressed the Return key instead of entering a name. If you did press Return or an invalid pay name, line 3130 tells you so and then gets the valid names from the pay names array and prints them for you to see. It then asks which one you want, and will continue to do so until you get it right. This sounds dictatorial, but remember that we are messing with someone's pay here, and it should be done right. SUGGESTED ADDITIONS As mentioned at the very beginning of this article, making a program that applies to all states and situations would be formidable. Once you study this program you should be able to modify it sufficiently to take care of your special cases. One of the things that could be added is a check writer. Here again, there are so many conventions and spacings on available check stock that you almost need to do your own. In the "do the payroll" module you could easily print the pay stub above a tractor feed check, then jump to a subroutine at the end of this program, where a check would be written. ANother feature that could be added is the computation of overtime. You could simply convert overtime hours to straight hours, but be careful. If your state computes anything on hours (ours does) then you would be off here. W-2 form information is all contained on the last pay stub of the year. If you do not routinely make copies of your pay stubs, this is one you will want to copy. END OF TEXT