COMPILE FUNCTION obj_RDS(Method,Parms)
#pragma precomp SRP_PreCompiler

/*
	Methods for RDS table
    
	08/21/2004 JCH - Initial Coding
     
    Properties:
     
    Methods:
    
    Create(DataStruct)		;* Create new record
	
	
*/


DECLARE FUNCTION Get_Status, Msg, Utility, obj_Tables, NextKey, obj_WO_Verify, obj_Prod_Spec, Send_Dyn, obj_RDS_Makeup
DECLARE FUNCTION obj_RDS2, obj_RDS_Test, obj_WO_Mat, obj_Clean_Insp, obj_PRS_Prop, Database_Services
DECLARE FUNCTION Logging_Services, Environment_Services, Error_Services, Signature_Services
DECLARE SUBROUTINE Set_Status, Msg, obj_Tables, Send_Dyn, obj_WO_Step, obj_RDS_Layer, obj_RDS_Test, obj_WM_In
DECLARE SUBROUTINE Btree.Extract, RDS_React_Run, Environment_Services, Logging_Services, Error_Services, Send_Info
DECLARE SUBROUTINE SRP_Stopwatch, Database_Services, Lot_Services

$INSERT MSG_EQUATES
$INSERT WO_VERIFY_EQU
$INSERT WO_LOG_EQUATES
$INSERT RDS_EQUATES
$INSERT RDS_MAKEUP_EQU
$INSERT RDS_LAYER_INFO_EQU
$INSERT QUOTE_SPEC_EQU
$INSERT PROD_SPEC_EQUATES
$INSERT SCHEDULE_EQU
$INSERT WO_STEP_EQU
$INSERT NCR_EQU
$INSERT WO_MAT_EQUATES
$INSERT REACT_RUN_EQUATES
$INSERT CLEAN_INSP_EQUATES
$INSERT EPI_PART_EQUATES
$INSERT WO_REACT_EQUATES
$INSERT PRS_LAYER_EQU	;* Used to return obj_Prod_Spec values
$INSERT LOGICAL

ErrTitle = 'Error in Stored Procedure "obj_RDS"'
ErrorMsg = ''

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Log.csv'
Headers     = 'Logging DTM' : @FM : 'User' : @FM : 'RDS Key ID' : @FM : 'Notes'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)

LogPath      = Environment_Services('GetApplicationRootPath') : '\LogFiles\RemoveMetrology'
LogFileName  = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : '.log'
Headers      = 'Logging DTM' : @FM : 'Results'
ColumnWidths = 20 : @FM : 50
objLog2      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, ColumnWidths, False$, False$)

LogPath       = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_LOG'
LogFileName   = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Release Log.csv'
Headers       = 'Logging DTM' : @FM : 'User' : @FM : 'Work Order No' : @FM : 'Notes'
objReleaseLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$)

LogPath      = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName  = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WAFERS_IN.csv'
Headers      = 'Logging DTM' : @FM : 'RDS Key ID' : @FM : 'WAFERS_IN'
objWafersLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)

LogPath      = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName  = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS_TEST_DELETE.csv'
Headers      = 'Logging DTM' : @FM : 'RDS Test Key ID' : @FM : 'Message'
objRDSTestDeleteLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)


LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

IF NOT(ASSIGNED(Method))	THEN ErrorMsg = 'Unassigned parameter "Method" passed to subroutine'
IF NOT(ASSIGNED(Parms))		THEN Parms = ''

IF ErrorMsg NE '' THEN
	Set_Status(-1,ErrTitle:@SVM:ErrorMsg)
	RETURN ''
END

Result = ''

BEGIN CASE
	CASE Method = 'CurrStatus'		; GOSUB CurrStatus
	CASE Method = 'Create'			; GOSUB Create
	CASE Method = 'VerifySpecInfo'	; GOSUB VerifySpecInfo
		* 	CASE Method = 'Update'			; GOSUB Update
	CASE Method = 'SchedWfrQty'		; GOSUB SchedWfrQty
	CASE Method = 'TestRejWfrQty'	; GOSUB TestRejWfrQty
	CASE Method = 'MUSrcWfrQty'		; GOSUB MUSrcWfrQty
	CASE Method = 'MUDestWfrQty'	; GOSUB MUDestWfrQty
	CASE Method = 'RemMUWafers'		; GOSUB RemMUWafers
	CASE Method = 'WafersOut'		; GOSUB WafersOut
	CASE Method = 'YieldOutThruput' ; GOSUB YieldOutThruput
	CASE Method = 'WafersPerHour'	; GOSUB WafersPerHour
	CASE Method = 'AddShip'			; GOSUB AddShip
	CASE Method = 'RemShip'			; GOSUB RemShip
	CASE Method = 'RefreshRDSSpec'	; GOSUB RefreshRDSSpec
	CASE Method = 'WMInKeys'		; GOSUB WMInKeys
	CASE Method = 'WMOutKeys'		; GOSUB WMOutKeys
	CASE Method = 'SetSchedWfrQty'	; GOSUB SetSchedWfrQty
	CASE Method = 'MU_ADE_Reads'	; GOSUB MU_ADE_Reads
	CASE Method = 'MetPropFlag'		; GOSUB MetPropFlag
	CASE 1
		Result = obj_RDS2(Method,Parms)
		
END CASE

IF ErrorMsg NE '' THEN
	Set_Status(-1,ErrTitle:@SVM:ErrorMsg)
END

RETURN Result


* * * * * * *
CurrStatus:
* * * * * * *
	
	IF NOT(ASSIGNED(RDSNos)) THEN
		RDSNos = Parms[1,@RM]
		RDSRec = Parms[COL2()+1,@RM]
	END
	
	IF RDSNos = ''	THEN RETURN			;* 9/9/2014 JCH *** This routine has multiple Keys in with only a single record  **** AWS__T!  needs to be fixed
	
	ReturnVals = ''
	
	
	RDSCnt = COUNT(RDSNos,@VM) + (RDSNos NE '')
	FOR R = 1 TO RDSCnt
		
		NCRStatuses = XLATE('NCR',RDSRec<RDS_NCR_KEYS$>,7,'X')
		
		IF INDEX(NCRStatuses,'O',1) THEN
			ReturnVals<1,R> = 'NCR'				;* Open NCR on RDS *
			GOTO StatusHere
		END
		
		* ROTR inspection failure check -> Set status to PSTC (PostCleans)
		
		RotrAction = XLATE('RDS',RDSNos,'ROTR_ACTION','X')
		
		
		IF RotrAction = 'F' Then				;* Drive the CURR_STATUS to PostEpi Clean if the ROTR fails 
			ReturnVals<1,R> = 'PSTC'
			GOTO StatusHere
		END
		
		
		* Check for out of spec 
		
		OutOfSpec		= 0		;
		OutOfSpecThick	= ''
		OutOfSpecRes	= ''
		
		LSKeys = RDSRec<RDS_RDS_LAYER_KEYS$>
		
		MetOutOfSpec = SUM(XLATE('RDS_LAYER',LSKeys,'TEST_OUT_OF_SPEC','X'))		;* Updated for Metrology update 4/16/2006 JCH
		
		IF MetOutOfSpec > 0  THEN			;* Added check for F(ailed) ROTR_ACTION value.
			ReturnVals<1,R> = 'SPEC'		;* Run is out of spec *
			GOTO StatusHere
		END
		
		* Check for Metrology Complete
		
		MetComplete = SUM(XLATE('RDS_LAYER',LSKeys,'TEST_MET_COMPLETE','X'))		;* Added with DKK 11/3/2015 JCH
		
		IF NOT(MetComplete)  THEN			;* Added check for F(ailed) ROTR_ACTION value.
			ReturnVals<1,R> = 'MET'			;* Run is missing metrology *
			GOTO StatusHere
		END
		
		
		* * * * * * * 
		
		WONo		= RDSRec<RDS_WO$>
		CassNo		= RDSRec<RDS_CASS_NO$>
		WOStepKey	= RDSRec<RDS_WO_STEP_KEY$>
		
		WOMatRec = XLATE('WO_MAT',WONo:'*':CassNo,'','X')
		
		WOStep = FIELD(WOStepKey,'*',2)
		
		RDSKeys = ''
		RSCnt = 0
		RunSigProfs		= ''
		RunSignatures	= ''
		RunSigDTMs		= ''
		
		WOMatKey      = WONo:'*':CassNo
		SigArray      = Signature_Services('GetSigProfile', WOMatKey)
		RunSigProfs   = SigArray<1>
		RunSignatures = SigArray<2>
		
		ProcessStart = 0
		ProcessComp	= 0
		
		LOOP
			RunSignature	= RunSignatures<1,1>
			RunSigProf		= RunSigProfs<1,1>
		UNTIL RunSignature = ''
			ProcessStart = 1
			RunSignatures	= DELETE(RunSignatures,1,1,0)
			RunSigProfs		= DELETE(RunSigProfs,1,1,0)
		REPEAT
		
		IF RunSignature = '' AND RunSigProf = '' AND ProcessStart = 1 THEN
			ReturnVals<1,R> = 'COMP'
			GOTO StatusHere
		END ELSE
			ReturnVals<1,R> = RunSigProf[2,20]
			GOTO StatusHere
		END
		
		* EpiPRO specific (unload)
		
		TestPockets = RDSRec<RDS_POCKET$>
		TestOutCassNos = RDSRec<RDS_OUT_CASS_NO$>
		
		CONVERT @VM TO '' IN TestPockets
		CONVERT @VM TO '' IN TestOutCassNos
		
		IF TestPockets NE '' AND TestOutCassNos NE '' THEN
			ReturnVals<1,R> = 'COMP'				;* EpiPRO RDS is complete with wafer unload
		END
		
		StatusHere:
		
	NEXT R
	
	Result = ReturnVals
	
