'===========================================================================
' Subject: PERSONAL EXPENSE RECORDER          Date: 11-25-95 (00:00)       
'  Author: Dave Gjessing                      Code: QB, QBasic, PDS        
'  Origin: dgjess@freenet.columbus.oh.us    Packet: MISC.ABC
'===========================================================================
'November 25, 1995
'file PER12QB.BAS
'"Personal Expense Recorder"
'Copyright Dave Gjessing 1995
'
'the README file:
'
'PER is intended to be a quick, simple means to record one's day-to-day
'expenses, and to generate handy reports about same. If you are a
'bean-counter type person, you will find it to be completely inadequate,
'and should not waste your time looking at it. If (on the other hand) you
'are a normal person, you just might find it useful.
'
'To use:
'
'While in the directory where the .BAS file resides, type -> qbasic
'Once it is loaded, press SHIFT+F5
'
'The program will ask for a passcode. Since you have not yet set up a
'code, you simply press ENTER.  The main menu will come up.
'
'Press S, to go to the set-up menu. Press 1, and type in your name and a
'passcode. The passcode must be a number. (From here on out you will need
'to type in your passcode when the program starts).
'
'Back at the set-up menu, press 2, to add expense categories. Category
'names may be up to 16 characters long. Some examples: food, shelter, and
'utilities. You also need to provide a two-character category code. For
'the examples above, these might be fo, sh, and ut. You are given a
'chance to accept or re-do each entry. (You may also edit them later on).
'
'Repeat the process for all your expense categories. Don't get carried
'away with creating categories; each entry also has a note attached to
'it. The note is where you should be specific. (I have been getting along
'fine for three months with 15 categories).
'
'Also at the set-up menu, you may fool around with the screen colors. The
'default colors are 1,15.
'
'Once you have set up your categories, return to the main menu.
'
'Press N, to add new expenses. You will be presented with a data file
'name to either accept or reject. The program creates a new file each
'month. The files are named [MMYY]QPER.DAT. If the filename being
'presented to you is the wrong one for the current month, then you need
'to go to DOS and correct your system's date. You may do this from the
'main menu. You may want to add an entry for the month that just ended;
'in that case press ESCAPE, and tell the program the month and year that
'you wish to work with. In most case though, you will simply press ENTER,
'to accept the file shown (the current month's file). Next, you may
'either accept or change the day. If you are recording an expense from a
'few days ago, type in the new day. (Note that you cannot name a new
'month or year at this point; only a new day). In most cases, you will
'again simply press ENTER to accept the current day. Now you have to pick
'a category. (The reasoning behind the two-character category codes will
'now become apparent to you (if there was any doubt)). Pick one, and then
'you must enter in the dollar amount (dollars and cents). You may then
'enter in a short note (up to 40 characters). Next, your entire new entry
'is presented for your approval. Press Y to accept the entry, N do do it
'all over, or Q to quit back to the main menu and forget all about it.
'
'That's all there is to entering expenses. Now to look at what you have
'done...

'At the main menu, press R for reports, and then A, S, or C. A (All
'Expenses for Month) will give you a complete listing of all the line
'items for all categories for a given month. S (Monthly Summary) will do
'a short report; just totals for each category, and the percentage of the
'grand total that each represents. C (Expenses per Category) will show
'all line items in a given month, for a given category.
'
'With all reports, you are offered a chance to save the report to either
'a file or to a printer. If you save to a file you may import the report
'into any wordprocessing program.
'
'Finally, at the main menu you may press E to edit existing records. You
'have a choice of editing Entries or Categories. You can change anything.
'Be aware that if you eliminate a category code, the program will not be
'able to find prior entries (entered under the old code). I would suggest
'writing down all your category codes. You may need them if you screw up
'whilst editing.
'
'Which brings us to crisis prevention. If you forget your passcode, go to
'DOS and delete the file PERSONAL.DAT. This will allow you to get back
'into the program (but you will have to re-do name, passcode, and
'colors). If you trash your category codes while editing, delete the file
'CATEGORY.DAT, and re-create it at the set-up menu, with the information
'that you wrote down earlier.
'
'                                 ***
'
'This computer programing stuff is great fun. I've been at it in earnest
'for about four months now. This program is written in Visual Basic for
'DOS (although it does not use any of the slick features available in
'VBDOS). This particular version has been converted to run under the QBasic
'interperator.
'
'In the original VB version I used the CURRENCY data type for entry.amount.
'QBasic does not recognise that, so it has been changed to DOUBLE.
'
'I hope that the source code might be helpful to other budding nerds like
'myself. After all, I've spent an absurd amount of time working on this
'thing, gleaning bits of stuff from other people's programs. To all from
'whom I have learned stuff, here is something back! I hope it is useful.
'
'dgjess@freenet.columbus.oh.us
'
'*************************************************************************
'start of the program:
'
DECLARE SUB editentries ()
DECLARE SUB editcategories ()
DECLARE SUB line25 ()
DECLARE SUB sumfile (sumfilename$)
DECLARE SUB sumprint ()
DECLARE SUB selectcolors ()
DECLARE SUB calcsubtotal ()
DECLARE SUB sumscreen ()
DECLARE SUB perhelp (topic$)
DECLARE SUB afmscreen ()
DECLARE SUB background (character%)
DECLARE SUB pcfile (pcfilename$)
DECLARE SUB drawborder (UpRow%, LeftCol%, BotRow%, RtCol%, bgc%)
DECLARE SUB pcprint ()
DECLARE SUB afmprint ()
DECLARE SUB afmfile (afmfilename$)
DECLARE SUB pcscreen ()
DECLARE SUB getamount ()
DECLARE SUB getnote ()
DECLARE SUB getcategory ()
DECLARE SUB addcategories ()
DECLARE SUB getday ()
DECLARE SUB displaycategories ()
DECLARE SUB selectfile ()
DECLARE SUB getpass ()
DECLARE SUB getpersonaldat ()
COMMON SHARED bgc%      'background color - user-defined in setup
COMMON SHARED fgc%      'forground color - user-defined in setup
DEFINT A-Z

'************************************************************************
'Today's notes... (11/26/95)

'I have moved mass quantities of code from module level to sub level,
'where it belongs, and eliminated tons of SHARED statements.

'I need to work on reporting over a range of months.

'I also plan to make the program multi-user - PERSONAL.DAT will hold any
'number of passcodes; the code entered tells the program who's data files
'to access. Of course, the name of the data files will have to be revised.

'************************************************************************
'define the form of the PERSONAL.DAT file record
    TYPE personal
        uname AS STRING * 30     'the user's name
        passcode AS SINGLE      'a numeric passcode
        bgc AS INTEGER          'background color
        fgc AS INTEGER         'forground color
    END TYPE
DIM SHARED userid AS personal
'************************************************************************
'define the form of the CATEGORY.DAT file records
    TYPE category
        code AS STRING * 2      'two-character code, easy to remember
        label AS STRING * 16    'full description, tied to the code
    END TYPE
