***************************************************************
** UCSYS - inventory and point-of-sale program
** J Osako    8 Jan 1996	'This code is cursed'
** Copyright 1996 The Used Computer Store, All Rights Reserved
**
**	Revision History
**	----------------
**		v1.11 : released 29 Mar 1996
**			29 Mar 1996 - rewrote warranty copy, reset error 
**				handler
**		v1.1  : released 28 Mar 1996
**			28 Mar 1996 - finished employee handler
**			27 Mar 1996 - added simple employee data handle
**				to other
**			26 Mar 1996 - rewrote warranty copy (again), fixed
**				persistent-window bugs in user and other, fixed 
**				loophole in other
**		v1.01 : released 26 Mar 1996 (J Osako)
**			26 Mar 1996 - rewrote warranty copy, fixed non-return
**				bug in summary, no-name bug in get_cust and procedure
**				name length bug in ucsys
**		v1.0 released for use 25 Mar 1996 
**		Prerelease : (J. Osako)
**			20 Mar 1996 - completed initial debugging, tested on
**				target machines
**			18 Mar 1996 - began working on report gen. for 
**				receipts
**			15 Mar 1996 - rewrote main loop, improved password
**				handler, changed option switch code to jump table
**			 1 Mar 1996 - Sales input function written, starting
**				debugging and testing
**			 2 Feb 1996 - Added minimal error-checking routine
**			25 Jan 1996 - completed draft of main program,
**				began documenting code
**			10 Jan 1996 - modified for use as general system
**		  	 8 Jan 1996 - initial work on software inventory 
**				handler
***************************************************************

**turn these off before using in service

SET DEVELOPMENT OFF
SET DEBUG OFF
SET STEP off

**********
** A few system initializations
**********
CLEAR				&& clear the screen 
CLEAR WINDOWS		&& dump the existing windows
CLEAR ALL			&& clear the work areas and variables
SET TALK OFF
SET CENTURY ON		&& don't take any chances on this one
SET ESCAPE ON
SET REPROCESS TO AUTOMATIC	
** file locking will proceed until either the file is 
** available or until the user kills the attempt.

***********
** program constants
** I put them here because some of the definitions 
** below depend on them
***********
PUBLIC NULL
NULL = SPACE(10)	&& default 10 character blank space

err_colors = 7		&& color sets for windows - red and yellow
log_colors = 10		&& cyan and drk blue
opt_colors = 8
MAXPCS = 35

M.itemno = 1
go_on = .T.

ON ERROR DO oops WITH NULL 

*ON ESCAPE go_on = .F.
**********
** open universal databases and set relations
**********
USE Customer IN 1
	SELECT Customer
*	INDEX ON (cust_name) TAG sucker
*	INDEX ON cdl TAG mark FOR (cdl != NULL)
*	INDEX ON cust_num TAG rube
	SET ORDER TO rube
USE Trans_Ty IN 2
USE Trans_Re IN 3
	SELECT Trans_Re
*	INDEX ON (DTOS(tr_date) + timestamp) TAG action
	SET ORDER TO action
	SET RELATION TO cust_num INTO Customer
USE Slaves IN 4
	SELECT Slaves
*	INDEX ON (ALLTRIM(last_name) +', '+ ALLTRIM(first_name)) TAG stuck FOR currentp
*	INDEX ON (ALLTRIM(last_name) +', '+ ALLTRIM(first_name)) TAG canned FOR !currentp
*	INDEX ON logname TAG luser FOR currentp
	SET ORDER TO luser 
	SET RELATION TO ssn INTO Trans_Re ADDITIVE
*USE PC_Inv IN 0
*	SELECT PC_Inv
*	INDEX ON (DTOS(purch_date) + timestamp) TAG ibm; 
*		FOR ((system > 0) AND (system < MAXPCS))	
*USE Soft_Inv IN 0
*	SELECT Soft_Inv 
*	INDEX ON prg_num TAG invtry
*	SET ORDER TO invtry	
*USE Sys_List IN 0
*	SELECT Sys_List 
*	INDEX ON system TAG syssy
*	SET ORDER TO syssy
*USE Soft_Lis IN 0
*	SELECT Soft_Lis
*	SET RELATION TO prg_num INTO Soft_Inv
*	SET RELATION TO system INTO Sys_List ADDITIVE

**********
** Variable declarations and initialization
**  NOTE : To insure data validity over the network, 
** most operations work on temporary memory variables 
** during entry, and only save to the .DBFs AFTER 
** the transaction is finished - that way, no incorrect
** or incomplete data is used, and the critical area
** is entered only once.
**********

PUBLIC tr_date,timestamp,transactn,item
PUBLIC qty,serialnum,stocknum,warranty,price
** memvar equivalents of the atom table records
** table ATOM.DBF and ATEMP.DBF

PUBLIC check		&& for the good-check routine in get_cust()
PUBLIC cust_num		&& for the relational key between
					&& trans_re and customer

PUBLIC dups			&& the default # of copies of a receipt
dups = 2			&& currently assumes plain paper

PUBLIC logname
namelen = SPACE(LEN(Slaves.logname)) 
M.logname = namelen
passlen = SPACE(LEN(Slaves.passwd))	

cus_p = .F.		