RETURN



* * * * * * *
Create:
* * * * * * *
	WONo          = Parms[1,@RM]
	WOStep        = Parms[COL2()+1,@RM]
	LastStep      = Parms[COL2()+1,@RM]
	CassNo        = Parms[COL2()+1,@RM]
	QuoteNo       = Parms[COL2()+1,@RM]
	OrderNo       = Parms[COL2()+1,@RM]
	OrderItem     = Parms[COL2()+1,@RM]
	CustNo        = Parms[COL2()+1,@RM]
	PONo          = Parms[COL2()+1,@RM]
	PS_No         = Parms[COL2()+1,@RM]
	SubSuppliedBy = Parms[COL2()+1,@RM]
	SubPreClean   = Parms[COL2()+1,@RM]
	SubPostClean  = Parms[COL2()+1,@RM]
	SchedDt       = Parms[COL2()+1,@RM]
	LotNo         = Parms[COL2()+1,@RM]
	CustPartNo    = Parms[COL2()+1,@RM]
	WaferQty      = Parms[COL2()+1,@RM]
	SubPartNo     = Parms[COL2()+1,@RM]
	QXJFlag       = Parms[COL2()+1,@RM]
	SubVendCd     = Parms[COL2()+1,@RM]
	
	ErrorMsg = ''
	IF WONo = ''		THEN ErrorMsg := 'Null Parameter "WONo" passed to routine. (':Method:')' 		
	IF WOStep = ''		THEN ErrorMsg := 'Null Parameter "WOStep" passed to routine. (':Method:')'		
	IF CassNo = ''		THEN ErrorMsg := 'Null Parameter "CassNo" passed to routine. (':Method:')'		
	IF CustNo = ''		THEN ErrorMsg := 'Null Parameter "CustNo" passed to routine. (':Method:')'		
	IF PS_No = ''		THEN ErrorMsg := 'Null Parameter "PS_No" passed to routine. (':Method:')'		
	IF SchedDt = ''		THEN ErrorMsg := 'Null Parameter "SchedDt" passed to  routine. (':Method:')'	
	IF LotNo = ''		THEN ErrorMsg := 'Null Parameter "LotNo" passed to  routine. (':Method:')'		
	IF WaferQty = ''	THEN ErrorMsg := 'Null Parameter "WaferQty" passed to  routine. (':Method:')'	
	
	If ErrorMsg NE '' then
		Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : 'RDSKey Not Yet Assigned' : ',' : 'Error occured in OBJ_RDS(CREATE): ' : ErrorMsg)
		Return
	end
	
	RDSNo   = NextKey('RDS')
	errCode = ''
	
	If RDSNo EQ '' or RDSNo EQ 0 or Error_Services('HasError') or Get_Status(errCode) then
		Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'NextKey(RDS) returned NULL or 0 for KeyID')
		Error_Services('Add', 'Error retrieving next RDS key from NextKey("RDS"). ' : Error_Services('GetMessage'))
		Result = RDSNo
		return 
	end
	
	// Delete old instance of this RDS if it exists ------------------------------------------------------------------------
	If RowExists('RDS', RDSNo) then
		Database_Services('DeleteDataRow', 'RDS', RDSNo, True$, False$)
		If Error_Services('NoError') then
			Results = 'RDS ' : RDSNo : ' deleted'
		end else
			Results = 'RDS ' : RDSNo : ' not deleted. Error : ' : Error_Services('GetMessage')
		end
	end
	// ---------------------------------------------------------------------------------------------------------------------
	
	
	// Delete related RDS_LAYER records ------------------------------------------------------------------------------------
	Layers = 'L1,L2,2'
	For each Layer in Layers using ','
		RDSLayerKey = RDSNo:'*':Layer
		If RowExists('RDS_LAYER', RDSLayerKey) then
			// Look for related RDS_TEST records and delete them first
			RDSTestKeys = Xlate('RDS_LAYER', RDSLayerKey, 'RDS_TEST_KEYS', 'X')
			If RDSTestKeys NE '' then
				For each RDSTestKey in RDSTestKeys using @VM
					// Look for related TW_USE records and delete them first
					TWKeys = Xlate('RDS_TEST', RDSTestKey, 'TW_USE_ID', 'X')
					If TWKeys NE '' then
						For each TWKey in TWKeys using @VM
							Database_Services('DeleteDataRow', 'TW_USE', TWKey, True$, True$)
						Next TWKey
					end
					Database_Services('DeleteDataRow', 'RDS_TEST', RDSTestKey, True$, True$)
					If Error_Services('NoError') then
						LogData    = ''
						LogData<1> = LoggingDTM
						LogData<2> = RDSTestKey
						LogData<3> = 'RDS_Test record deleted without error.'
						Logging_Services('AppendLog', objRDSTestDeleteLog , LogData, @RM, @FM, False$)
					end else
						ErrorMessage = Error_Services('GetMessage')
						LogData    = ''
						LogData<1> = LoggingDTM
						LogData<2> = ErrorMessage
						Logging_Services('AppendLog', objRDSTestDeleteLog , LogData, @RM, @FM, False$)
					end
				Next RDSTestKey
			end
			Database_Services('DeleteDataRow', 'RDS_LAYER', RDSLayerKey, True$, False$)
			If Error_Services('NoError') then
				Results = 'RDS_LAYER ' : RDSLayerKey : ' deleted'
			end else
				Results = 'RDS_LAYER ' : RDSLayerKey : ' not deleted. Error : ' : Error_Services('GetMessage')
			end
		end
	Next Layer
	// ---------------------------------------------------------------------------------------------------------------------
	
	
	// Delete old REACT_RUN record if it exists ----------------------------------------------------------------------------
	If RowExists('REACT_RUN', RDSNo) then
		// Delete old CLEAN_INSP record(s) if they exist
		CIKeys = Xlate('REACT_RUN', RDSNo, 'CI_NO', 'X')
		For each CIKey in CIKeys using @VM
			If RowExists('CLEAN_INSP', CIKey) then
				Database_Services('DeleteDataRow', 'CLEAN_INSP', CIKey, True$, False$)
				If Error_Services('NoError') then
					Results = 'CLEAN_INSP ' : CIKey : ' deleted'
				end else
					Results = 'CLEAN_INSP ' : CIKey : ' not deleted. Error : ' : Error_Services('GetMessage')
				end          
			end
		Next CIKey
		Database_Services('DeleteDataRow', 'REACT_RUN', RDSNo, True$, False$)
		If Error_Services('NoError') then
			Results = 'REACT_RUN ' : RDSNo : ' deleted'
		end else
			Results = 'REACT_RUN ' : RDSNo : ' not deleted. Error : ' : Error_Services('GetMessage')
		end
	end
	// ---------------------------------------------------------------------------------------------------------------------
	
	
	// Create new record
	RDSRec = ''
	RDSRec<RDS_ENTRY_ID$>			= @USER4
	RDSRec<RDS_ENTRY_DATE$>			= Date()
	RDSRec<RDS_ENTRY_TIME$>			= Time()
	RDSRec<RDS_STATUS$>    			= 'C' 		;* Received
	RDSRec<RDS_WO$>					= WONo
	RDSRec<RDS_WO_STEP_KEY$>		= WONo:'*':WOStep
	RDSRec<RDS_CASS_NO$>			= CassNo
	RDSRec<RDS_QUOTE_NO$>			= QuoteNo
	RDSRec<RDS_ORDER_NO$>			= OrderNo
	RDSRec<RDS_ORDER_ITEM$>			= OrderItem
	RDSRec<RDS_CUST_NO$>			= CustNo
	RDSRec<RDS_PO$>					= PONo
	RDSRec<RDS_PROD_SPEC_ID$>		= PS_No
	RDSRec<RDS_COMMIT_DATE_FINAL$>	= SchedDt
	RDSRec<RDS_LOT_NUM$>			= LotNo
	RDSRec<RDS_PART_NUM$>			= CustPartNo
	
	RDSRec<RDS_CASS_WAFER_QTY$>		= WaferQty
	RDSRec<RDS_SUB_PART_NO$>		= SubPartNo
	RDSRec<RDS_LAST_STEP$>			= LastStep
	RDSRec<RDS_SUB_SUPPLIED_BY$>	= SubSuppliedBy
	RDSRec<RDS_SUB_PRE_CLEAN$>		= SubPreClean
	RDSRec<RDS_SUB_POST_CLEAN$>		= SubPostClean
	
	
	IF CassNo = 1 THEN
		WOVStatus = 'O'														;* Open status (?)
		WOVNotes = ''
		WOVNo = obj_WO_Verify('Create',RDSNo:@RM:WOVStatus:@RM:WOVNotes)	;* Create a WO_Verify record on 1st run order
		RDSRec<RDS_WO_VERIFY_ID$> = WOVNo									;* Add pointer to RDS record
		IF Get_Status(errCode) THEN
			Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error calling OBJ_WO_VERIFY within OBJ_RDS(CREATE)')
		end
	End
	
	
	PSRec = XLATE('PROD_SPEC',PS_No,'','X')
	
	ReactorType = PSRec<PROD_SPEC_REACTOR_TYPE$>							;* This isn't used anwhere in the program 8/27/2014 JCH
	RDSRec<RDS_SPECIAL_INST$>	= PSRec<PROD_SPEC_SPEC_INST$>				;* 3/25/2013 jch
	RDSRec<RDS_SPEC_TYPE_ORIG$>	= XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
	
	Send_Info('Retrieving PSN Layer Properties...')
	
	LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1)	;* Returns specs for all layers in internal format
	
	
	* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
	* before the equates match up correctly
	
	* Prod_Spec table has layer specs all in one field
	* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
	
	LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
	LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
	LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet
	
	RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
	RecipeRec = XLATE('RECIPE',RecipeNo,'','X')			;* This used in 2nd and 3rd layer stuff (in error it appears)
	
	RDSRec<RDS_OVERGROW_REQ$>	= LayerSpec<PRS_LAYER_RES_MEASUREMENT$,9>	;* JCH 2/27/2006
	
	
	IF QXJFlag THEN
		RDSRec<RDS_QXJ_POST$> = 0				;* And here a couple of minor cluster operations
	END
	
	IF CustNo = '621' AND CassNo = 1 THEN
		RDSRec<RDS_QXJ_POST$> = 0			
	END
	
	NoCombinedLayerFlag = ''
	FOR I = 1 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
		LayerSpec	= FIELD(LayerSpecs,@RM,I)		;* Take the Ith Layer
		LayerSet	= FIELD(LayerSpec,@FM,1)
		LayerSpec	= FIELD(LayerSpec,@FM,2,99)	;* LayerSpec without the LayerSet
		
		IF LayerSet = I THEN NoCombinedLayerFlag = 1 ELSE NoCombinedLayerFlag = 0
		
		Send_Info('Creating RDS Layer ':LayerSet:'...')
		
		obj_RDS_Layer('Create',RDSNo:@RM:LayerSet:@RM:PS_No:@RM:NoCombinedLayerFlag)
		
		RDSRec<RDS_RDS_LAYER_KEYS$,I> = RDSNo:'*':LayerSet							;* Added 4/17/2006 JCH
		
		Send_Info('Creating Metrology for Layer Set ':LayerSet:'...')
		
		obj_RDS_Test('Create',RDSNo:@RM:LayerSet:@RM:PS_No)
		
	NEXT I
	
	
	********************************
	*Automatically Apply Supplement* 
	********************************
	// If first cassette in work order, then there is no supplement in place, therefore skip this step.
	If RDSRec<RDS_CASS_NO$> GT 1 then
		WoStepKey       = RDSRec<RDS_WO_STEP_KEY$>
		WoStepRec       = Database_Services('ReadDataRow', 'WO_STEP', WoStepKey)
		If Error_Services('NoError') then
			LastRDSKey      = WoStepRec<WO_STEP_RDS_KEY$>[-1, 'B' : @VM]
			LastRDSRec      = Database_Services('ReadDataRow', 'RDS', LastRDSKey)
			If Error_Services('NoError') then
				HasSupplement   = LastRDSRec<RDS_SUPPLEMENT$>
				If HasSupplement then
					RDSRec<RDS_SUPPLEMENT$>         = True$
					RDSRec<RDS_SUPPL_INST$>         = LastRDSRec<RDS_SUPPL_INST$>
					RDSRec<RDS_SUPPL_ENTRY_ID$>     = LastRDSRec<RDS_SUPPL_ENTRY_ID$>
					RDSRec<RDS_SUPPL_ENTRY_DATE$>   = LastRDSRec<RDS_SUPPL_ENTRY_DATE$>
					RDSRec<RDS_SUPPL_ENTRY_TIME$>   = LastRDSRec<RDS_SUPPL_ENTRY_TIME$>
				end
			end else
				Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error automatically applying supplement to new RDS.')
			end
		end else
			Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error automatically applying supplement to new RDS.')
		end
	end
	
	
	Send_Info('Saving RDS record...')
	
	obj_Tables('WriteRec','RDS':@RM:RDSNo:@RM:@RM:RDSRec)
	
	IF Get_Status(errCode) THEN
		Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error writing new RDS record. Error code: ':errCode)
		Result = ''
	END ELSE
		Lot_Services('CreateNewLot', 'RDS', '', WaferQty, SubPartNo, LotNo, SubVendCd, @User4, '', RDSNo)
		Result   = RDSNo
	END
	
	* * * * * * *
	
	Send_Info('Conversion to REACT_RUN record...')
	
	RDS_React_Run(RDSNo)			;********************************** Conversion stuff JCH 9/26/2008 *********************
	