DIM SHARED whatfor AS category
'************************************************************************
'define the form of the expense record file entries
    TYPE expenrec
        day AS STRING * 8       'the date of the expense
        catcode AS STRING * 2   'taken from whatfor.code
        amount AS DOUBLE        'the money
        note AS STRING * 40     'optional note
    END TYPE
DIM SHARED entry AS expenrec
'************************************************************************
DIM SHARED workfilename AS STRING   'the data file currently in use
DIM SHARED screenfull AS INTEGER    'for report subs - a screenfull of stuff
DIM SHARED linenum AS INTEGER       'for printing - a pagefull of stuff
screenfull = 18
linenum = 0

'************************************************************************
CLS
getpass         'very simple passcode "protection"

'************************************************************************
'OK, the user is in and we are up and running...

top:
CLS
COLOR fgc%, bgc%
background (176)    'number in parenthesis is ASCII character code
                    'can be any one you want

CALL drawborder(8, 8, 16, 72, bgc%) 'draw the box around the menu
COLOR 14, bgc%                             'the main menu...
LOCATE 8, 23
PRINT " PERSONAL EXPENSE RECORDER .12(QB) "
COLOR fgc%, bgc%
LOCATE 10, 29
PRINT "N) Enter New Expenses"
LOCATE 11, 29
PRINT "R) Generate Reports"
LOCATE 12, 29
PRINT "E) Edit Existing Records"
LOCATE 13, 29
PRINT "S) Personal Set-Up"
LOCATE 14, 29
PRINT "D) Set System Date"
LOCATE 16, 29
COLOR 14, bgc%
PRINT " (H)elp - ESC to Quit ";
CALL line25
    DO                                  'main menu selection process...
    mainchoice$ = INKEY$
    mainchoice$ = UCASE$(mainchoice$)
    IF mainchoice$ = "N" THEN CLS : GOTO startnewentry
    IF mainchoice$ = "R" THEN CLS : GOTO reportsmenu
    IF mainchoice$ = "S" THEN CLS : GOTO setup
    IF mainchoice$ = "E" THEN CLS : GOTO editing
    IF mainchoice$ = "H" THEN CLS : CALL perhelp("main"): GOTO top
    IF mainchoice$ = "D" THEN CLS : SHELL "date": GOTO top
    IF mainchoice$ = CHR$(27) THEN : CLOSE : COLOR 7, 0: CLS : END '*SYSTEM
    '* a little QBasic trick: (excuse me if this is common knowlege)
    'If the last command in your program is SYSTEM, you will leave the
    'QBasic environment automaticaly upon termination. This can be used
    'to make it seem like your un-compiled .BAS program runs as a stand-alone
    'program, when you start it with a batch file. For instance, write a
    'per.bat file, as follows:
        'copy con per.bat
        'qbasic /run per12qb
        '<F6>
    'Now replace the END statement above with SYSTEM
    'Now, at the DOS command line, type per
    'The program will load up and run without any further intervention,
    'and when you exit it, you will be puked back onto the command line.
    '"We don't need no stinking compiler!" <bg>
    'End of trick.
        LOCATE 25, 63
        PRINT TIME$; 'this is not in line25 because it changes constantly
    LOOP
'************************************************************************
startnewentry:                  'begin gathering data for new entry
selectfile                      'chose the data file to write to
getday                          'get the day within the selected month
displaycategories               'show the available expense categories
getcategory                     'pick one
getamount                       'get the amount of money (negetive is OK)
getnote                         'get the note about the expense
CLS
'show the data entered, and find out if it is all OK...
COLOR fgc%, bgc%
CALL drawborder(9, 8, 15, 72, bgc%) 'draw the box around the menu
LOCATE 8, 27
COLOR 12, bgc%
PRINT " New Entry Confirmation !"
LOCATE 10, 12
COLOR fgc%, bgc%
PRINT "Record File..: "; workfilename$
LOCATE 11, 12
PRINT "Date.........: "; entry.day
LOCATE 12, 12
PRINT "Category.....: "; entry.catcode; "    ("; RTRIM$(whatfor.label); ")"
LOCATE 13, 12
PRINT USING "Amount.......: $##,###.##"; entry.amount
LOCATE 14, 12
PRINT "Note: "; entry.note
LOCATE 16, 27
COLOR 14, bgc%
PRINT " Is all this OK? (Y/N/Q) "

    DO
    newentryconf$ = INKEY$
    newentryconf$ = UCASE$(newentryconf$)
    IF newentryconf$ = "Y" THEN GOTO recordnewentry
    IF newentryconf$ = "N" THEN GOTO startnewentry      'start over
    IF newentryconf$ = "Q" THEN GOTO top        'never mind, forget it
    LOOP

'if it is all OK, then write it to the selected data file...
recordnewentry:
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)
numrecords = LOF(3) / LEN(entry)
newplace = numrecords + 1
PUT #3, newplace, entry
CLOSE 3
PRINT
COLOR 14, bgc%
LOCATE 18, 25
PRINT " New entry has been recorded ": SLEEP 1
COLOR fgc%, bgc%
GOTO top
'************************************************************************
reportsmenu:
CLOSE
linenum = 0                     'initialize the number of text lines shown
CLS                             'on the screen to *0*
LOCATE 9
CALL drawborder(9, 8, 15, 72, bgc%) 'draw the box around the menu
COLOR 14, bgc%
LOCATE 9, 20
PRINT " Personal Expense Recorder Reports Menu "
COLOR fgc%, bgc%
LOCATE 11, 27
PRINT "A) ALL Expenses for Month"
LOCATE 12, 27
PRINT "S) Monthly Summary"
LOCATE 13, 27
PRINT "C) Expenses per CATEGORY"
COLOR 14, bgc%
LOCATE 15, 28
PRINT " ESC return to main menu "
COLOR fgc%, bgc%
CALL line25
    DO
    reportschoice$ = INKEY$
    reportschoice$ = UCASE$(reportschoice$)
    IF reportschoice$ = "A" THEN CLS : CALL selectfile: GOTO allformonth
    IF reportschoice$ = "S" THEN CLS : CALL selectfile: GOTO monthsummary
    IF reportschoice$ = "C" THEN CLS : CALL selectfile: GOTO pcscreen
    IF reportschoice$ = CHR$(27) THEN CLS : GOTO top
        LOCATE 25, 63
        PRINT TIME$;
    LOOP

'**************************************************************************
allformonth:
afmscreen
PRINT
COLOR 13, bgc%
PRINT "                 would you like to save this report?"
PRINT
COLOR fgc%, bgc%
PRINT "                     to save to a file press F"
PRINT "              to send the report to your printer press P"
PRINT "                  press ENTER to forget all about it"
    DO
    afmchoice$ = INKEY$
    afmchoice$ = UCASE$(afmchoice$)
    IF afmchoice$ = "F" THEN GOTO afmfile
    IF afmchoice$ = "P" THEN GOTO afmprint
    IF afmchoice$ = CHR$(13) THEN GOTO reportsmenu
    LOOP