** In addition to being an awful pun, cus_p is the
** 'customer known' flag. If true, then there is a record 
** of the customer, which can be used immediately; otherwise, 
** a new record must be made for the person before setting
** the cust_num variable in the transaction record.

= NUMLOCK(.F.)		&& sets number lock off by default

**********
** define universal windows
** note that most of these will 
** be CENTERed at calling time
**********
** 'login' for employee initials
DEFINE WINDOW Login FROM 1,1 TO 5, 18+LEN(Slaves.logname); 
		NONE FLOAT SHADOW; 
		COLOR SCHEME log_colors
MOVE WINDOW Login CENTER
** error messages
DEFINE WINDOW S_O_L FROM 1,1 to 10, 35; 
	 	CLOSE FLOAT;
 		COLOR SCHEME err_colors; 
 		TITLE ' What The %@(< ? '
 MOVE WINDOW S_O_L CENTER
** menu of actions - sale, purchasing, etc.
DEFINE WINDOW Option FROM 1,1 TO 11,14; 
		NONE CLOSE FLOAT;
		COLOR SCHEME opt_colors
MOVE WINDOW Option CENTER


**********
** Start by getting the employee's name
** This is, in effect, the main loop of the program.
** The name and password are checked, and the program 
** proceeds from there. 
**********
	SET CLOCK ON
	ACTIVATE WINDOW Login
	DO WHILE go_on
		@0,8 SAY 'UCSYS v.1.11'
		@2,2 SAY 'Username :' GET M.logname 
		READ 
		IF pass()
			DEACTIVATE WINDOW Login
			DO opt_in
			ACTIVATE WINDOW Login
		ENDIF
		M.logname = namelen
		M.passwd = passlen	
	ENDDO		
	DO shutdown WITH NULL

RETURN   && not necessary, but a good practice anyway 


************************************
** pass() - the main login function
** this checks the name and password 
** against the Slaves table and gets
** the option which the user wants next
************************************
FUNCTION pass

	SELECT Slaves
	SET ORDER TO luser				&& ordered by logname
	IF SEEK(upper(M.logname))		&& is this an employee?
		IF EMPTY(Slaves.passwd)		&& Yes, check password
			RETURN .T.				&& no password, go on
		ELSE
			@3,2 SAY 'Password : '
			IF Slaves.passwd =  pin()
				RETURN .T.		&& password right, go on
			ENDIF
		ENDIF
	ENDIF 
RETURN .F.		&& pass()
	
FUNCTION pin
** pin() - generalized password blanking
** routine. It reads in the password
** one character at a time, encoding the
** characters as they come in. Any printable
** character can be used in a password;
** control characters and mousedowns
** end the password
	** some constants - decimal equ. of delimiting ASCII chars
	SPC = 32		&& spacebar
	TIL = 126		&& tilde
	BSP = 8			&& backspace
	

	tpass= ''
	ptemp = INKEY(120,'SM')
	DO WHILE BETWEEN(ptemp,SPC,TIL) OR ptemp = BSP 
		pl = LEN(tpass) 
		IF ptemp = BSP
			IF pl > 1
				tpass = LEFT(tpass, pl - 1)
				@ROW(),COL() SAY ' '
				@ROW(),COL()-1 SAY '*'					 
			ENDIF
		ELSE
			tpass = tpass + coded(CHR(ptemp))
			@ROW(),COL() SAY '*'
		ENDIF
		ptemp = INKEY(120,'SM')	
	ENDDO				
RETURN PADR(tpass, 10)

**********
** coded(plaintxt) - simple substitution cipher
** not very safe, but good enough
FUNCTION coded
	PARAMETER plaintxt

	key1 = '~!@#$%^&*()-+=1234567890QWERTYUIOPASDFGHJKLZXCVBNM >'
	key2 = '7MD4I$A0Q5-RT+XE=)&MN2Z~YC(P>9L1B^F!K*83O@#J UGHV%6W'
RETURN CHRTRAN(UPPER(plaintxt),key1,key2)

PROCEDURE opt_in
**********
** opt_in() - select which operation to start.
** Trans_Ty is a list of transaction types
** for Trans_Re. The list is copied into
** choices[] and displayed for the user to 
** choose from. 
**********
	M.transactn = 'Sale'	&& reset locally for each terminal
	ACTIVATE WINDOW Option
	SELECT Trans_ty
	COPY TO ARRAY choices
	@0,0 GET M.transactn FROM choices
	READ
	DEACTIVATE WINDOW Option
	*********
	** Now get a timestamp 
	********* 
	DO get_timestamp IN gts
	M.itemno = 1
	
	DO (ALLTRIM(LEFT(M.transactn, 8)))		
	******************
	** This is treats M.transactn as the index
	** of a jump table.
	******************
	** To add option foo, you have to do two things :
	** add 'foo' to TRANS_TY.DBF and create a file FOO.PRG 
	** containing the necessary handler code.
	******************
RETURN


FUNCTION shutdown
	PARAMETER errcode
	
	IF errcode != ' '
		ACTIVATE WINDOW S_O_L 
		@2,1 SAY 'Fatal Error : ' 
		@ROW()+1,3 SAY errcode
		@ROW()+2,1 SAY 'Please tell Bill immediately'
		WAIT
*	ELSE		&& normal shutdown, get out
		** clean up the rest of the system
		DEACTIVATE WINDOW Login
		CLOSE ALL
	ENDIF
	QUIT
RETURN