RETURN


* * * * * * * 
VerifySpecInfo:
* * * * * * *
	
	RDSNo	= Parms[1,@RM]
	RDSRec	= Parms[COL2()+1,@RM]
	
	IF NOT(ASSIGNED(RDSNo))		THEN ErrorMsg = 'Unassigned Parm "RDSNo" passed to routine. (':Method:')'
	IF NOT(ASSIGNED(RDSRec))	THEN RDSRec = ''
	
	IF ErrorMsg NE '' THEN RETURN
	
	IF RDSNo = '' THEN RETURN		;* used in dictionary - no error messages
	
	IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
	IF RDSRec = '' THEN RETURN
	
	PS_No = RDSRec<RDS_PROD_SPEC_ID$>
	PSRec = XLATE('PROD_SPEC',PS_No,'','X')
	
	LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No)	;* Returns specs for all layers
	
	IF RDSRec<RDS_SPECIAL_INST$> NE PSRec<PROD_SPEC_SPEC_INST$> THEN Matches = 0
	
	LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
	LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
	LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet 
	
	RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
	RecipeRec = XLATE('RECIPE',RecipeNo,'','X')			;* This used in 2nd and 3rd layer stuff (in error it appears)
	
	ErrNum = 1
	
	* IF RDSRec<RDS_RECIPE_NO$>					NE RecipeNo								THEN ErrNum = -11
	
	
	* This section is here because the targets calculated in the existing SCHEDULE*WRITE event are not done correctly
	* There is a last decimal point difference in the calculation that causes a mismatch whenever a remainder of .5 
	* is generated during the division by 2.  WRITE event code doesn't drop the remainder like it should
	* This section calculates the targets based on the min and max on the RDS.  We can remove this after the WRITE
	* event is replaced and the data has had enough time to move through the system.
	* JCH 8/23/2004
	
	RDSConMin = RDSRec<RDS_CON_MIN_ORG$,1>		;* Record in internal format
	RDSConMax = RDSRec<RDS_CON_MAX_ORG$,1>		;* Record in internal format
	
	GOSUB CalcConTarget	;* Returns RDSTarget in internal format
	
	RDSResMin = RDSRec<RDS_RES_MIN_ORG$>
	RDSResMax = RDSRec<RDS_RES_MAX_ORG$>
	
	GOSUB CalcResTarget
	
	RDSThickMin = RDSRec<RDS_THICK_MIN_ORG$>
	RDSThickMax = RDSRec<RDS_THICK_MAX_ORG$>
	
	GOSUB CalcThickTarget
	
	
	IF OCONV(RDSRec<RDS_CON_MIN_ORG$,1>,'MS21')		NE LayerSpec<PRS_LAYER_CONC_MIN$>		THEN ErrNum = -12
	IF OCONV(RDSRec<RDS_CON_MAX_ORG$,1>,'MS21') 	NE LayerSpec<PRS_LAYER_CONC_MAX$>		THEN ErrNum = -13
	IF RDSRec<RDS_CON_UNITS_ORG$>					NE LayerSpec<PRS_LAYER_CONC_UNITS$>		THEN ErrNum = -14
	IF OCONV(RDSConTarget,'MS21')				NE LayerSpec<PRS_LAYER_CONC_TARGET$>	THEN ErrNum = -15
	
	IF OCONV(RDSRec<RDS_RES_MIN_ORG$>,'MD3')		NE LayerSpec<PRS_LAYER_RES_MIN$>		THEN ErrNum = -16
	IF OCONV(RDSRec<RDS_RES_MAX_ORG$>,'MD3')		NE LayerSpec<PRS_LAYER_RES_MAX$>		THEN ErrNum = -17
	IF RDSRec<RDS_RES_UNITS_ORG$>					NE LayerSpec<PRS_LAYER_RES_UNITS$>		THEN ErrNum = -18
	IF OCONV(RDSResTarget,'MD3')				NE LayerSpec<PRS_LAYER_RES_TARGET$>		THEN ErrNum = -19
	
	IF OCONV(RDSRec<RDS_THICK_MIN_ORG$>,'MD2')		NE LayerSpec<PRS_LAYER_THICK_MIN$>		THEN ErrNum = -110
	IF OCONV(RDSRec<RDS_THICK_MAX_ORG$>,'MD2')		NE LayerSpec<PRS_LAYER_THICK_MAX$>		THEN ErrNum = -111
	IF RDSRec<RDS_THICK_UNITS_ORG$>					NE LayerSpec<PRS_LAYER_THICK_UNITS$>	THEN ErrNum = -112
	IF OCONV(RDSThickTarget,'MD2')				NE LayerSpec<PRS_LAYER_THICK_TARGET$>	THEN ErrNum = -113
	
	RDSLayerInfo = RDSRec<RDS_LAYER_INFO$>		;* All Layers beyond the first
	
	FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
		LayerSpec = FIELD(LayerSpecs,@RM,I)		;* Take the Ith Layer
		LayerSet = LayerSpec<1>
		LayerSpec = FIELD(LayerSpec,@FM,2,99)	;* LayerSpec without the LayerSet 
		
		thisLayerInfo = FIELD(RDSLayerInfo,CHAR(248),I-1,1)	;* L2 & 2 from the RDS
		
		* Calculate RDS target using the same algorithm used in obj_Prod_Spec
		
		RDSConMin = ICONV(thisLayerInfo<1,RLConMin$,1>,'MS')
		RDSConMax = ICONV(thisLayerInfo<1,RLConMax$,1>,'MS')
		
		GOSUB CalcConTarget
		
		IF RDSConMin AND RDSConMax THEN
			IF RDSConMin = RDSConMax THEN
				RDSConTarget = RDSConMin
			END ELSE
				Delta = INT((RdsConMax-RDSConMin)/2)
				RDSConTarget = OCONV(RDSConMin + Delta,'MS21')
			END
		END ELSE
			RDSConTarget = ''
		END
		
		IF thisLayerInfo<1,RLRecipeNo$>		NE RecipeNo								THEN ErrNum = '-':I:1
		
		IF thisLayerInfo<1,RLConMin$,1>		NE LayerSpec<PRS_LAYER_CONC_MIN$>		THEN ErrNum = '-':I:2
		IF thisLayerInfo<1,RLConMax$,1>		NE LayerSpec<PRS_LAYER_CONC_MAX$>		THEN ErrNum = '-':I:3
		IF thisLayerInfo<1,RLConUnits$>		NE LayerSpec<PRS_LAYER_CONC_UNITS$>		THEN ErrNum = '-':I:4
		IF RDSConTarget						NE LayerSpec<PRS_LAYER_CONC_TARGET$>	THEN ErrNum = '-':I:5
		
		IF OCONV(thisLayerInfo<1,RLResMin$>,'MD3')	NE LayerSpec<PRS_LAYER_RES_MIN$>		THEN ErrNum = '-':I:6
		IF OCONV(thisLayerInfo<1,RLResMax$>,'MD3')	NE LayerSpec<PRS_LAYER_RES_MAX$>		THEN ErrNum = '-':I:7
		IF thisLayerInfo<1,RLResUnits$>			NE LayerSpec<PRS_LAYER_RES_UNITS$>			THEN ErrNum = '-':I:8
		IF OCONV(thisLayerInfo<1,RLResTarget$>,'MD3')	NE LayerSpec<PRS_LAYER_RES_TARGET$>	THEN ErrNum = '-':I:9
		
		IF OCONV(thisLayerInfo<1,RLThickMin$>,'MD2')	NE LayerSpec<PRS_LAYER_THICK_MIN$>		THEN ErrNum = '-':I:10
		IF OCONV(thisLayerInfo<1,RLThickMax$>,'MD2')	NE LayerSpec<PRS_LAYER_THICK_MAX$>		THEN ErrNum = '-':I:11
		IF thisLayerInfo<1,RLThickUnits$>				NE LayerSpec<PRS_LAYER_THICK_UNITS$>	THEN ErrNum = '-':I:12
		IF OCONV(thisLayerInfo<1,RLThickTarget$>,'MD2')	NE LayerSpec<PRS_LAYER_THICK_TARGET$>	THEN ErrNum = '-':I:13
		
	NEXT I
	
	SchedNo = RDSRec<RDS_SCHEDULE_NO$>
	OrdNo	= RDSRec<RDS_ORDER_NO$>
	
	Result = ErrNum:@FM:'Sched No: ':SchedNo:@FM:' Order No: ':OrdNo
	