afmfile:
CLOSE
PRINT
LINE INPUT "filename:  "; afmfilename$
'half-assed bad filename detection...
IF afmfilename$ = "" THEN BEEP: CLS : PRINT "bad filename": SLEEP 2: GOTO reportsmenu

afmfile (afmfilename$)

CLS
CLOSE
LOCATE 12, 20
PRINT "report written to "; afmfilename$
SLEEP 2
GOTO reportsmenu

afmprint:
afmprint
GOTO reportsmenu
'***************************************************************************
monthsummary:
CLOSE
PRINT
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1
grandtotal# = 0             'initialize the grand total to 0
'figure the grand total...

    WHILE counter < numrec
        FOR X = counter TO counter
            GET #4, X, whatfor
            selectedcatcode$ = whatfor.code
            selectedcatlabel$ = whatfor.label
            counter = counter + 1
            CALL calcsubtotal
    grandtotal# = grandtotal# + subtotal#
    NEXT    'finished with category?, OK, on to the next one...
WEND        'no more categories?, OK, finish the report

sumscreen
PRINT
COLOR 13, bgc%
PRINT "                 would you like to save this report?"
PRINT
COLOR fgc%, bgc%
PRINT "                     to save to a file press F"
PRINT "              to send the report to your printer press P"
PRINT "                  press ENTER to forget all about it"
    DO
    sumchoice$ = INKEY$
    sumchoice$ = UCASE$(sumchoice$)
    IF sumchoice$ = "F" THEN GOTO sumfile
    IF sumchoice$ = "P" THEN GOTO sumprint
    IF sumchoice$ = CHR$(13) THEN GOTO reportsmenu
    LOOP

GOTO reportsmenu

sumfile:
CLOSE
PRINT
LINE INPUT "filename:  "; sumfilename$
'half-assed bad filename detection...
IF sumfilename$ = "" THEN BEEP: CLS : PRINT "bad filename": SLEEP 2: GOTO reportsmenu
    
sumfile (sumfilename$)
CLS
CLOSE
LOCATE 12, 20
PRINT "report written to "; sumfilename$
SLEEP 2
GOTO reportsmenu

sumprint:
sumprint
GOTO reportsmenu

'***************************************************************************
pcscreen:
displaycategories
getcategory
pcscreen

PRINT
COLOR 13, bgc%
PRINT "                 would you like to save this report?"
PRINT
COLOR fgc%, bgc%
PRINT "                     to save to a file press F"
PRINT "              to send the report to your printer press P"
PRINT "                  press ENTER to forget all about it"
    DO
    pcchoice$ = INKEY$
    pcchoice$ = UCASE$(pcchoice$)
    IF pcchoice$ = "F" THEN GOTO pcfile
    IF pcchoice$ = "P" THEN GOTO pcprint
    IF pcchoice$ = CHR$(13) THEN GOTO reportsmenu
    LOOP

pcfile:
PRINT
LINE INPUT "filename:  "; pcfilename$
IF pcfilename$ = "" THEN BEEP: CLS : PRINT "bad filename": SLEEP 2: GOTO reportsmenu
pcfile (pcfilename$)
CLS
CLOSE
LOCATE 12, 20
PRINT "report written to "; pcfilename$
SLEEP 2
GOTO reportsmenu

pcprint:
pcprint
GOTO reportsmenu

'************************************************************************
editing:
CLS
LOCATE 9
PRINT "                             Edit what?"
PRINT
PRINT "                             (E)ntries"
PRINT "                             (C)ategories"
PRINT "                             (Q)uit"
    DO
    editchoice$ = INKEY$
    editchoice$ = UCASE$(editchoice$)
    IF editchoice$ = "E" THEN CLS : GOTO editentries
    IF editchoice$ = "C" THEN CLS : GOTO editcategories
    IF editchoice$ = "Q" THEN CLS : GOTO top
    LOOP

editentries:
editentries
GOTO top

editcategories:
editcategories
GOTO top

'************************************************************************
setup:
setupmenu:
CLS
LOCATE 9
PRINT "                  Personal Expense Recorder Set-Up Menu "
PRINT
PRINT "                        1) set name, passcode"
PRINT "                        2) add expense categories"
PRINT "                        3) set colors"
PRINT "                        M) go back to main menu"

    DO
    setupchoice$ = INKEY$
    setupchoice$ = UCASE$(setupchoice$)
    IF setupchoice$ = "1" THEN CLS : GOTO personaldat
    IF setupchoice$ = "2" THEN CLS : GOTO categories
    IF setupchoice$ = "3" THEN CLS : CALL selectcolors: GOTO setupmenu
    IF setupchoice$ = "M" THEN CLS : GOTO top
    LOOP

personaldat:
getpersonaldat
GOTO setupmenu

categories:
displaycategories
PRINT
addcategories
GOTO setupmenu
GOTO top

'************************************************************************
END
handler:
CLS
BEEP
LOCATE 12, 30
PRINT "check your printer"
SLEEP 2
CLOSE

                            'quick fix to stop termination upon
RESUME top                  'off-line printer in the reports sections
'************************************************************************
                            'end of program

DEFSNG A-Z
SUB addcategories
startaddcategories:

INPUT "New Category Name      "; newlabel$
INPUT "Two-place abbreviation "; newcode$

    IF LEN(newcode$) <> 2 THEN BEEP: GOTO startaddcategories
    newcode$ = UCASE$(newcode$)
    whatfor.label = newlabel$
    whatfor.code = newcode$
    
PRINT
PRINT "New entry confirmation: "; whatfor.code; "  "; whatfor.label
PRINT
PRINT "press ESCAPE to do over, ENTER if OK"

    DO
    verifyaddcategorieschoice$ = INKEY$
    IF verifyaddcategorieschoice$ = CHR$(13) THEN GOTO endaddcategories
    IF verifyaddcategorieschoice$ = CHR$(27) THEN GOTO quitwithoutdoinganything
    LOOP

endaddcategories:
OPEN "CATEGORY.DAT" FOR RANDOM AS #2 LEN = LEN(whatfor)
numrec = LOF(2) / LEN(whatfor)
numrec = numrec + 1
PUT #2, numrec, whatfor
CLOSE
PRINT
quitwithoutdoinganything:
END SUB

DEFINT A-Z
SUB afmfile (afmfilename$)
OPEN afmfilename$ FOR OUTPUT AS #5
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

PRINT #5, "==============================================================================="
PRINT #5, " All expenses paid by "; userid.uname; "             during: "; monthyear$
PRINT #5, "==============================================================================="
PRINT #5, ""

'just about the same as the screen version...
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1
grandtotal# = 0

