IMPLEMENTATION MODULE Sales; (* Copyright (C) 1988,1989 Jensen & Partners International *) IMPORT FIO, Str, IO, Misc, Globals, Window, Client, Items, Btree, Lib; FROM Globals IMPORT WriteAt, PromptFore, DisplayBorder, DisplayFore, DisplayBack, GetMenu, TaxRate, DataFore, DataBack, ItemIndex, ItemData, ClientData, ClientIndex; FROM Window IMPORT GotoXY, WinType, TextColor, TextBackground, ClrEol, Use, Used, PutOnTop, Open, WinDef, Black, White, SingleFrame, DoubleFrame, SetFrame, SetTitle, CenterLowerTitle, CursorOn, CursorOff, Hide; CONST MAX_ROWS = 15; FIRST_ROW = 6; TYPE SalesRec = RECORD Item : Items.ItemRec; Qty : CARDINAL; END; VAR SaleItems : ARRAY[FIRST_ROW..MAX_ROWS] OF SalesRec; SummaryFile : FIO.File; year, month, day : CARDINAL; weekday : Lib.DayType; misc : ARRAY[0..3] OF CHAR; ok : BOOLEAN; SalesWin, lastWin : WinType; SummaryWin, psumWin : WinType; OnScreen : BOOLEAN; keyPressed : CHAR; blankItem : Items.ItemRec; CurrentTotals : TotalRec; SubTotal, GrandTotal, SalesTax : LONGREAL; PROCEDURE PressAKey( txt : ARRAY OF CHAR); VAR ch : CHAR; BEGIN TextColor(PromptFore); TextBackground(DisplayBack); WriteAt(MAX_ROWS+1,1,txt); GotoXY(30,MAX_ROWS+1); ch := IO.RdKey(); GotoXY(1,MAX_ROWS+1); ClrEol(); keyPressed := CAP(ch); END PressAKey; PROCEDURE Template(); (* This procedure un-hides the item display window and displays the field names. *) VAR x : CARDINAL; BEGIN lastWin := Used(); Use(SalesWin); PutOnTop(SalesWin); Clear(); OnScreen := TRUE; IF FIO.Exists(TotalFile) THEN SummaryFile := FIO.Open(TotalFile); FIO.Seek(SummaryFile,0); x := FIO.RdBin(SummaryFile,CurrentTotals,SIZE(TotalRec)); FIO.Close(SummaryFile); ELSE WITH CurrentTotals DO TotalDollars := 0.0; TotalCash := 0.0; TotalCharge := 0.0; NumTrans := 0; END; END; END Template; PROCEDURE Clear(); (** Clear information off the Sales screen **) VAR i : CARDINAL; BEGIN TextColor(DataFore); TextBackground(DataBack); WriteAt(1,11," "); WriteAt(1,37," "); WriteAt(1,63," "); WriteAt(2,11," "); WriteAt(2,40," "); FOR i := FIRST_ROW TO MAX_ROWS DO WriteAt(i,3," "); WriteAt(i,16," "); WriteAt(i,45," "); WriteAt(i,53," "); WriteAt(i,66," "); END; WriteAt(MAX_ROWS+2,45," "); WriteAt(MAX_ROWS+2,66," "); END Clear; PROCEDURE DisplayClient( aClient : Client.ClientRec); VAR S : ARRAY[0..9] OF CHAR; ok : BOOLEAN; BEGIN TextColor(DataFore); TextBackground(DataBack); WriteAt(1,11," "); WriteAt(1,37," "); WriteAt(1,63," "); WriteAt(2,11," "); WriteAt(2,40," "); WITH aClient DO WriteAt(1,11,CNum); WriteAt(1,37,LName); WriteAt(1,63,FName); WriteAt(2,11,Phone); WriteAt(2,40," "); Str.FixRealToStr(Balance,2,S,ok); IF ok = FALSE THEN WriteAt(2,40,"???"); ELSE WriteAt(2,40,S); END; END; END DisplayClient; PROCEDURE GetClient( VAR aClient : Client.ClientRec ) : BOOLEAN; VAR CNum : Globals.FileKey; ReEnter, GotClient : BOOLEAN; ch : CHAR; BEGIN GotClient := FALSE; CNum := ""; REPEAT (* until GotClient *) ReEnter := FALSE; Clear(); GotoXY(11,1); Misc.InputStr(CNum, 10); IF CNum[0] <= ' ' THEN (* cancel the transaction *) RETURN FALSE; ELSE (* a CNum was entered *) IF Btree.Find(ClientIndex,CNum,aClient) THEN DisplayClient(aClient); GotClient := TRUE; ELSIF Btree.Search(ClientIndex,CNum,aClient) THEN REPEAT DisplayClient(aClient); GetMenu("T)his One, N)ext, P)revious, or R)e-enter? ", Globals.CharSet{'T','N','P'},ch); CASE ch OF 'T' : GotClient := TRUE; | 'N' : IF Btree.Next(ClientIndex,aClient) THEN DisplayClient(aClient); ELSE Globals.Beep(); END; | 'P' : IF Btree.Prev(ClientIndex,aClient) THEN DisplayClient(aClient); ELSE Globals.Beep(); END; | 'R' : ReEnter := TRUE; ELSE Globals.Beep(); END; (* case *) UNTIL GotClient OR ReEnter; ELSE Globals.Beep(); Globals.Beep(); Globals.Beep(); PressAKey("That client is not in our records!"); TextColor(DataFore); TextBackground(DataBack); END; END; UNTIL GotClient; RETURN TRUE; END GetClient; PROCEDURE DisplayItem( row : CARDINAL; anItem : Items.ItemRec ); VAR ok : BOOLEAN; S : ARRAY[0..9] OF CHAR; BEGIN TextColor(DataFore); TextBackground(DataBack); WriteAt(row,16,anItem.Description); WriteAt(row,53," "); Str.FixRealToStr(anItem.Retail,2,S,ok); IF ok = FALSE THEN WriteAt(row,53,"???"); ELSE WriteAt(row,53,S); END; END DisplayItem; PROCEDURE GetOneItem( row: CARDINAL; VAR anItem : Items.ItemRec ): BOOLEAN; VAR item : Globals.FileKey; ReEnter, GotItem : BOOLEAN; ch : CHAR; BEGIN GotItem := FALSE; Str.Copy(item,""); REPEAT ReEnter := FALSE; GotoXY(3,row); Misc.InputStr(item,10); IF item[0] <= ' ' THEN (* cancel the transaction *) RETURN FALSE; ELSE (* an item number was entered *) IF Btree.Find(ItemIndex,item,anItem) THEN DisplayItem(row,anItem); GotItem := TRUE; ELSIF Btree.Search(ItemIndex,item,anItem) THEN REPEAT DisplayItem(row,anItem); GetMenu("T)his One, N)ext, P)revious, or R)e-enter? ", Globals.CharSet{'T','N','P'},ch); CASE ch OF 'T' : GotItem := TRUE; | 'N' : IF Btree.Next(ItemIndex,anItem) THEN DisplayItem(row,anItem); ELSE Globals.Beep(); END; | 'P' : IF Btree.Prev(ItemIndex,anItem) THEN DisplayItem(row,anItem); ELSE Globals.Beep(); END; | 'R' : ReEnter := TRUE; ELSE Globals.Beep(); END; (* case *) UNTIL GotItem OR ReEnter; ELSE Globals.Beep(); Globals.Beep(); Globals.Beep(); PressAKey("That item is not in our records!"); TextColor(DataFore); TextBackground(DataBack); END; END; UNTIL GotItem; RETURN TRUE; END GetOneItem; PROCEDURE GetSaleItem( VAR which : CARDINAL; VAR action : CARDINAL ) : BOOLEAN; VAR item : Items.ItemRec; qty : CARDINAL; qtyStr : ARRAY[0..4] OF CHAR; ok : BOOLEAN; ch : CHAR; thisTotal : LONGREAL; S : ARRAY[0..10] OF CHAR; BEGIN action := 0; ok := FALSE; qtyStr := "1"; IF GetOneItem(which,item) THEN REPEAT WriteAt(which,45," "); GotoXY(45,which); Misc.InputStr(qtyStr,5); qty := CARDINAL(Str.StrToCard(qtyStr,10,ok)); UNTIL ok; SaleItems[which].Qty := qty; SaleItems[which].Item := item; thisTotal := LONGREAL(qty) * item.Retail; WriteAt(which,66," "); Str.FixRealToStr(thisTotal,2,S,ok); IF ok = FALSE THEN WriteAt(which,66,"???"); ELSE WriteAt(which,66,S); END; SubTotal := SubTotal + thisTotal; SalesTax := (SubTotal * TaxRate)/100.0; GrandTotal := SubTotal + SalesTax; WriteAt(MAX_ROWS+2,45," "); WriteAt(MAX_ROWS+2,66," "); Str.FixRealToStr(SalesTax,2,S,ok); IF ok = FALSE THEN WriteAt(MAX_ROWS+2,45,"???"); ELSE WriteAt(MAX_ROWS+2,45,S); END; Str.FixRealToStr(GrandTotal,2,S,ok); IF ok = FALSE THEN WriteAt(MAX_ROWS+2,66,"???"); ELSE WriteAt(MAX_ROWS+2,66,S); END; END; GetMenu("C)ancel item, N)o Sale, A)nother item, D)one with sale: ", Globals.CharSet{'C','N','A','D'},ch); CASE ch OF 'D' : RETURN TRUE; | 'A' : RETURN FALSE; | 'C' : DEC(which); DisplayItem(which+1,blankItem); WriteAt(which+1,45," "); WriteAt(which+1,66," "); | 'N' : action := 99; RETURN TRUE; ELSE Globals.Beep(); END; RETURN FALSE; END GetSaleItem; PROCEDURE Work(); (** Perform the entry of sales, information requests, etc. Template should be called first to open the window. **) VAR theClient : Client.ClientRec; ch : CHAR; transDone : BOOLEAN; choice, i, row : CARDINAL; BEGIN SubTotal := 0.0; GrandTotal := 0.0; SalesTax := 0.0; IF GetClient(theClient) THEN transDone := FALSE; FOR row := FIRST_ROW TO MAX_ROWS DO SaleItems[row].Qty := 0; END; row := FIRST_ROW; REPEAT transDone := GetSaleItem( row, choice ); INC(row); UNTIL (transDone) OR (row>MAX_ROWS); IF choice = 0 THEN (* take the cash or charge *) GetMenu("Will that be C)ash or cH)arge? ", Globals.CharSet{'C','H'},ch); CASE ch OF 'C' : CurrentTotals.TotalCash := CurrentTotals.TotalCash + GrandTotal; | 'H' : CurrentTotals.TotalCharge := CurrentTotals.TotalCharge + GrandTotal; theClient.Balance := theClient.Balance + GrandTotal; Btree.Delete(ClientData); Btree.Add(ClientData,theClient,SIZE(Client.ClientRec)); ELSE Globals.Beep(); END; CurrentTotals.TotalDollars := CurrentTotals.TotalDollars + GrandTotal; INC(CurrentTotals.NumTrans); ELSE (* cancel transaction *) Clear(); END; END; (* if *) END Work; PROCEDURE Summary(); (** Summarize current sales figures in a window **) VAR SummaryWin, psumWin : WinType; ch : CHAR; S : ARRAY[0..10] OF CHAR; ok : BOOLEAN; BEGIN psumWin := Used(); SummaryWin := Open( WinDef( 28, 10, 52, 17, White,Black,TRUE,FALSE,TRUE,TRUE, SingleFrame,White,Black) ); SetFrame(SummaryWin,DoubleFrame,DataFore, DataBack); SetTitle(SummaryWin,"Daily Totals",CenterLowerTitle); Use(SummaryWin); CursorOff(); TextColor(DataFore); TextBackground(DataBack); Window.Clear(); WriteAt(2,3,"Total Sales: $"); WriteAt(3,3,"Cash Sales: "); WriteAt(4,3,"Charge Sales: "); WriteAt(5,3,"# Trans: "); PutOnTop(SummaryWin); (* write out the current totals *) WITH CurrentTotals DO Str.FixRealToStr(TotalDollars,2,S,ok); WriteAt(2,18,S); Str.FixRealToStr(TotalCash,2,S,ok); WriteAt(3,18,S); Str.FixRealToStr(TotalCharge,2,S,ok); WriteAt(4,18,S); GotoXY(18,5); IO.WrCard(NumTrans,4); END; ch := IO.RdKey(); Window.Close(SummaryWin); PutOnTop(psumWin); Use(psumWin); CursorOn(); END Summary; PROCEDURE Close(); (** Remove the Sales screen from the screen **) BEGIN Hide(SalesWin); Use(lastWin); PutOnTop(lastWin); OnScreen := FALSE; (* write out summary file *) SummaryFile := FIO.Create(TotalFile); FIO.Seek(SummaryFile,0); FIO.WrBin(SummaryFile,CurrentTotals,SIZE(TotalRec)); FIO.Close(SummaryFile); END Close; BEGIN (* init code *) (* set up the summary file name *) TotalFile := "000000.TOT"; (* default name *) Lib.GetDate(year,month,day,weekday); IF year > 1900 THEN year := year - 1900; END; Str.CardToStr(LONGCARD(year),misc,10,ok); IF misc[1] = 0C THEN TotalFile[4] := '0'; TotalFile[5] := misc[0]; ELSE TotalFile[4] := misc[0]; TotalFile[5] := misc[1]; END; Str.CardToStr(LONGCARD(month),misc,10,ok); IF misc[1] = 0C THEN TotalFile[0] := '0'; TotalFile[1] := misc[0]; ELSE TotalFile[0] := misc[0]; TotalFile[1] := misc[1]; END; Str.CardToStr(LONGCARD(day),misc,10,ok); IF misc[1] = 0C THEN TotalFile[2] := '0'; TotalFile[3] := misc[0]; ELSE TotalFile[2] := misc[0]; TotalFile[3] := misc[1]; END; (* create the sales window *) SalesWin := Open( WinDef( 0, 4, 79, 22, White,Black,TRUE,FALSE,TRUE,TRUE, SingleFrame,White,Black) ); SetFrame(SalesWin,SingleFrame,DisplayBorder, DisplayBack); Use(SalesWin); TextColor(DisplayFore); TextBackground(DisplayBack); Window.Clear(); WriteAt(1,3,"Client:"); WriteAt(2,3,"Phone:"); WriteAt(1,30,"Last:"); WriteAt(1,55,"First:"); WriteAt(2,30,"Balance:"); WriteAt(4,3,"ITEM"); WriteAt(4,16,"DESCRIPTION"); WriteAt(4,45,"QTY"); WriteAt(4,53,"EACH"); WriteAt(4,66,"TOTAL"); WriteAt(17,40,"TAX:"); WriteAt(17,57,"TOTAL:"); blankItem.Retail := 0.0; blankItem.Description := " "; END Sales.