RETURN


* * * * * * *
* Update:
* * * * * * *
* 
* RDSNo		= Parms[1,@RM]
* 
* IF NOT(ASSIGNED(RDSNo))		THEN ErrorMsg = 'Unassigned Parm "RDSNo" passed to routine. (':Method:')'
* 
* IF ErrorMsg NE '' THEN RETURN
* 
* IF RDSNo = ''	THEN ErrorMsg = 'Null Parameter "RDSNo" passed to routine. (':Method:')'
* 
* IF ErrorMsg NE '' THEN RETURN
* 
* RDSRec<RDS_ENTRY_ID$>		= @USER4
* RDSRec<RDS_ENTRY_DATE$>		= Date()
* RDSRec<RDS_ENTRY_TIME$>		= Time()
* RDSRec<RDS_SCHEDULE_NO$>	= SchedNo
* RDSRec<RDS_WO$>				= WONo
* 
* WO Run Order number is not stored in the RDS
* 
* RDSRec<RDS_QUOTE_NO$>			= QuoteNo
* RDSRec<RDS_ORDER_NO$>			= OrderNo
* RDSRec<RDS_CUST_NO$>			= CustNo
* RDSRec<RDS_PO$>					= PONo
* RDSRec<RDS_PROD_SPEC_ID$>		= PS_No
* RDSRec<RDS_STATUS$>				= RDSStatus								;* Usually passed as 'C' - Received 
* RDSRec<RDS_COMMIT_DATE_FINAL$>	= SchedDt
* RDSRec<RDS_LOT_NUM$>			= LotNo
* RDSRec<RDS_PART_NUM$>			= PartNo
* 
* IF CassNo = 1 THEN
* 	WOVStatus = 'O'														;* Open status (?)
* 	WOVNotes = ''
* 	WOVNo = obj_WO_Verify('Create',RDSNo:@RM:WOVStatus:@RM:WOVNotes)	;* Create a WO_Verify record on 1st run order
* 	RDSRec<RDS_WO_VERIFY_ID$> = WOVNo									;* Add pointer to RDS record
* END
* 
* PSRec = XLATE('PROD_SPEC',PS_No,'','X')
* 
* RDSRec<RDS_SPECIAL_INST$>	= PSRec<PROD_SPEC_SPEC_INST$>
* RDSRec<RDS_SPEC_TYPE_ORIG$>	= XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
* 
* LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1)	;* Returns specs for all layers without output conversion
* 
* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
* before the equates match up correctly
* 
* Prod_Spec table has layer specs all in one field
* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
* 
* LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
* LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
* LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet 
* 
* RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
* RecipeRec = XLATE('RECIPE',RecipeNo,'','X')			;* This used in 2nd and 3rd layer stuff (in error it appears)
* 
* RDSRec<RDS_RECIPE_NO$>		= RecipeNo
* RDSRec<RDS_CON_MIN$>		= LayerSpec<PRS_LAYER_CONC_MIN$>
* RDSRec<RDS_CON_MAX$>		= LayerSpec<PRS_LAYER_CONC_MAX$>	
* RDSRec<RDS_CON_UNITS$>		= LayerSpec<PRS_LAYER_CONC_UNITS$>
* RDSRec<RDS_CON_TARGET$>		= LayerSpec<PRS_LAYER_CONC_TARGET$>
* 
* RDSRec<RDS_RES_MIN$>		= LayerSpec<PRS_LAYER_RES_MIN$>
* RDSRec<RDS_RES_MAX$>		= LayerSpec<PRS_LAYER_RES_MAX$>	
* RDSRec<RDS_RES_UNITS$>		= LayerSpec<PRS_LAYER_RES_UNITS$>
* RDSRec<RDS_RES_TARGET$>		= LayerSpec<PRS_LAYER_RES_TARGET$>
* 
* RDSRec<RDS_THICK_MIN$>		= LayerSpec<PRS_LAYER_THICK_MIN$>
* RDSRec<RDS_THICK_MAX$>		= LayerSpec<PRS_LAYER_THICK_MAX$>	
* RDSRec<RDS_THICK_UNITS$>	= LayerSpec<PRS_LAYER_THICK_UNITS$>
* RDSRec<RDS_THICK_TARGET$>	= LayerSpec<PRS_LAYER_THICK_TARGET$>
* 
* LayerInfo = ''
* 
* FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
* 	LayerSpec = FIELD(LayerSpecs,@RM,I)		;* Take the Ith Layer
* 	LayerSpec = FIELD(LayerSpec,@FM,2,99)	;* LayerSpec without the LayerSet 
* 	
* 	thisLayerInfo = ''	;* Empty bucket to parse into
* 	
* 	thisLayerInfo<1,RLConMin$>		= LayerSpec<PRS_LAYER_CONC_MIN$>
* 	thisLayerInfo<1,RLConMax$>		= LayerSpec<PRS_LAYER_CONC_MAX$>
* 	thisLayerInfo<1,RLConUnits$>	= LayerSpec<PRS_LAYER_CONC_UNITS$>
* 	thisLayerInfo<1,RLConTarget$>	= LayerSpec<PRS_LAYER_CONC_TARGET$>
* 	
* 	thisLayerInfo<1,RLRecipeNo$> = RecipeNo			;* Copied from the original in the WRITE event of the Schedule window
* 	thisLayerInfo<1,RLThickRead$> = STR(@SVM,16)
* 	thisLayerInfo<1,RLSheetRhoRead$> = STR(@SVM,16)
* 
* 	thisLayerInfo<1,RLResMin$>		= LayerSpec<PRS_LAYER_RES_MIN$>
* 	thisLayerInfo<1,RLResMax$>		= LayerSpec<PRS_LAYER_RES_MAX$>	
* 	thisLayerInfo<1,RLResUnits$>	= LayerSpec<PRS_LAYER_RES_UNITS$>
* 	thisLayerInfo<1,RLResTarget$>	= LayerSpec<PRS_LAYER_RES_TARGET$>
* 	
* 	thisLayerInfo<1,RLThickMin$>	= LayerSpec<PRS_LAYER_THICK_MIN$>
* 	thisLayerInfo<1,RLThickMax$>	= LayerSpec<PRS_LAYER_THICK_MAX$>	
* 	thisLayerInfo<1,RLThickUnits$>	= LayerSpec<PRS_LAYER_THICK_UNITS$>
* 	thisLayerInfo<1,RLThickTarget$>	= LayerSpec<PRS_LAYER_THICK_TARGET$>
* 	
* 	LayerInfo := thisLayerInfo:CHAR(248)
* 	
* NEXT I
* 
* LayerInfo[-1,1] = '' 	;* Strip trailing CHAR(248)
* 
* 
* RDSRec<RDS_LAYER_INFO$> = LayerInfo			;* End of the great Layer cluster function
* 
* IF QXJFlag THEN
* 	RDSRec<RDS_QXJ_POST$> = 0				;* And here a couple of minor cluster operations
* END
* 
* IF CustNo = '621' AND CassNo = 1 THEN
* 	RDSRec<RDS_QXJ_POST$> = 0			
* END
* 
* obj_Tables('WriteRec','RDS':@RM:RDSKey:@RM:@RM:RDSRec)
* 
* IF Get_Status(errCode) THEN
* 	Result = ''
* END ELSE
* 	Result = RDSKey
* END
* 
* 
* 
* RETURN