WHILE counter < numrec

    FOR X = counter TO counter
        GET #4, X, whatfor
        selectedcatcode$ = whatfor.code
        selectedcatlabel$ = whatfor.label
        counter = counter + 1
        GOTO lineitemsafmfile
nextlineitemsafmfile:

        grandtotal# = grandtotal# + subtotal#

    NEXT
WEND
PRINT #5, "==============================================================================="
PRINT #5, USING " Total...... $ ##,###.## "; grandtotal#;
PRINT #5, "                              Report Date: "; DATE$
PRINT #5, "==============================================================================="
GOTO endafmfile

lineitemsafmfile:
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundafmfile
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundafmfile
codefoundafmfile:
        PRINT #5, " "; entry.day; "  "; entry.catcode;
        PRINT #5, USING "  $ ##,###.##"; entry.amount;
        PRINT #5, "  "; entry.note
        subtotal# = subtotal# + entry.amount
codenotfoundafmfile:
Icounter = Icounter + 1
NEXT
WEND
PRINT #5, ""
PRINT #5, " Sub Total "; selectedcatcode$;
PRINT #5, USING "  $ ##,###.## "; subtotal#;
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
PRINT #5, " ("; selectedcatlabel$; ")"
PRINT #5, "-------------------------------------------------------------------------------"
CLOSE 3
GOTO nextlineitemsafmfile

endafmfile:

END SUB

SUB afmprint
CLOSE
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

ON ERROR GOTO handler

LPRINT "==============================================================================="
LPRINT " All expenses paid by "; userid.uname; "             during: "; monthyear$
LPRINT "==============================================================================="
LPRINT
linenum = 4
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1
grandtotal# = 0

WHILE counter < numrec

    FOR X = counter TO counter
        GET #4, X, whatfor
        selectedcatcode$ = whatfor.code
        selectedcatlabel$ = whatfor.label
        counter = counter + 1
        linenum = linenum + 1
        GOTO afmprintlineitems
nextafmprintlineitems:
IF linenum > screenfull + 40 THEN
    LPRINT CHR$(12)
    linenum = 0
    ELSE
    END IF
    grandtotal# = grandtotal# + subtotal#
    NEXT
WEND
LPRINT "==============================================================================="
LPRINT USING " Total...... $ ##,###.## "; grandtotal#;
LPRINT "                              Report Date: "; DATE$
LPRINT "==============================================================================="
LPRINT CHR$(12)
GOTO endafmprint

afmprintlineitems:
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundafmprint
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundafmprint
codefoundafmprint:
        LPRINT " "; entry.day; "  "; entry.catcode;
        LPRINT USING "  $ ##,###.##"; entry.amount;
        LPRINT "  "; entry.note
        linenum = linenum + 1
        subtotal# = subtotal# + entry.amount
codenotfoundafmprint:
Icounter = Icounter + 1

IF linenum > screenfull + 40 THEN
    LPRINT CHR$(12)
    linenum = 0
    ELSE
    END IF

NEXT
WEND
LPRINT
LPRINT " Sub Total "; selectedcatcode$;
LPRINT USING "  $ ##,###.## "; subtotal#;
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
LPRINT " ("; selectedcatlabel$; ")"
LPRINT "-------------------------------------------------------------------------------"
linenum = linenum + 3
CLOSE 3
GOTO nextafmprintlineitems

endafmprint:
END SUB

SUB afmscreen
CLOSE
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

PRINT "==============================================================================="
PRINT " All expenses paid by "; userid.uname; "             during: "; monthyear$
PRINT "==============================================================================="
PRINT
linenum = linenum + 4       'there are four lines right there...
CLOSE

'we will now get each category code in turn, and display all the entries
'that are associated with each code...
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1
grandtotal# = 0             'initialize the grand total to 0

    WHILE counter < numrec
        FOR X = counter TO counter
            GET #4, X, whatfor
            selectedcatcode$ = whatfor.code
            selectedcatlabel$ = whatfor.label
            counter = counter + 1
            GOTO afmslineitems       'go and show the line items...
nextafmslineitems:
        IF linenum > screenfull THEN    'if so many lines have been displayed
                                    'on screen then stop and re-set counter
            PRINT
            COLOR 13, bgc%
            PRINT " press any key to continue": Halt$ = INPUT$(1)
            COLOR fgc%, bgc%
            linenum = 0             '(re-set counter)
            ELSE                    'if linenum is not greater than screenfull
        END IF                      'then never mind

        grandtotal# = grandtotal# + subtotal#

    NEXT    'finished with category?, OK, on to the next one...
WEND        'no more categories?, OK, finish the report
        IF linenum > screenfull THEN    'if so many lines have been displayed
                                    'on screen then stop and re-set counter
            PRINT
            COLOR 13, bgc%
            PRINT " press any key to continue": Halt$ = INPUT$(1)
            COLOR fgc%, bgc%
            linenum = 0             '(re-set counter)
            ELSE                    'if linenum is not greater than screenfull
        END IF                      'then never mind

PRINT "==============================================================================="
PRINT USING " Total...... $ ##,###.## "; grandtotal#;
PRINT "                              Report Date: "; DATE$
PRINT "==============================================================================="

PRINT
COLOR 13, bgc%
PRINT " press any key to continue": Halt$ = INPUT$(1)
GOTO endafms

afmslineitems:       'go and show the line items...
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundapm
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundapm
codefoundapm:
        PRINT " "; entry.day; "  "; entry.catcode;
        PRINT USING "  $ ##,###.##"; entry.amount;
        PRINT "  "; entry.note
        linenum = linenum + 1
        subtotal# = subtotal# + entry.amount
codenotfoundapm:
Icounter = Icounter + 1
IF linenum > screenfull THEN
    PRINT
    COLOR 13, bgc%
    PRINT " press any key to continue": Halt$ = INPUT$(1)
    COLOR fgc%, bgc%
    linenum = 0
    END IF

NEXT
WEND
PRINT
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
PRINT " Sub Total "; selectedcatcode$;
PRINT USING "  $ ##,###.## "; subtotal#;
PRINT " ("; selectedcatlabel$; ")"
COLOR 14, bgc%
PRINT "-------------------------------------------------------------------------------"
COLOR fgc%, bgc%
linenum = linenum + 3
CLOSE 3

GOTO nextafmslineitems
endafms:
END SUB

SUB background (character%)
FOR X = 1 TO 25                             'these statements
    LOCATE X, 1                             'place a background
    PRINT STRING$(80, CHR$(character%));    'of ASCII characters
    NEXT                                    'on the screen

END SUB

SUB calcsubtotal
SHARED selectedcatcode$
SHARED selectedcatlabel$
SHARED subtotal#

OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)
numrec = LOF(3) / LEN(entry)
numrec = numrec + 1
counter = 1
subtotal# = 0

WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundct
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundct

codefoundct:
subtotal# = subtotal# + entry.amount

codenotfoundct:
counter = counter + 1

NEXT
WEND
CLOSE #3
END SUB

