* *************** PAYROLL COMMAND FILE ********************************
* This  command file generates payroll check stubs showing all deductions; gets
* the next check number and writes a check in the CheckFile, showing the new
* balance; and stores the salaries and deductions in a database called Hold81.
* This file is used to store monthly, quarterly and annual FIT, FICA, SDI
* and SIT deductions.  The deductions are not picked up from tax tables because
* there are so few employees.  Instead, they are obtained from the individual
* employee records in the Personnel database.
*	Constants.MEM keeps track of the FICA and SDI percentages and their
* maximums, as well as the constant for ThisYear.  Changes can be thus
* made in a single spot and will be correct in all the programs in the
* accounting system.
* The file is quite long, but breaks down into simpler modules:
*	I:  Get the date and End of Month, Quarter and Year flags.
*      II:  Compute all deductions and net pay for an individual employee, then
*	    place this in the employee record in Personne.DBF
*     III:  Operator verifies deductions and payroll stub is printed.
*      IV:  Paycheck is written to the Checkfil and all amounts are placed into
*	    the Hold81 summary file.
*	V:  When all individuals have been paid, the Hold81 summary file is
*	    updated if it is the end of the month, quarter or year.
*      VI:  Print out the summary file and data so that the physical checkbook
*	    can be updated (computer does not print our checks).
*     VII:  Delete transient constants, save others back to Constant.MEM for
*	    system use.
****************************************************************************

**********************************************************
*************	I: Get date and pay period flags *********

RESTORE FROM B:Constant
DO GetDate

STORE 'Y' TO GetWhen
DO WHILE !(GetWhen) = "Y"
   ERASE
   @ 1,18 SAY "PAYROLL PROCESSING"
   STORE " " TO EOY
   @ 4,8  SAY 'Want to change the date?' GET Date
   @ 5,8  SAY '(Press <Return> if okay.)'
   READ
   @ 7,6  SAY "Is it the end of the YEAR?" GET EOY
   @ 7,35 SAY "(Y or N)"
   ? CHR(7)
   READ
   STORE !(EOY) TO EOY
   IF EOY = "Y"
      STORE "Y" TO EOQ
      STORE "Y" TO EOM
   ELSE
      STORE "N" TO EOY
      STORE " " TO EOQ
      @ 8, 3 SAY "Is it the end of the QUARTER?" GET EOQ
      @ 8,35 SAY "(Y or N)"
      ? CHR(7)
      READ
      STORE !(EOQ) TO EOQ
      IF EOQ = "Y"
	 STORE "Y" TO EOM
      ELSE
  	 STORE "N" TO EOQ
	 STORE " " TO EOM
	 @ 9, 5 SAY "Is it the end of the MONTH?" GET EOM
	 @ 9,35 SAY "(Y or N)"
	 ? CHR(7)
	 READ
	 STORE !(EOM) TO EOM
	 IF EOM <> "Y"
	    STORE "N" TO EOM
	 ENDIF monthly
      ENDIF quarterly
   ENDIF year

   ERASE
   @ 4,25 SAY $(Date,1,2)+'/'+$(Date,3,2)+'/'+$(Date,5,2)
   @ 6,0  SAY "End of YEAR: "+EOY"     End of QUARTER: "+EOQ+;
	      "     End of MONTH: "+EOM
   STORE " " TO GetWhen
   ?
   ? 
   @ 8,6 SAY 'The above information MUST be correct.     '
   ? CHR(7)
   * 2nd chance at date and flags
   ACCEPT '	        Any CHANGES (Y or N)?' TO GetWhen

   STORE 'B:Hold'+STR(ThisYear,2) TO Header
   * Computer now does a date and flag check
   IF !(GetWhen) <> 'Y'
      IF $(Date,5,2)<'26' .AND. EOM = 'Y'
	 ?
	 ?
	 ? "CHECK THE INFO AGAIN.  It's the end of the month, but the"
	 ? 'date is '+Date-'.  Do you want to make changes (Y or N)?'
	 ? CHR(7)
	 WAIT TO GetWhen
      ENDIF
      IF EOY = 'Y'
	 SELECT SECONDARY
	 USE &Header
	 GO BOTTOM
	 IF Marker = 'Y'
	    ? CHR(7)
	    ? 'You blew it--the end of the year has been done!'
	    WAIT
	    RELEASE ALL
	    STORE T TO Paying
	    RETURN
	 ENDIF
      ENDIF
   ENDIF