* * * * * * *
SchedWfrQty:
* * * * * * *
	
	IF NOT(ASSIGNED(thisRDSNo)) THEN
		thisRDSNo = Parms[1,@RM]
	END
	IF NOT(ASSIGNED(thisRDSRec)) THEN
		thisRDSRec = Parms[COL2()+1,@RM]
	END
	
	IF thisRDSNo = '' THEN  RETURN
	IF thisRDSRec = '' THEN thisRDSRec = XLATE('RDS',thisRDSNo,'','X')
	
	IF thisRDSRec = '' THEN RETURN
	
	SchedNo = thisRDSRec<RDS_SCHEDULE_NO$>
	SchedRec = XLATE('SCHEDULE',SchedNo,'','X')
	
	LOCATE thisRDSNo IN SchedRec<SCHEDULE_RDS_IDS$> USING @VM SETTING Pos THEN
		Result = SchedRec<SCHEDULE_WAFERS_IN$,Pos>
	END
	
RETURN


* * * * * * *
TestRejWfrQty:
* * * * * * *
	
	IF NOT(ASSIGNED(thisRDSNo)) THEN
		thisRDSNo = Parms[1,@RM]
	END
	IF NOT(ASSIGNED(thisRDSRec)) THEN
		thisRDSRec = Parms[COL2()+1,@RM]
	END
	
	IF thisRDSNo = '' THEN  RETURN
	IF thisRDSRec = '' THEN thisRDSRec = XLATE('RDS',thisRDSNo,'','X')
	
	IF thisRDSRec = '' THEN RETURN
	
	Tmp = 0
	Tmp += XLATE('RDS',thisRDSNo,'TOT_REJ','X')
	
	TestKeys		= XLATE('RDS_LAYER',thisRDSRec<RDS_RDS_LAYER_KEYS$>,3,'X')
	
	ProdTestWfrs	= obj_RDS_Test('ProdTestCount',TestKeys)
	
	Tmp +=  ProdTestWfrs
	
	Tmp +=  thisRDSRec<RDS_WAF_BACK_TO_INVENTORY$>  ;* <97>
	Tmp +=  thisRDSRec<RDS_RESEARCH_SRP_BILLABLE$>  ;* <221>
	
	Result = Tmp
	
RETURN


* * * * * * *
MUSrcWfrQty:
* * * * * * *
	
	IF NOT(ASSIGNED(thisRDSNo)) THEN
		thisRDSNo = Parms[1,@RM]
	END
	IF NOT(ASSIGNED(thisRDSMakeupRec)) THEN
		thisRDSMakeupRec = Parms[COL2()+1,@RM]
	END
	
	IF thisRDSNo		= '' THEN RETURN
	IF thisRDSMakeupRec	= '' THEN thisRDSMakeupRec = XLATE('RDS_MAKEUP',thisRDSNo,'','X')
	
	IF thisRDSMakeupRec NE '' THEN
		Tmp = 0
		FOR I = 1 TO COUNT(thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$>,@VM) + (thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$> NE '')
			IF thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$,I> NE '' THEN Tmp += 1
		NEXT I
	END
	
RETURN