DEFSNG A-Z
SUB displaycategories
OPEN "CATEGORY.DAT" FOR RANDOM AS #2 LEN = LEN(whatfor)
numrec = LOF(2) / LEN(whatfor)
numrec = numrec + 1
counter = 1
col = 2
COLOR 14, bgc%
PRINT " Code  Name            Code  Name            Code  Name"
COLOR fgc%, bgc%
PRINT
WHILE counter < numrec
FOR X = counter TO counter + 1
    GET #2, X, whatfor
    counter = counter + 1
    PRINT TAB(col); whatfor.code; "   "; whatfor.label; " ";
        IF col <= 46 THEN col = col + 22        'does three
        IF col > 46 THEN col = 2: PRINT " "     'columns of categories
NEXT

WEND
CLOSE
PRINT

END SUB

DEFINT A-Z
SUB drawborder (UpRow, LeftCol, BotRow, RtCol, bgc%)

    'draw the top of the border
    LOCATE UpRow, LeftCol
    PRINT CHR$(213) + STRING$(((RtCol - LeftCol) - 1), CHR$(205)) + CHR$(184)

    'draw the sides of the border
    FOR i = (UpRow + 1) TO (BotRow - 1)
      LOCATE i, LeftCol
      PRINT CHR$(179) + STRING$(((RtCol - LeftCol) - 1), CHR$(32)) + CHR$(179)
    NEXT

    'draw the bottom of the border
    LOCATE BotRow, LeftCol
    PRINT CHR$(212) + STRING$(((RtCol - LeftCol) - 1), CHR$(205)) + CHR$(190)

END SUB

SUB editcategories
CLOSE

OPEN "category.dat" FOR RANDOM AS #3 LEN = LEN(whatfor)
numrec = LOF(3) / LEN(whatfor)
numrec = numrec + 1
counter = 1
linenum = 0
PRINT
WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, whatfor
        linenum = linenum + 1
            IF linenum > screenfull THEN
            PRINT
            linenum = 0
            COLOR 13, bgc%
            INPUT " item # to edit + ENTER, or ENTER to continue ", edit%
                SELECT CASE edit%
                CASE IS > numrec
                    BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditcat
                CASE IS < 0
                    BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditcat
                'CASE IS = 0

                CASE ELSE
                    GOTO ReplaceOldCat

                END SELECT
            COLOR fgc%, bgc%
            END IF
        PRINT "#"; counter; TAB(7); whatfor.label; "  "; whatfor.code
counter = counter + 1
NEXT
WEND
PRINT
COLOR 13, bgc%

INPUT " item # to edit + ENTER, or ENTER to forget it ", edit%
                SELECT CASE edit%
                CASE IS > numrec
                BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditcat
                CASE IS = 0
                    CLOSE
                    GOTO endeditcat
                CASE ELSE
                    GOTO ReplaceOldCat

                END SELECT
COLOR fgc%, bgc%
ReplaceOldCat:
CLS
PRINT
GET #3, edit%, whatfor
LOCATE 20
COLOR 11, bgc%
        PRINT " OLD ->     ";
        PRINT " "; whatfor.label; "  "; whatfor.code
LOCATE 1, 1

COLOR fgc%, bgc%
INPUT "New Category Name      "; newlabel$
INPUT "Two-place abbreviation "; newcode$

    IF LEN(newcode$) <> 2 THEN
        BEEP
        PRINT "Bad code": SLEEP 1
        GOTO endeditcat
        END IF
    newcode$ = UCASE$(newcode$)
    whatfor.label = newlabel$
    whatfor.code = newcode$

LOCATE 21
COLOR 14, bgc%

    PRINT " NEW ->     ";
        PRINT " "; whatfor.label; "  "; whatfor.code
PRINT
COLOR 14, bgc%
PRINT " Is all this OK? (Y/N/Q) "

    DO
    newentryconf$ = INKEY$
    newentryconf$ = UCASE$(newentryconf$)
    IF newentryconf$ = "Y" THEN GOTO recordeditedcat
    IF newentryconf$ = "N" THEN CLOSE : GOTO endeditcat    'start over
    IF newentryconf$ = "Q" THEN CLOSE : GOTO endeditcat      'never mind, forget it
    LOOP

recordeditedcat:
PUT #3, edit%, whatfor
CLOSE 3
endeditcat:
END SUB

SUB editentries
selectfile
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)
numrec = LOF(3) / LEN(entry)
numrec = numrec + 1
counter = 1
linenum = 0
PRINT
WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, entry
        linenum = linenum + 1
            IF linenum > screenfull THEN
            PRINT
            linenum = 0
            COLOR 13, bgc%
            INPUT " item # to edit + ENTER, or ENTER to continue ", edit%
                SELECT CASE edit%
                CASE IS > numrec
                    BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditentries
                CASE IS < 0
                    BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditentries
                CASE IS = 0

                CASE ELSE
                    GOTO ReplaceOldEntry

                END SELECT
            COLOR fgc%, bgc%
            END IF
        PRINT "#"; counter; TAB(7); entry.day; "  "; entry.catcode;
        PRINT USING "  $ ##,###.##"; entry.amount;
        PRINT "  "; entry.note
counter = counter + 1
NEXT
WEND
PRINT
COLOR 13, bgc%
INPUT " item # to edit + ENTER, or ENTER to forget it ", edit%
                SELECT CASE edit%
                CASE IS > numrec
                BEEP
                    CLS : LOCATE 12, 35
                    PRINT "no such record": SLEEP 2
                    CLOSE : GOTO endeditentries
                CASE IS = 0
                    CLOSE
                    GOTO endeditentries
                END SELECT
COLOR fgc%, bgc%
ReplaceOldEntry:
CLS
PRINT
GET #3, edit%, entry
LOCATE 20
COLOR 11, bgc%
        PRINT " OLD ->     ";
        PRINT " "; entry.day; "  "; entry.catcode;
        PRINT USING "  $ ##,###.##"; entry.amount;
        PRINT "  "; entry.note;
LOCATE 1, 1

COLOR fgc%, bgc%
getday                          'get the day within the selected month
getcategory
getamount                       'get the amount of money (negetive is OK)
getnote                         'get the note about the expense

LOCATE 21
COLOR 14, bgc%

    PRINT " NEW ->     ";
        PRINT " "; entry.day; "  "; entry.catcode;
        PRINT USING "  $ ##,###.##"; entry.amount;
        PRINT "  "; entry.note
PRINT
COLOR 14, bgc%
PRINT " Is all this OK? (Y/N/Q) "

    DO
    newentryconf$ = INKEY$
    newentryconf$ = UCASE$(newentryconf$)
    IF newentryconf$ = "Y" THEN GOTO recordeditedentry
    IF newentryconf$ = "N" THEN CLOSE : GOTO endeditentries    'start over
    IF newentryconf$ = "Q" THEN CLOSE : GOTO endeditentries      'never mind, forget it
    LOOP