ENDDO GetWhen
RELEASE GetWhen


***************************************************************************
*********** II: Calculate deductions and net pay for each individual ******
* Compute deductions.  Deductions for FICA, FIT, SDI and SIT are kept in the 
* individual employee's Personnel record, rather than getting them from tax
* tables, because there are so few employees.  (You have to decide what should
* and should not be computerized.)  The "YTDxxx" are the year-to-date
* totals for these items.  Limits and percentages for FICA and SDI are obtained
* from a file called Constant.MEM.  These are the variables FICACut, FICAMax,
* FICAEnd, SDICut, SDIMax, and SDIEnd.

SELECT PRIMARY
 
USE B:Personne
REPLACE ALL FICA WITH (Pay:Rate*FICACUT+0.005);
              SDI WITH (Pay:Rate*SDICUT+0.005)

STORE 0 TO Count
GO TOP
DO WHILE .NOT. EOF
   IF Paid .OR. *
      SKIP
   ELSE
      STORE Count + 1 TO Count

      *** Save the employee record in case the procedure is ended ***
      STORE STR(#,5) TO Payee
      COPY Record &Payee TO Bak

      *** Deductions for partial salary based on number of days worked ***
      *** Ratio is computed in PayMenu.CMD
      IF Ratio < 1.0000
         REPLACE Pay:Rate WITH Pay:Rate*Ratio, FICA WITH FICA*Ratio, FIT;
                 WITH FIT*Ratio, SDI WITH SDI*Ratio, SIT WITH SIT*Ratio
      ENDIF

      * Deductions and totals are computed then stored in the employee
      * record FedTemp, Statemp and EmpTemp are used to carry forward
      * values for salaries subject to FICA, SDI and state unemployment
      * insurance to Hold81, the summary file.

      IF YTDSAL > FICAEnd
	 STORE 0 TO FedTemp
	 REPLACE FICA WITH 0
      ELSE
         IF (YTDSal + Pay:Rate) <= FICAEnd
             REPLACE YTD WITH (YTDFICA + FICA)
             STORE Pay:Rate TO FedTemp
         ELSE
             REPLACE FICA WITH (MAXFICA - YTDFICA), YTDFICA WITH MAXFICA
             STORE (FICAEnd - YTDSal) TO FedTemp
         ENDIF
      ENDIF

      IF YTDSal > SDIEnd
         STORE 0 TO StaTemp
         REPLACE SDI WITH 0
      ELSE
         IF (YTDSAL + Pay:Rate) <= SDIEnd
            REPLACE YTDSDI WITH (YTDSDI + SDI)
	    STORE Pay:Rate TO StaTemp
         ELSE
	    REPLACE SDI WITH (MAXSDI - YTDSDI), YTDSDI WITH MAXSDI
	    STORE (SDIEnd-YTDSal) TO StaTemp
         ENDIF
      ENDIF

      * In California,the employer pays an Unemployment Insurance 
      * contribution on employee salary up to the amount of UIEnd.There is 
      * nothing deducted form the employee salary for this, so we keep track
      * only of the employer obligation as UISal.

      IF YTDSal > UIEnd
         STORE 0 TO EmpTemp
      ELSE
         IF (YTDSal + Pay:Rate) <= UIEnd
            STORE Pay:Rate TO EmpTemp
         ELSE
            STORE (UIEnd - YTDSal) TO EmpTemp
         ENDIF
      ENDIF  

      REPLACE Net:Pay WITH (Pay:Rate-FICA-FIT-SDI-SIT)
      REPLACE YTDFIT WITH (YTDFIT + FIT)
      REPLACE YTDSIT WITH (YTDSIT + SIT)
      REPLACE QTDSal WITH (QTDSal + Pay:Rate)
      REPLACE YTDSal WITH (YTDSal + Pay:Rate)

      ***********************************************************************
      ***************** III: Print employee stub ********************
      ERASE
      SET PRINT ON
      ? '         '+$(DATE,3,2)+'/'+$(Date,5,2)+'/'+$(Date,1,2)+': '+Name;
            + '   '+$(SS:Nmbr,1,3)+'-'+$(SS:Nmbr,4,2)+'-'+$(SS:Nmbr,6,4)
      ? '          GROSS PAY: $'-STR(Pay:Rate,7,2)+'    NET PAY: $';
			        -STR(NET:PAY,7,2)
      ?
      ? '			   FICA        FIT	 SDI	   SIT'
      ? '	     THIS CHECK:  '+STR(FICA,6,2)+'    '+STR(FIT,7,2);
                           +'     '+STR(SDI,5,2)+'  ' +STR(SIT,7,2)
      ? '           THIS YEAR:  '+STR(YTDFICA,7,2)+'  '+STR(YTDFIT,8,2);
		          +'    '+STR(YTDSDI,6,2) +'  '+STR(YTDSIT,7,2)
      ? '			 TOTAL SALARY THIS QUARTER: $'-STR(QTDSal,9,2)
      ? '			    TOTAL SALARY THIS YEAR: $'-STR(YTDSal,9,2)
      ?
      ?
      ?
      * Pagefeed after every six employee stubs
      IF Count >= 6
         ? CHR(12)
         STORE 0 TO COUNT
      ENDIF
      SET PRINT OFF

      IF EOQ = 'Y' .AND. Paid
         REPLACE QTDSal WITH 0
      ENDIF

      ********************************************************************
      ******** IV: Record paycheck in Checkfil and Hold81 ****************

      * Now a check is "written" in the CheckFil.
      SELECT SECONDARY
      USE B:CheckFil
      APPEND BLANK
      REPLACE Check:Nmbr WITH NextCheck, Check:Date WITH date,;
	      Name WITH P.Name, Amount WITH Net:Pay, Emp:Nmbr;
	      WITH P.Emp:Nmbr, Client WITH 'OFC', Job:Nmbr WITH 31,;
	      Descrip WITH 'SALARY', Balance WITH (MBalance - Amount)
      STORE (MBalance - Amount) TO MBalance
      STORE STR(VAL(NextCheck)+1,4) TO NextCheck

      ERASE
      @ 3,25 SAY "** DO NOT INTERRUPT **"
      @ 5,25 SAY "UPDATING MASTER RECORD"
      ? CHR(7)
      * We keep an aggretate record of payroll and deductions.  The amounts
      * for each employee are added to the amounts already in the last
      * record in the file represented by "Header".  (This was set up at the 
      * start of the "GetWhen" loop earlier, and has the name "B:Hold81" or
      * "B:Hold82" or whatever "ThisYear" is.)
      *      This last record is either a blank (if this is the first
      * payroll of the month), or has data from previous salary payments
      * made during the current month.  At the end of the month, quarter and
      * year, totals and a new blank record (except at the end of the year)
      * are added.  This is done in the next loop.

      USE &Header

      * If this is a new year, there are no records in the file so we add a
      * blank record.  Otherwise, we go to the last record in the file.
      IF EOF
         APPEND BLANK
      ELSE
         GO BOTTOM
      ENDIF

      REPLACE Check:date WITH Date, Payroll WITH (Payroll+Pay:Rate),;
	      FICA WITH (FICA+P.FICA), FICASal WITH (FICASal + FedTemp),;
	      FIT WITH (FIT + P.FIT), SDI WITH (SDI+P.SDI),;
	      SDISal WITH (SDISal + Statemp), SIT WITH (SIT + P.SIT),;
      	      UISal WITH (UISal + EmpTemp)
      SELECT PRIMARY

      *** Reset the employee record if he was paid for part time. ***
      *** The Bak file is not deleted here, as each copy command  ***
      *** above wipes out the previous contents.		  ***
      IF Ratio <> 1.0000
         REPLACE Ratio WITH 1.0000
         UPDA FROM Bak on Emp:Nmbr REPL Pay:Rate,FICA,FIT,SDI,SIT,Net:Pay
      ENDIF
   ENDIF

   SKIP
ENDDO personnel file

*********************************************************************
******* V: Personnel records are reset and Holdxx is updated ********
STORE ' ' TO Completed
REPLACE ALL Paid WITH F

USE &Header
GO BOTTOM
IF EOM = 'Y'
   REPLACE Marker WITH 'M'

   * If it's the end of the quarter, we total the amounts for the
   * previous three months to a new record and mark it with a 'Q'.
   IF EOQ = 'Y'
      STORE STR(#,5) TO Number
      TOTAL ON Marker TO Quarter FOR # >= (VAL(Number)-2)
      APPEND FROM Quarter
      DELETE FILE Quarter

      IF $(Date,3,2) = '03'
         REPLACE Check:Date WITH '1ST'
      ELSE
	 IF $(DATE,3,2) = '06'
	    REPLACE Check:Date WITH '2ND'
	 ELSE
	    IF $(Date,3,2) = '09'
	       REPLACE Check:Date WITH '3RD'
	    ELSE
	       IF $(Date,3,2) = '12'
		  REPLACE Check:Date WITH '4TH'
	       ENDIF
	    ENDIF
         ENDIF
      ENDIF

      REPLACE Marker WITH 'Q'

      * If it's the end of the year, we total all the quarterly amounts to
      * a new record and mark it with a 'Y'.
      IF EOY = 'Y'
	 TOTAL ON Marker TO Annual FOR Marker = 'Q'
	 APPEND FROM Annual
	 REPLACE Marker WITH 'Y', Check:Date WITH 'END'
	 DELETE FILE Annual
      ENDIF
   ENDIF

   * If it's the end of a month but not the end of the year, we add a new
   * blank record for next month's payroll records.
   IF EOY <> 'Y'
      APPEND BLANK
   ENDIF
ENDIF

*************************************************************************
******** VI: Print payroll summary, transfer checks to costbase *********
USE B:CheckFil
COUNT FOR .NOT. * TO Any
IF Any = 0
   ? '        No new checks written.'
   ? '     <Return> to continue.'
   WAIT
ELSE
   USE &Header
   ERASE
   @ 12,25 SAY "CHECK THE PRINTER, THEN PRESS <RETURN>."
   ? CHR(7)
   WAIT
   ERASE
   SET PRINT ON
   * SET MARGIN TO 45
   SET MARGIN TO 17
   ? '             MASTER PAYROLL FILE SUMMARY: '+$(Date,3,2) +'/';
              +$(Date,5,2)+'/'+$(Date,1,2)
   ?
   ?
   ?'DATE   PAYROLL    FICA    FICASAL     FIT    SDI   SDISAL      '+;
                'SIT    UISal'
   ?
   LIST OFF
   * SET MARGIN TO 38
   SET MARGIN TO 10
   ? CHR(12)
   SET PRINT OFF

   ERASE
   @ 3,25 SAY "*** DO NOT INTERRUPT ***"
   @ 5,25 SAY " UPDATING THE COSTBASE"
   ? CHR(7)

   USE B:CostBase INDEX B:$Supp
   APPEND FROM B:Checkfil

   DO CheckStu 
ENDIF

***********************************************************************
****** VII:  Dump transient variables, save necessary ones ************
RELEASE Payee,Number,Date,Ratio,Aborted,Printed,EOY,EOQ,EOM,Any,Header,;
        Count, FedTemp, StaTemp, EmpTemp, Marker, Paying, Salaries
SAVE TO B:Constant

USE 
RELEASE ALL
DELETE FILE Bak
RETURN