* * * * * * *
MUDestWfrQty:
* * * * * * *
	
	IF NOT(ASSIGNED(thisRDSNo)) THEN
		thisRDSNo = Parms[1,@RM]
	END
	IF NOT(ASSIGNED(thisRDSMakeupRec)) THEN
		thisRDSMakeupRec = Parms[COL2()+1,@RM]
	END
	
	IF thisRDSNo = '' THEN  RETURN
	IF thisRDSMakeupRec = '' THEN thisRDSMakeupRec = XLATE('RDS_MAKEUP',thisRDSNo,'','X')
	
	IF thisRDSMakeupRec NE '' THEN
		Tmp = 0
		FOR I = 1 TO COUNT(thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$>,@VM) + (thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$> NE '')
			IF thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$,I> NE '' THEN Tmp += 1
		NEXT I
		Result = Tmp
	END
	
RETURN


* * * * * * *
WafersOut:
* * * * * * *
	
	IF NOT(ASSIGNED(RDSNo))		THEN RDSNo	= Parms[1,@RM]
	IF NOT(ASSIGNED(RDSRec))	THEN RDSRec	= Parms[COL2()+1,@RM]
	IF NOT(ASSIGNED(Filter))	THEN Filter = Parms[COL2()+1,@RM]
	IF NOT(ASSIGNED(NoMU))		THEN NoMU	= Parms[COL2()+1,@RM]		;* NoMU = No Makeup Wafer counts
	
	IF RDSNo = '' THEN RETURN
	IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
	
	VerifyQty	= RDSRec<RDS_VERIFY_QTY$>
	WafersIn	= RDSRec<RDS_WAFERS_IN$>
	CassWfrQty	= RDSRec<RDS_CASS_WAFER_QTY$>
	NCRKeys		= RDSRec<RDS_NCR_KEYS$>
	
	If Not(Num(WafersIn)) then
		// Log the WafersIn value
		LogData    = ''
		LogData<1> = LoggingDTM
		LogData<2> = RDSNo
		LogData<3> = WafersIn
		Logging_Services('AppendLog', objWafersLog, LogData, @RM, @FM)
		WafersIn   = WafersIn<1, 1, 1>
	end
	
	WONo			= RDSRec<RDS_WO$>
	CassNo			= RDSRec<RDS_CASS_NO$>
	MUWafersIn		= XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT_MU_ADDED','X')
	MUWafersRemoved	= XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT_USED_MU','X')
	CurrWfrCnt		= XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT','X')					;* Added 5/10/2011 JCH * * * * * * * * * * * * * *
	
	IF NCRKeys NE '' THEN
		* This happens when a box of wafers is bad upon opening in the cleanroom
		* An NCR rejecting the entire cassette is generated and the box is returned to shipping/receiving
		NCRStatuses = XLATE('NCR',NCRKeys,NCR_STATUS$,'X')			;* Added this section 09/17/2005 JCH - J.C. Henry & Co., Inc.
		IF INDEX(NCRStatuses,'O',1) ELSE
			* All NCR's are closed
			RejectQty = XLATE('NCR',NCRKeys,'REJ_CNT','X')
			* 11/17/22 - DJS/JRO - Updated the following line to check if CurrWfrCnt is equal to zero to prevent OI from
			*                      erroneously returning zero. Consider refactoring WafersOut subroutine.
			IF ( ( (SUM(RejectQty) = CassWfrQty) or (SUM(RejectQty) = WafersIn) ) and (CurrWfrCnt EQ 0) ) THEN
				Result = 0
				RETURN
			end
		END
	END
	
	TotRejects		= SUM(XLATE('NCR',NCRKeys,'REJ_CNT','X'))
	TestKeys		= XLATE('RDS_LAYER',RDSRec<RDS_RDS_LAYER_KEYS$>,3,'X')
	TWProd			= obj_RDS_Test('ProdTestCount',TestKeys)
	SRPBillable 	= RDSRec<RDS_RESEARCH_SRP_BILLABLE$>
	
	IF NoMU THEN
		Added = WafersIn
		Removed = TotRejects + TWProd + SRPBillable 
	END ELSE
		Added = WafersIn + MUWafersIn
		Removed = TotRejects + TWProd + SRPBillable + MUWafersRemoved
	END
	
	IF Filter NE '' THEN
		BEGIN CASE
			CASE Filter = 'Q'
				SignedOff = RDSRec<RDS_SUP_VER_SIG$> NE ''
			CASE Filter = 'P'
				SignedOff = RDSRec<RDS_POST_EPI_SIG$> NE ''
			CASE 1
				SignedOff = ''		;* This is an error
		END CASE
	END ELSE
		SignedOff = (RDSRec<RDS_OPERATOR_OUT$> NE '')
	END
	
	IF (Removed <= Added) AND (Added NE 0) AND SignedOff THEN	;* Added SignedOff Flag for QA on 09/21/2005 JCH - J.C. Henry & Co., Inc.
		Result = Added - Removed
		IF Result NE CurrWfrCnt THEN Result = CurrWfrCnt
	END ELSE
		Result = ''
	END 
	
RETURN


****************
YieldOutThruput:
****************
	
	RDSNo  = Parms[1,@RM]
	RDSRec = Parms[COL2()+1,@RM]
	
	YieldOut    = 0
	
	If (RDSNo NE '') then
		If (RDSRec = '') then
			RDSRec = XLATE('RDS',RDSNo,'','X')
		end
		// Number of wafers out = Number of wafers in
		WafersOut = RDSRec<RDS_WAFERS_IN$>
		
		// Calculate the total number of rejected wafers
		CustScrap    = Xlate('RDS', RDSNo, 'CUST_TOT_REJ', 'X')
		IFXScrap     = Xlate('RDS', RDSNo, 'LSL_TOT_REJ', 'X')
		TotalRejects = CustScrap + IFXScrap
		
		// Determine the number of production test wafers  
		TestKeys = XLATE('RDS_LAYER',RDSRec<RDS_RDS_LAYER_KEYS$>, 3, 'X')
		TWProd = obj_RDS_Test('ProdTestCount', TestKeys)
		
		YieldOut  = WafersOut - TotalRejects - TWProd
	end
	
	Result = YieldOut
	
return


* * * * * * *
RemMUWafers:
* * * * * * *
	
RETURN

* * * * * * *
WafersPerHour:
* * * * * * *
	
	RDSNos 	= Parms[1,@RM]
	
	IF NOT(ASSIGNED(RDSNos)) THEN RDSNos = ''
	IF RDSNos = '' THEN RETURN
	
	HoursTotal		= 0
	WafersInTotal	= 0
	TargetTotal		= 0
	
	RDSCount = COUNT(RDSNos,@VM) + (RDSNos NE '')
	FOR I = 1 TO RDSCount
		
		RDSRec = XLATE('RDS',RDSNos<1,I>,'','X')
		
		LoadDTM		= ICONV(OCONV(RDSRec<RDS_DATE_IN$>,'D4/'):' ':OCONV(RDSRec<RDS_TIME_IN$>,'MTS'),'DT')
		UnLoadDTM	= ICONV(OCONV(RDSRec<RDS_DATE_OUT$>,'D4/'):' ':OCONV(RDSRec<RDS_TIME_OUT$>,'MTS'),'DT')
		WafersIn	= RDSRec<RDS_WAFERS_IN$>
		
		If Not(Num(WafersIn)) then
			// Log the WafersIn value
			LogData    = ''
			LogData<1> = LoggingDTM
			LogData<2> = RDSNo
			LogData<3> = WafersIn
			Logging_Services('AppendLog', objWafersLog, LogData, @RM, @FM)
			WafersIn   = WafersIn<1, 1, 1>
		end
		
		IF UnloadDTM NE '' THEN
			HoursTotal		+= (UnloadDTM - LoadDTM)*24
			WafersInTotal	+= WafersIn
		END
		
		MinutesPerWfr = XLATE('PROD_SPEC',RDSRec<RDS_PROD_SPEC_ID$>,96,'X')	;* MD3 format
		
		IF MinutesPerWfr = '' THEN MinutesPerWfr = ICONV('7.333','MD3')	;* Default per Todd to get us going with OEE
		WfrsPerHour = ICONV(ICONV(60,'MD3')/MinutesPerWfr,'MD2')		;* Should be in MD2 format
		
		TargetTotal += WfrsPerHour
		
	NEXT I
	
	IF HoursTotal = 0 THEN
		Actual = ''
	END ELSE
		Actual = OCONV(ICONV(WafersInTotal/HoursTotal,'MD2'),'MD2')	;* Average Actual Wafers per Hour
	END
	
	IF RDSCount = 0 THEN
		Target = ''
	END ELSE
		Target = OCONV(ICONV(TargetTotal/RDSCount,'MD0'),'MD2')			;* Average Target Wafers per Hour
	END
	
	Result = Actual:@RM:Target
	