recordeditedentry:
PUT #3, edit%, entry
CLOSE 3

endeditentries:
END SUB

DEFSNG A-Z
SUB getamount

INPUT " Amount............ : $", entry.amount

END SUB

SUB getcategory
SHARED selectedcat$
startgetcategory:
PRINT
LINE INPUT " Enter Category Code: "; selectedcat$
selectedcat$ = UCASE$(selectedcat$)
entry.catcode = selectedcat$

OPEN "CATEGORY.DAT" FOR RANDOM AS #2 LEN = LEN(whatfor)
numrec = LOF(2) / LEN(whatfor)
totalrec = numrec
numrec = numrec + 1
counter = 1

WHILE counter < numrec
FOR X = counter TO counter + 1
    GET #2, X, whatfor
    counter = counter + 1
    IF whatfor.code = entry.catcode THEN GOTO goodcat
    IF counter > totalrec THEN CLOSE 2: BEEP: GOTO startgetcategory
NEXT
WEND

goodcat:
CLOSE 2
END SUB

SUB getday
LOCATE 1
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "-" + year$

thisday$ = MID$(DATE$, 4, 2)
thisday$ = month$ + "-" + thisday$ + "-" + year$

PRINT " Date of Expense..."; thisday$; "     type new DAY, or ENTER to accept date shown"
LOCATE 1, 23
LINE INPUT newday$
    IF newday$ = "" THEN GOTO todayisfine
    IF VAL(newday$) > 31 THEN BEEP: PRINT "invalid day": GOTO trydayagain
    IF LEN(newday$) <> 2 THEN BEEP: PRINT "invalid day": GOTO trydayagain

entry.day = month$ + "-" + newday$ + "-" + year$
GOTO donewithday

trydayagain:
SLEEP 2
CLS
PRINT " Date of Expense..."; thisday$; "     type new DAY, or ENTER to accept date shown"
LOCATE 1, 23
LINE INPUT newday$
    IF newday$ = "" THEN GOTO todayisfine
    IF VAL(newday$) > 31 THEN BEEP: PRINT "invalid day": GOTO trydayagain
    IF LEN(newday$) <> 2 THEN BEEP: PRINT "invalid day": GOTO trydayagain

entry.day = month$ + "-" + newday$ + "-" + year$
GOTO donewithday

todayisfine:
entry.day = thisday$

donewithday:
END SUB

SUB getnote
LINE INPUT " Note...............: "; entry.note
END SUB

SUB getpass

passtry = 0
OPEN "PERSONAL.DAT" FOR RANDOM AS #1 LEN = LEN(userid)

GET #1, 1, userid                               'get the previously recorded
passcode:                                       'passcode from PERSONAL.DAT
LOCATE 12, 26
PRINT "passcode please";
COLOR 0, 0                                      'hide the code being entered
INPUT try
IF try = userid.passcode THEN CLOSE : GOTO ok
IF try <> userid.passcode THEN BEEP: GOTO notOK

notOK:
passtry = passtry + 1
LOCATE 14, 10
COLOR 7, 0

PRINT "Invalid passcode. If none has been set yet, try ENTER "
SLEEP 3
CLS
IF passtry < 3 THEN GOTO passcode
CLS
COLOR 14, 12
LOCATE 12, 20
PRINT " Sorry. (Three strikes and 'yer OUT!) "
COLOR 7, 0
CLOSE
SLEEP 3: CLS : END

ok:                         'if passcode is lost, delete the
                            'file PERSONAL.DAT, and use the ENTER

IF userid.bgc = 0 AND userid.fgc = 0 THEN   'if there is no PERSONAL.DAT
    bgc% = 1: fgc% = 15                     'file, then the colors will be
                                            '0,0. This changes them to 1,15
    ELSE
    bgc% = userid.bgc                       'if there is a PERSONAL.DAT file
    fgc% = userid.fgc                       'then get *those* colors
    END IF

END SUB

SUB getpersonaldat
startgpd:

CLOSE
OPEN "PERSONAL.DAT" FOR RANDOM AS #1 LEN = LEN(userid)
PRINT "Current User name: "; userid.uname
PRINT "Current passcode : "; userid.passcode
PRINT
INPUT "New User name    : ", userid.uname
INPUT "New passcode     : ", userid.passcode

PUT #1, 1, userid
CLOSE
END SUB

DEFINT A-Z
SUB line25
LOCATE 25, 1
PRINT STRING$(80, CHR$(219));
COLOR fgc%, bgc%
LOCATE 25, 1: PRINT "       "; : PRINT CHR$(16); " For: "; userid.uname; : PRINT "    "; DATE$; "             "; CHR$(17); : PRINT "        ";
END SUB

SUB pcfile (pcfilename$)
SHARED selectedcat$
OPEN pcfilename$ FOR OUTPUT AS #5
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$
OPEN "PERSONAL.DAT" FOR RANDOM AS #4
PRINT #5, "==============================================================================="
PRINT #5, " Expenses paid by "; userid.uname; "                 during: "; monthyear$
PRINT #5, " For category "; selectedcat$; " ONLY"
PRINT #5, "==============================================================================="
CLOSE 4

OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)
CLS
numrec = LOF(3) / LEN(entry)
numrec = numrec + 1
counter = 1
total# = 0
PRINT #5,
WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, entry
        IF entry.catcode = selectedcat$ THEN GOTO pcfcodefound
        IF entry.catcode <> selectedcat$ THEN GOTO pcfcodenotfound
pcfcodefound:
        PRINT #5, " "; entry.day; "  "; entry.catcode;
        PRINT #5, USING "  $ ##,###.##"; entry.amount;
        PRINT #5, "  "; entry.note
        total# = total# + entry.amount
pcfcodenotfound:
counter = counter + 1
NEXT
WEND
PRINT #5,
PRINT #5, "==============================================================================="
PRINT #5, " Total for "; selectedcat$;
PRINT #5, USING ": $ ##,###.## "; total#;
PRINT #5, "                            Report Date: "; DATE$
PRINT #5, "==============================================================================="
CLOSE 3

END SUB

SUB pcprint
SHARED selectedcat$
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$
OPEN "PERSONAL.DAT" FOR RANDOM AS #4
ON ERROR GOTO handler
LPRINT "==============================================================================="
LPRINT " Expenses paid by "; userid.uname; "                 during: "; monthyear$
LPRINT " For category "; selectedcat$; " ONLY"
LPRINT "==============================================================================="
CLOSE 4

OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

numrec = LOF(3) / LEN(entry)
numrec = numrec + 1
counter = 1
total# = 0
linenumber = 0
LPRINT
WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, entry
        IF entry.catcode = selectedcat$ THEN GOTO pccodefound
        IF entry.catcode <> selectedcat$ THEN GOTO pccodenotfound
pccodefound:
        LPRINT " "; entry.day; "  "; entry.catcode;
        LPRINT USING "  $ ##,###.##"; entry.amount;
        LPRINT "  "; entry.note
        total# = total# + entry.amount
        linenumber = linenumber + 1
        IF linenumber = 50 THEN linenumber = 0: LPRINT " continued...": LPRINT CHR$(12)
pccodenotfound:
counter = counter + 1
NEXT
WEND
LPRINT
LPRINT "==============================================================================="
LPRINT " Total for "; selectedcat$;
LPRINT USING ": $ ##,###.## "; total#;
LPRINT "                            Report Date: "; DATE$
LPRINT "==============================================================================="
CLOSE 3
LPRINT CHR$(12)
END SUB

SUB pcscreen
SHARED selectedcat$

OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)
CLS
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

PRINT "==============================================================================="
PRINT " Expenses paid by "; userid.uname; "                 during: "; monthyear$
PRINT " For category "; selectedcat$; " ONLY"
PRINT "==============================================================================="
linenum = 5

numrec = LOF(3) / LEN(entry)
numrec = numrec + 1
counter = 1
total# = 0
PRINT
WHILE counter < numrec
FOR X = counter TO counter
        GET #3, X, entry
        IF entry.catcode = selectedcat$ THEN GOTO codefound
        IF entry.catcode <> selectedcat$ THEN GOTO codenotfound
codefound:
        PRINT " "; entry.day; "  "; entry.catcode;
        PRINT USING "  $ ##,###.##"; entry.amount;
        PRINT "  "; entry.note
        total# = total# + entry.amount
        linenum = linenum + 1
            IF linenum > screenfull THEN
            PRINT
            linenum = 0
            COLOR 13, bgc%
            PRINT " press any key to continue": Halt$ = INPUT$(1)
            COLOR fgc%, bgc%
            END IF

codenotfound:
counter = counter + 1
NEXT
WEND
            IF linenum > screenfull THEN
            PRINT
            linenum = 0
            COLOR 13, bgc%
            PRINT " press any key to continue": Halt$ = INPUT$(1)
            COLOR fgc%, bgc%
            END IF

PRINT
PRINT "==============================================================================="
PRINT " Total for "; selectedcat$;
PRINT USING ": $ ##,###.## "; total#;
PRINT "                            Report Date: "; DATE$
PRINT "==============================================================================="
CLOSE 3
PRINT
COLOR 13, bgc%
PRINT " press any key to continue": Halt$ = INPUT$(1)

END SUB

SUB perhelp (topic$)
'Obviously I was originaly planning on having a lot of on-line help text.
'However, it's a pain in the ass writing all this stuff, and I'm tired of
'fooling with it. I'll do the readme file, but that's it! <bg>

IF topic$ = "main" THEN
PRINT
PRINT " The Personal Expense Recorder program is intended as an easy-to-use, simple"
PRINT " means to record one's day-to-day expenses. This is the QBasic version .12"
PRINT
PRINT " See the file README.PER for full instructions."
PRINT
PRINT " Expenses are recorded in monthly data files, according to category. The "
PRINT " files are named in the format [MMYY]QPER.DAT. You should back these files up "
PRINT " from time to time."
PRINT
PRINT " The first thing to do is go to Set-Up from the main menu. I would suggest "
PRINT " setting up a few test categories, and then running the program through its"
PRINT " various functions to get a feel for it. Once you see how it works, go to "
PRINT " DOS and delete all the .DAT files, and then start over for real."
PRINT
PRINT " Thanks for helping to test this program. All future versions will use"
PRINT " the same data files as this prototype version, so go ahead and use it."
PRINT
PRINT " PER is by Dave Gjessing (dgjess@freenet.columbus.oh.us). It is freeware."
PRINT " However, any comercial use is prohibited, without prior written consent"
PRINT " from the author. Copyright Dave Gjessing 1995. All rights reserved."
PRINT

    COLOR 13, bgc%
    PRINT " press any key to continue"; : Halt$ = INPUT$(1)
    'COLOR fgc%, bgc%
    END IF
END SUB

DEFSNG A-Z
SUB selectcolors
colortop:
CLS
PRINT "Currently, your colors are:"
PRINT "background "; bgc%
PRINT "foreground "; fgc%
PRINT
PRINT "0 - Black     4 - Red         8 - Dark Grey    12 - Light Red"
PRINT "1 - Blue      5 - Magenta     9 - Light Blue   13 - Light Magenta"
PRINT "2 - Green     6 - Brown      10 - Light Green  14 - Yellow"
PRINT "3 - Cyan      7 - White      11 - Light Cyan   15 - Bright White"
PRINT
PRINT "To see what the various combinations look like, indicate"
PRINT "a foreground and a background number below:"
PRINT

   PRINT "background ";
   INPUT bgc%
   PRINT
   PRINT "foreground ";
   INPUT fgc%
   PRINT
   COLOR fgc%, bgc%
IF bgc% = fgc% THEN     'if user screws up, set colors to default
    BEEP: CLS
    fgc% = 15
    bgc% = 1
    COLOR fgc%, bgc%
    PRINT "You are trying to make the BG the same as the FG! - that's no good."
    GOTO colortop
    END IF

userid.fgc = fgc%
userid.bgc = bgc%

OPEN "PERSONAL.DAT" FOR RANDOM AS #1 LEN = LEN(userid)
PUT #1, 1, userid
CLOSE

END SUB

SUB selectfile
startselectfile:
CLS

current$ = DATE$
month$ = LEFT$(current$, 2)
year$ = RIGHT$(current$, 2)
currentfileid$ = month$ + year$
currentfilename$ = currentfileid$ + "QPER.DAT"
CALL drawborder(9, 8, 15, 72, bgc%) 'draw the box around the menu

LOCATE 10, 20
PRINT "The current month's data file would be... "
COLOR 14, bgc%
LOCATE 12, 33
PRINT currentfilename$
COLOR fgc%, bgc%
LOCATE 14, 13
PRINT "ESCAPE to name another file, ENTER to accept this file"

    DO
    selectfilechoice$ = INKEY$
    IF selectfilechoice$ = CHR$(13) THEN GOTO current
    IF selectfilechoice$ = CHR$(27) THEN GOTO other
    LOOP

current:
workfilename$ = currentfilename$
GOTO endselectfile

other:
PRINT
INPUT "                     month and year you want (MMYY) "; otherfile$
    IF LEN(otherfile$) <> 4 THEN BEEP: CLS : GOTO startselectfile
    proposedmonth$ = LEFT$(otherfile$, 2)
    proposedmonth = VAL(proposedmonth$)
    IF proposedmonth > 12 THEN BEEP: CLS : GOTO startselectfile

workfilename$ = otherfile$ + "QPER.DAT"