RETURN


* * * * * * *
AddShip:
* * * * * * *
	
	ShipNo	= Parms[1,@RM]
	RdsNo	= Parms[COL2()+1,@RM]
	ShipDt	= Parms[COL2()+1,@RM]
	ShipTm	= Parms[COL2()+1,@RM]
	Reship	= Parms[COL2()+1,@RM]
	
	If Reship EQ '' then
		Reship = False$
	end
	
	IF NOT(ASSIGNED(RdsNo))		THEN ErrorMsg = 'Unassigned Parm "RdsNo" passed to routine. (':Method:')'
	IF NOT(ASSIGNED(ShipNo))	THEN ErrorMsg = 'Unassigned Parm "ShipNo" passed to routine. (':Method:')'
	IF NOT(ASSIGNED(ShipDt))	THEN ErrorMsg = 'Unassigned Parm "ShipDt" passed to routine. (':Method:')'
	IF NOT(ASSIGNED(ShipTm))	THEN ErrorMsg = 'Unassigned Parm "ShipTm" passed to routine. (':Method:')'
	
	IF ErrorMsg NE '' THEN RETURN
	
	IF RdsNo = ''	THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
	IF ShipNo = ''	THEN ErrorMsg = 'Null Parm "ShipNo" passed to routine. (':Method:')'
	IF ShipDt = ''	THEN ErrorMsg = 'Null Parm "ShipDt" passed to routine. (':Method:')'
	IF ShipTm = ''	THEN ErrorMsg = 'Null Parm "ShipTm" passed to routine. (':Method:')'
	
	IF ErrorMsg NE '' THEN RETURN
	
	thisShipDt = ICONV(ShipDt,'D')
	IF thisShipDt = '' THEN
		ErrorMsg = 'Invalid ShipDt ':QUOTE(ShipDt):' parameter passed to routine. (':Method:')'
		RETURN
	END
	
	thisShipTm = ICONV(ShipTm,'MT')
	IF thisShipTm = '' THEN
		ErrorMsg = 'Invalid ShipTm ':QUOTE(ShipTm):' parameter passed to routine. (':Method:')'
		RETURN
	END
	
	otParms = 'RDS':@RM:RdsNo
	RDSRec = obj_Tables('ReadRec',otParms)	;* Reads and sets lock
	
	IF Get_Status(errCode) THEN RETURN			;* Problems getting the lock
	
	IF RDSRec<RDS_SHIP_NO$> = '' OR RDSRec<RDS_SHIP_NO$> = ShipNo or Reship EQ True$ THEN
		RDSRec<RDS_SHIP_NO$>	= ShipNo
		RDSRec<RDS_SHIP_DATE$>	= thisShipDt
		RDSRec<RDS_SHIP_TIME$>	= thisShipTm
		RDSRec<RDS_STATUS$>		= 'S'
		
		otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
		obj_Tables('WriteRec',otParms)
		
	END ELSE
		obj_Tables('UnlockRec',otParms)
		ErrorMsg = "RDS was already shipped on shipment" :QUOTE(RDSRec<RDS_SHIP_NO$>): ". (" :Method: ")"
	END
	
RETURN


* * * * * * *
RemShip:
* * * * * * *
	
	ShipNo	= Parms[1,@RM]
	RdsNo	= Parms[COL2()+1,@RM]
	
	IF NOT(ASSIGNED(RdsNo))		THEN ErrorMsg = 'Unassigned Parm "RdsNo" passed to routine. (':Method:')'
	IF NOT(ASSIGNED(ShipNo))	THEN ErrorMsg = 'Unassigned Parm "ShipNo" passed to routine. (':Method:')'
	
	IF ErrorMsg NE '' THEN RETURN
	
	IF RdsNo = ''	THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
	IF ShipNo = ''	THEN ErrorMsg = 'Null Parm "ShipNo" passed to routine. (':Method:')'
	
	IF ErrorMsg NE '' THEN RETURN
	
	otParms = 'RDS':@RM:RdsNo
	RDSRec = obj_Tables('ReadRec',otParms)		;* Reads and sets lock
	
	IF Get_Status(errCode) THEN RETURN			;* Problems getting the lock
	
	IF RDSRec<RDS_SHIP_NO$> = ShipNo OR RDSRec<RDS_SHIP_NO$> = '' THEN
		RDSRec<RDS_SHIP_NO$>	= ''
		RDSRec<RDS_SHIP_DATE$>	= ''
		RDSRec<RDS_SHIP_TIME$>	= ''
		RDSRec<RDS_STATUS$>		= 'R'
		
		otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
		obj_Tables('WriteRec',otParms)
		
	END ELSE
		obj_Tables('UnlockRec',otParms)
		ErrorMsg = "Passed Ship No " :QUOTE(ShipNo): " doesn't match Ship No on RDS " :QUOTE(RdsNo): ". (" :Method: ")"
	END
	
RETURN


* * * * * * *
RefreshRDSSpec:
* * * * * * * 
	
	RdsNos = Parms[1,@RM]
	
	IF RdsNos = '' THEN RETURN
	
	RTParms			= 'RDS'
	LockedRDSNos	= ''
	
	FOR I = 1 TO COUNT(RdsNos,@VM) + (RdsNos NE '')
		RdsNo = RdsNos<1,I>
		RTParms = FieldStore(RTParms, @RM, 2, 1, RdsNo)
		
		obj_Tables('LockRec',RTParms)
		IF Get_Status(errCode) THEN
			
			FOR N = 1 TO COUNT(LockedRDSNos,@VM) + (LockedRDSNos NE '')
				RTParms = FieldStore(RTParms, @RM, 2, 1, LockedRDSNos<1,N>)
				obj_Tables('UnlockRec',RTParms)		;* Unlock everything locked up to here
			NEXT N
			
			ErrorMsg = 'Unable to lock RDS ':QUOTE(RdsNo):' for update.'
			obj_Tables('UnlockRec',OTParms)
			RETURN
		END ELSE
			LockedRDSNos<1,-1> = RdsNo
		END
	NEXT I
	
	
	RDSTableVar	= FIELD(RTParms,@RM,3)
	
	FOR N = 1 TO COUNT(LockedRDSNos,@VM) + (LockedRDSNos NE '')
		LockedRDSNo = LockedRDSNos<1,N>
		READ RDSRec FROM RDSTableVar,LockedRDSNo THEN
			PS_No = RDSRec<RDS_PROD_SPEC_ID$>
			
			PSRec = XLATE('PROD_SPEC',PS_No,'','X')
			
			RDSRec<RDS_SPECIAL_INST$>	= PSRec<PROD_SPEC_SPEC_INST$>
			RDSRec<RDS_SPEC_TYPE_ORIG$>	= XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
			
			LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1)	;* Returns specs for all layers
			
			* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
			* before the equates match up correctly
			
			* Prod_Spec table has layer specs all in one field
			* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
			
			LayerSpec 	= FIELD(LayerSpecs,@RM,1)				;* Take the first Layer
			LayerSet	= FIELD(LayerSpec,@FM,1)				;* Not used here but shown for clarity
			LayerSpec	= FIELD(LayerSpec,@FM,2,99)				;* LayerSpec without the LayerSet 
			
			RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
			RecipeRec = XLATE('RECIPE',RecipeNo,'','X')			;* This used in 2nd and 3rd layer stuff (in error it appears)
			
			*		IF RecipeNo NE RDSRec<RDS_RECIPE_NO$> THEN
			*			RDSRec<RDS_RECIPE_NO$>		= RecipeNo
			*		END
			
			RDSRec<RDS_CON_MIN_ORG$>    = LayerSpec<PRS_LAYER_CONC_MIN$>
			RDSRec<RDS_CON_MAX_ORG$>    = LayerSpec<PRS_LAYER_CONC_MAX$>	
			RDSRec<RDS_CON_UNITS_ORG$>  = LayerSpec<PRS_LAYER_CONC_UNITS$>
			RDSRec<RDS_CON_TARGET_ORG$> = LayerSpec<PRS_LAYER_CONC_TARGET$>
			
			RDSRec<RDS_RES_MIN_ORG$>    = LayerSpec<PRS_LAYER_RES_MIN$>
			RDSRec<RDS_RES_MAX_ORG$>    = LayerSpec<PRS_LAYER_RES_MAX$>	
			RDSRec<RDS_RES_UNITS_ORG$>  = LayerSpec<PRS_LAYER_RES_UNITS$>
			RDSRec<RDS_RES_TARGET_ORG$> = LayerSpec<PRS_LAYER_RES_TARGET$>
			
			RDSRec<RDS_THICK_MIN_ORG$>    = LayerSpec<PRS_LAYER_THICK_MIN$>
			RDSRec<RDS_THICK_MAX_ORG$>    = LayerSpec<PRS_LAYER_THICK_MAX$>	
			RDSRec<RDS_THICK_UNITS_ORG$>  = LayerSpec<PRS_LAYER_THICK_UNITS$>
			RDSRec<RDS_THICK_TARGET_ORG$> = LayerSpec<PRS_LAYER_THICK_TARGET$>
			
			LayerInfo = ''
			
			FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
				LayerSpec = FIELD(LayerSpecs,@RM,I)		;* Take the Ith Layer
				LayerSpec = FIELD(LayerSpec,@FM,2,99)	;* LayerSpec without the LayerSet 
				
				thisLayerInfo = ''	;* Empty bucket to parse into
				
				thisLayerInfo<1,RLConMin$>		= LayerSpec<PRS_LAYER_CONC_MIN$>
				thisLayerInfo<1,RLConMax$>		= LayerSpec<PRS_LAYER_CONC_MAX$>
				thisLayerInfo<1,RLConUnits$>	= LayerSpec<PRS_LAYER_CONC_UNITS$>
				thisLayerInfo<1,RLConTarget$>	= LayerSpec<PRS_LAYER_CONC_TARGET$>
				
				thisLayerInfo<1,RLRecipeNo$> = RecipeNo			;* Copied from the original in the WRITE event of the Schedule window
				thisLayerInfo<1,RLThickRead$> = STR(@SVM,16)
				thisLayerInfo<1,RLSheetRhoRead$> = STR(@SVM,16)
				
				thisLayerInfo<1,RLResMin$>		= LayerSpec<PRS_LAYER_RES_MIN$>
				thisLayerInfo<1,RLResMax$>		= LayerSpec<PRS_LAYER_RES_MAX$>	
				thisLayerInfo<1,RLResUnits$>	= LayerSpec<PRS_LAYER_RES_UNITS$>
				thisLayerInfo<1,RLResTarget$>	= LayerSpec<PRS_LAYER_RES_TARGET$>
				
				thisLayerInfo<1,RLThickMin$>	= LayerSpec<PRS_LAYER_THICK_MIN$>
				thisLayerInfo<1,RLThickMax$>	= LayerSpec<PRS_LAYER_THICK_MAX$>	
				thisLayerInfo<1,RLThickUnits$>	= LayerSpec<PRS_LAYER_THICK_UNITS$>
				thisLayerInfo<1,RLThickTarget$>	= LayerSpec<PRS_LAYER_THICK_TARGET$>
				
				LayerInfo := thisLayerInfo:CHAR(248)
				
			NEXT I
			
			LayerInfo[-1,1] = '' 	;* Strip trailing CHAR(248)
			
			RDSRec<RDS_LAYER_INFO$> = LayerInfo			;* End of the great Layer cluster function
			
			RTParms = FieldStore(RTParms, @RM, 2, 1, LockedRDSNo)
			RTParms = FieldStore(RTParms, @RM, 4, 1, RDSRec)
			obj_Tables('WriteRec',RTParms)								;* Write and unlock RDS records
		END
	NEXT N	
	