verifyselectfile:
CLS
LOCATE 9
PRINT "                             You have picked..."
PRINT
COLOR 14, bgc%
PRINT "                               "; workfilename$
PRINT
COLOR fgc%, bgc%
PRINT "                            as the working file."
PRINT
PRINT "                       ESCAPE to do over, ENTER if OK"

    DO
    verifyselectfilechoice$ = INKEY$
    IF verifyselectfilechoice$ = CHR$(13) THEN GOTO endselectfile
    IF verifyselectfilechoice$ = CHR$(27) THEN GOTO startselectfile
    LOOP
 
endselectfile:
CLS
END SUB

DEFINT A-Z
SUB sumfile (sumfilename$)
CLOSE

SHARED grandtotal#
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

OPEN sumfilename$ FOR OUTPUT AS #5
PRINT #5, "==============================================================================="
PRINT #5, " Summary of expenses paid by "; userid.uname; "      during: "; monthyear$
PRINT #5, "==============================================================================="
PRINT #5, ""

OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1

    WHILE counter < numrec
        FOR X = counter TO counter
            GET #4, X, whatfor
            selectedcatcode$ = whatfor.code
            selectedcatlabel$ = whatfor.label
            counter = counter + 1
            GOTO lineitemssumfile
nextlineitemssumfile:
        NEXT    'finished with category?, OK, on to the next one...
WEND        'no more categories?, OK, finish the report
PRINT #5, ""
PRINT #5, "==============================================================================="
PRINT #5, USING " Total...... $ ##,###.## "; grandtotal#;
PRINT #5, "                              Report Date: "; DATE$
PRINT #5, "==============================================================================="
GOTO endsumfile

lineitemssumfile:
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundsumfile
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundsumfile

codefoundsumfile:
subtotal# = subtotal# + entry.amount

codenotfoundsumfile:
Icounter = Icounter + 1

NEXT
WEND
percentage# = subtotal# / grandtotal#
percentage# = percentage# * 100
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
pad = 16 - LEN(selectedcatlabel$) + 1
PRINT #5, " "; selectedcatlabel$; STRING$(pad, CHR$(46)); " |";
PRINT #5, USING " ###.## %"; percentage#;
PRINT #5, " | "; STRING$(33, CHR$(46));
PRINT #5, USING "  $ ##,###.## "; subtotal#

CLOSE 3

GOTO nextlineitemssumfile
endsumfile:
END SUB

SUB sumprint
CLOSE

SHARED grandtotal#
ON ERROR GOTO handler
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$

LPRINT "==============================================================================="
LPRINT " Summary of expenses paid by "; userid.uname; "      during: "; monthyear$
LPRINT "==============================================================================="
LPRINT
CLOSE
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1

    WHILE counter < numrec
        FOR X = counter TO counter
            GET #4, X, whatfor
            selectedcatcode$ = whatfor.code
            selectedcatlabel$ = whatfor.label
            counter = counter + 1
            GOTO lineitemssumprint
nextlineitemssumprint:

            linenum = linenum + 1
    NEXT    'finished with category?, OK, on to the next one...
WEND        'no more categories?, OK, finish the report
LPRINT
LPRINT "==============================================================================="
LPRINT USING " Total...... $ ##,###.## "; grandtotal#;
LPRINT "                              Report Date: "; DATE$
LPRINT "==============================================================================="
LPRINT CHR$(12)
GOTO endsumprint

lineitemssumprint:


selectedcatlabel$ = RTRIM$(selectedcatlabel$)
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundsumprint
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundsumprint

codefoundsumprint:
subtotal# = subtotal# + entry.amount

codenotfoundsumprint:
Icounter = Icounter + 1

NEXT
WEND
percentage# = subtotal# / grandtotal#
percentage# = percentage# * 100
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
pad = 16 - LEN(selectedcatlabel$) + 1
LPRINT " "; selectedcatlabel$; STRING$(pad, CHR$(46)); " |";
LPRINT USING " ###.## %"; percentage#;
LPRINT " | "; STRING$(33, CHR$(46));
LPRINT USING "  $ ##,###.## "; subtotal#

CLOSE 3
GOTO nextlineitemssumprint
endsumprint:

END SUB

SUB sumscreen
CLOSE

SHARED grandtotal#
    month$ = LEFT$(workfilename$, 2)
    year$ = MID$(workfilename$, 3, 2)
    monthyear$ = month$ + "/" + year$
CLOSE


PRINT "==============================================================================="
PRINT " Summary of expenses paid by "; userid.uname; "      during: "; monthyear$
PRINT "==============================================================================="
PRINT
linenum = 4      'there are four lines right there...
CLOSE
OPEN "CATEGORY.DAT" FOR RANDOM AS #4 LEN = LEN(whatfor)
numrec = LOF(4) / LEN(whatfor)
numrec = numrec + 1
counter = 1

    WHILE counter < numrec
        FOR X = counter TO counter
            GET #4, X, whatfor
            selectedcatcode$ = whatfor.code
            selectedcatlabel$ = whatfor.label
            counter = counter + 1
            GOTO lineitemssumscreen
nextlineitemssumscreen:

            linenum = linenum + 1
        IF linenum > screenfull THEN
            PRINT
            COLOR 13, bgc%
            PRINT " press any key to continue": Halt$ = INPUT$(1)
            COLOR fgc%, bgc%
            linenum = 0             '(re-set counter)
            ELSE                    'if linenum is not greater than screenfull
        END IF                      'then never mind

    NEXT    'finished with category?, OK, on to the next one...
WEND        'no more categories?, OK, finish the report
IF linenum > screenfull THEN SLEEP

PRINT
PRINT "==============================================================================="
PRINT USING " Total...... $ ##,###.## "; grandtotal#;
PRINT "                              Report Date: "; DATE$
PRINT "==============================================================================="

PRINT
COLOR 13, bgc%
PRINT " press any key to continue": Halt$ = INPUT$(1)
GOTO endsumscreen

lineitemssumscreen:
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
OPEN workfilename FOR RANDOM AS #3 LEN = LEN(entry)

Inumrec = LOF(3) / LEN(entry)
Inumrec = Inumrec + 1
Icounter = 1
subtotal# = 0

WHILE Icounter < Inumrec
FOR Y = Icounter TO Icounter
        GET #3, Y, entry
        IF entry.catcode = selectedcatcode$ THEN GOTO codefoundsum
        IF entry.catcode <> selectedcatcode$ THEN GOTO codenotfoundsum

codefoundsum:
subtotal# = subtotal# + entry.amount

codenotfoundsum:
Icounter = Icounter + 1

NEXT
WEND
percentage# = subtotal# / grandtotal#
percentage# = percentage# * 100
selectedcatlabel$ = RTRIM$(selectedcatlabel$)
pad = 16 - LEN(selectedcatlabel$) + 1
PRINT " "; selectedcatlabel$; STRING$(pad, CHR$(46)); " |";
PRINT USING " ###.## %"; percentage#;
PRINT " | "; STRING$(33, CHR$(46));
PRINT USING "  $ ##,###.## "; subtotal#

CLOSE 3
GOTO nextlineitemssumscreen:

endsumscreen:
END SUB