RETURN


* * * * * * *
WMInKeys:
* * * * * * *
	
	InFlag	= 1
	OutFlag = 0
	
	GOTO WMKeys
	
	
	* * * * * * *
WMOutKeys:
* * * * * * *
	
	OutFlag = 1
	InFlag = 0
	
	
	* * * * * * *
WMKeys:
* * * * * * *
	
	RDSNo	= Parms[1,@RM]
	RDSRec	= Parms[COL2()+1,@RM]
	
	IF RDSNo = '' THEN RETURN
	IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
	
	IF InFlag THEN
		CassNos = RDSRec<RDS_IN_CASS_NO$>
	END ELSE
		CassNos = RDSRec<RDS_OUT_CASS_NO$>
	END
	
	WOStepKey = RDSRec<RDS_WO_STEP_KEY$>
	
	CassIDS = ''
	
	FOR I = 1 TO COUNT(CassNos,@VM) + (CassNos NE '')
		CassNo = CassNos<1,I>
		IF CassNo NE '' THEn
			LOCATE WOStepKey:'*':CassNo IN CassIDS BY 'AR' USING @VM SETTING Pos ELSE
				CassIDS = INSERT(CassIDS,1,Pos,0,WOStepKey:'*':CassNo)
			END
		END
	NEXT I
	
	Result = CassIDS
	
RETURN


* * * * * * *
SetSchedWfrQty:
* * * * * * *
	
	RdsNo		= Parms[1,@RM]
	SchedWfrQty	= Parms[COL2()+1,@RM]
	
	IF RdsNo = ''	THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
	IF SchedWfrQty = ''	THEN ErrorMsg = 'Null Parm "SchedWfrQty" passed to routine. (':Method:')'
	
	IF ErrorMsg NE '' THEN RETURN
	
	otParms = 'RDS':@RM:RdsNo
	RDSRec = obj_Tables('ReadRec',otParms)	;* Reads and sets lock
	
	IF Get_Status(errCode) THEN RETURN			;* Problems getting the lock
	
	RDSRec<RDS_CASS_WAFER_QTY$> = SchedWfrQty
	
	otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
	obj_Tables('WriteRec',otParms)
	
RETURN


* * * * * * *
MU_ADE_Reads:
* * * * * * *
	
	RDSNo	= Parms[1,@RM]
	RDSRec	= Parms[COL2()+1,@RM]
	
	IF RDSNo = '' THEN RETURN
	IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
	
	
	IF RDSRec = '' THEN RETURN
	
	WONo = RDSRec<RDS_WO$>
	CassNo = RDSRec<RDS_CASS_NO$>
	
	MUCassIDs = obj_WO_Mat('GetMUCassIDs',WONo:'*':CassNo)
	
	Result = XLATE('WO_MAT',MUCassIDs,'ADE_READ','X')
	
RETURN


* * * * * * * *
MetPropFlag:
* * * * * * * *
	
	RDSNo	= Parms[1,@RM]
	RDSRec	= Parms[COL2()+1,@RM]
	PropCd	= Parms[COL2()+1,@RM]
	
	IF RDSNo	= '' THEN RETURN
	IF PropCd	= '' THEN RETURN
	IF RDSRec	= '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
	
	IF RDSRec = '' THEN RETURN
	
	WONo		= RDSRec<RDS_WO$>
	WOStepKey	= RDSRec<RDS_WO_STEP_KEY$>
	ReactNo	 	= RDSRec<RDS_REACTOR$>
	PSNo		= RDSRec<RDS_PROD_SPEC_ID$>
	
	WOStepNo = FIELD(WOStepKey,'*',2)
	
	ReactRDSNos = XLATE('WO_REACT',WONo:'*':WOStepNo:'*':ReactNo,WO_REACT_RDS_NO$,'X')
	
	LOCATE RDSNo IN ReactRDSNos USING @VM SETTING Pos THEN
		Result = obj_PRS_Prop('GetIntervalFlag',PSNo:@RM:PropCd:@RM:Pos)
	END
	
RETURN



* * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
*           P r i v a t e   M e t h o d s               *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * *
CalcConTarget:
* * * * * * *
	
	IF RDSConMin AND RDSConMax THEN
		IF RDSConMin = RDSConMax THEN
			RDSConTarget = RDSConMin
		END ELSE
			Delta = INT((RdsConMax-RDSConMin)/2)
			RDSConTarget = RDSConMin + Delta
		END
	END ELSE
		RDSConTarget = ''
	END
	
RETURN


* * * * * * *
CalcResTarget:
* * * * * * *
	
	IF RDSResMin AND RDSResMax THEN
		IF RDSResMin = RDSResMax THEN
			RDSResTarget = RDSResMin
		END ELSE
			Delta = INT((RdsResMax-RDSResMin)/2)
			RDSResTarget = RDSResMin + Delta
		END
	END ELSE
		RDSResTarget = ''
	END
	
RETURN

* * * * * * *
CalcThickTarget:
* * * * * * *
	
	IF RDSThickMin AND RDSThickMax THEN
		IF RDSThickMin = RDSThickMax THEN
			RDSThickTarget = RDSThickMin
		END ELSE
			Delta = INT((RdsThickMax-RDSThickMin)/2)
			RDSThickTarget = RDSThickMin + Delta
		END
	END ELSE
		RDSThickTarget = ''
	END
	
RETURN


