COMPILE FUNCTION Comm_WO_Rec(Instruction, Parm1,Parm2)

/*
	Commuter module for WO_Rec (Work Order Receipt) window
	
	05/18/2004 - John C. Henry, J.C. Henry & Co., Inc.
*/

DECLARE SUBROUTINE Set_Property,  Set_Status, ErrMsg, Set_Property, obj_AppWindow, obj_Notes, Print_RX_Voucher, obj_Tables
DECLARE SUBROUTINE Btree.Extract, Send_Event, Security_Err_Msg, Forward_Event, End_Window, obj_WO_Log, obj_WO_Mat
DECLARE SUBROUTINE Logging_Services, Post_Event, Work_Order_Services, Error_Services, Database_Services, Service_Services
DECLARE FUNCTION   Get_Property, Get_Status, Popup, Send_Message, Msg, Security_Check, Dialog_Box, RowExists, obj_Prod_Spec
DECLARE FUNCTION   obj_Schedule, Dialog_Box, obj_WO_Log, obj_Order_Det, FindWindow,ShowWindow, obj_Tables, obj_WO_Mat, MemberOf
DECLARE FUNCTION   Logging_Services, Environment_Services, Work_Order_Services, Error_Services, Service_Services
DECLARE FUNCTION   SRP_Array, GetTickCount, Datetime, Wo_Mat_Services

$INSERT POPUP_EQUATES
$INSERT LOGICAL
$INSERT MSG_EQUATES
$INSERT APPCOLORS
$INSERT WO_LOG_EQUATES
$INSERT WO_MAT_EQUATES
$INSERT QUOTE_EQU
$INSERT QUOTE_DET_EQU
$INSERT ORDER_EQU
$INSERT ORDER_DET_EQU
$INSERT COMPANY_EQU
$INSERT PROD_SPEC_EQUATES
$INSERT QUOTE_SPEC_EQU
$INSERT LSL_USERS_EQU
$INSERT SECURITY_RIGHTS_EQU
$INSERT NOTIFICATION_EQU
$INSERT PROD_VER_EQUATES
$INSERT EPI_PART_EQUATES
$INSERT CUST_EPI_PART_EQUATES
$Insert IFX_EQUATES
$Insert PROC_QUEUE2_EQUATES

EQU CRLF$	TO \0D0A\

EQU COL$CASS_NO				TO 1		;* Equates for CASS_NO edit table control (cassettes received)
EQU COL$CASS_LOT_NO			TO 2
EQU COL$CASS_QTY			TO 3
EQU COL$CASS_CUST_PART_NO	TO 4
EQU COL$CASS_SUB_PART_NO	TO 5
EQU COL$CASS_SUB_VEND_CD	TO 6
EQU COL$CASS_TIME_STAMP		TO 7
EQU COL$CASS_SCAN_BY		TO 8
EQU COL$CASS_ORDER_ITEM		TO 9


EQU COL$OD_ITEM_NO			TO 1		;* Equates for ORDER_DETAIL control (material ordered)
EQU COL$OD_CUST_PART_NO		TO 2
EQU COL$OD_CUST_PN_DESC		TO 3
EQU COL$OD_CUST_PN_INBOUND	TO 4
EQU COL$OD_SUB_PART_NO		TO 5
EQU COL$OD_PROMISE_DT		TO 6
EQU COL$OD_ITEM_QTY			TO 7
EQU COL$OD_WAFER_QTY		TO 8

EQU CA$ITEM_NO         TO 1			;* Equates for Checking Array passed to Scan routine
EQU CA$LOT_NO          TO 2
EQU CA$LOT_QTY         TO 3
EQU CA$CUST_PART_NO    TO 4
EQU CA$SUB_PART_NO     TO 5
EQU CA$SCANNED_LOT_QTY TO 6
EQU CA$VERIFY_PART_NO  TO 7
EQU CA$SUB_SUPP_BY     TO 8
EQU CA$WO_NO           TO 9
EQU CA$REC_DTM         TO 10

LogPath       = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_LOG'
LogDate       = Oconv(Date(), 'D4/')
LogTime       = Oconv(Time(), 'MTS')
LogFileName   = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WO_MAT Receive Performance Log.csv'
Headers       = 'Logging DTM':@FM:'WO':@FM:'User':@FM:'Cassettes (Qty)':@FM:'WO_MAT Create (Secs)':@FM:'Form Refresh (Secs)':@FM:'Total Duration (Secs)':@FM:'Seconds/Cassette'
objReceiveLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$)

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


ErrTitle = 'Error in Comm_WO_Rec'
ErrorMsg = ''
ErrCode  = ''

Result = ''

BEGIN CASE
	CASE Instruction = 'Create' 		; GOSUB Create
	CASE Instruction = 'Refresh'		; GOSUB Refresh
	CASE Instruction = 'Page'			; GOSUB Page
	CASE Instruction = 'Read'			; GOSUB Read
	CASE Instruction = 'Clear'			; GOSUB Clear
	CASE Instruction = 'Delete'			; GOSUB Delete
	CASE Instruction = 'Close'			; GOSUB Close
	CASE Instruction = 'LUWONo'			; GOSUB LUWONo
	CASE Instruction = 'DueInWONos'		; GOSUB DueInWONos
	CASE Instruction = 'PrintVoucher'	; GOSUB PrintVoucher
	CASE Instruction = 'Scan'			; GOSUB Scan
	CASE Instruction = 'AddLeftover'	; GOSUB AddLeftover
	CASE 1
		ErrorMsg = 'Unknown Instruction passed to routine'
END CASE

IF ErrorMsg NE '' THEN
	ErrMsg(ErrTitle:@SVM:ErrorMsg)
END

RETURN Result


* * * * * * * 
Create:
* * * * * * *

    IF NOT(Security_Check('WO Log',READ$)) THEN
        Security_Err_Msg('WO Log',READ$)
        End_Window(@WINDOW)
        RETURN
    END

    IOOptions    = Get_Property(@Window, 'IOOPTIONS')
    IOOptions<2> = 2 ; // Database bound form - Do not lock the record
    Set_Property(@Window, 'IOOPTIONS', IOOptions)

    obj_Appwindow('Create',@WINDOW)

    GOSUB Refresh

    Parent = Get_Property(@Window, 'PARENT')
    If Parent EQ 'NDW_RELEASE_CASSETTES' then
        WONo = Get_Property(Parent:'.EDL_WO_NO', 'TEXT')
        Set_Property(@Window:'.WO_NO', 'TEXT', WONo)
        Post_Event(@Window, 'READ')
    end

RETURN


* * * * * * *
Read:
* * * * * * *

    WONo = Get_Property(@WINDOW:'.WO_NO','TEXT')

    IF RowExists('WO_LOG',WONo) THEN
        IF NOT(Security_Check('Work Order',READ$)) THEN
            Send_Event(@WINDOW,'CLEAR')
            Security_Err_Msg('Work Order',READ$)
            RETURN
        END
    END ELSE
        ErrMsg('Work Order Log entries may only be created from the ORDER window.')
        Send_Event(@WINDOW,'CLEAR')
        RETURN
    END


    ProdVerNo = Get_Property(@WINDOW:'.PROD_VER','DEFPROP')

    IF ProdVerNo = '' THEN
        ErrMsg('Work Order has not been routed.')
        Send_Event(@WINDOW,'CLEAR')
        RETURN
    END

    RxBy = Get_Property(@WINDOW:'.RX_BY','TEXT')
    IF RxBy = '' THEN
        CurrDate = OCONV(Date(),'D4/')
        CurrTime = OCONV(Time(),'MTS')
        CurrDTM = CurrDate:' ':CurrTime
        Set_Property(@WINDOW:'.RX_BY','TEXT',OCONV(@USER4,'[XLATE_CONV,LSL_USERS*FIRST_LAST]'))
        Set_Property(@WINDOW:'.RX_DTM','TEXT',CurrDTM)
    END

    Def = ""
    Def<MTEXT$> = "Loading cassette data..."
    Def<MTYPE$> = "U"
    MsgUp = Msg(@window, Def)   
    Columns  = 'CASS_NO':@VM:'LOT_NO':@VM:'WAFER_QTY':@VM:'CUST_PART_NO':@VM:'SUB_PART_NO':@VM:'SUB_VEND_CD':@VM:'RX_DTM':@VM:'RX_BY':@VM:'ORDER_ITEM'
    WOMatKeys = Wo_Mat_Services('GetWOMatKeys', WONo)
    If Error_Services('NoError') then
    	If (WOMatKeys NE '') then 
			CassData = WO_Mat_Services('GetWOMatData', WOMatKeys, Columns)
			If Error_Services('NoError') then
				Set_Property(@Window:'.CASS_NO', 'ARRAY', CassData)
				Msg(@window, MsgUp) 
			end else
				Msg(@window, MsgUp)        
				Msg(@Window, '', 'OK', '', 'Process Error':@FM:Error_Services('GetMessage'))
			end
		end else
			Msg(@window, MsgUp)       
		end
    end else
        Msg(@window, MsgUp)         
        Msg(@Window, '', 'OK', '', 'Process Error':@FM:Error_Services('GetMessage'))
    end
    
    GOSUB Refresh

RETURN


* * * * * * *
Clear:
* * * * * * *

    Send_Event(@WINDOW,'PAGE',1)

    GOTO Refresh

RETURN


* * * * * * *
Delete:
* * * * * * *

    Result = 0	;* No deletes from here

RETURN



* * * * * * *
Page:
* * * * * * *

	Page = Parm1
	
	IF Page = '' THEN
		Page = Get_Property(@WINDOW:'.TAB_MAIN','VALUE')
	END ELSE
		Set_Property(@WINDOW:'.TAB_MAIN','VALUE',Page)
	END
	
	Set_Property(@WINDOW,'VPOSITION', Page)

    GOSUB Refresh

RETURN



* * * * * * *
Close:
* * * * * * *

    Send_Event(@WINDOW,'CLEAR')		;* If this isn't here, the WO_LOG record has a lock on it

    obj_Appwindow('DetailReturn')

RETURN 


* * * * * * *
Refresh:
* * * * * * *

    Ctrls  = @WINDOW:'.RX_BY':@RM	; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.RX_DTM'		; Props := 'DEFPROP'

    Vals = Get_Property(Ctrls,Props)

    RxBy	= Vals[1,@RM]
    RxDTM	= Vals[COL2()+1,@RM]

    IF RxBy	= ''	THEN Vals  = 1:@RM	ELSE Vals  = 0:@RM
    IF RxDTM = ''	THEN Vals := 1		ELSE Vals := 0

    Props = 'ENABLED':@RM:'ENABLED'

    Set_Property(Ctrls,Props,Vals)


    Ctrls  = @WINDOW:'.WO_QTY':@RM		; Props  = 'DEFPROP':@RM
    Ctrls := @WINDOW:'.RX_QTY'			; Props := 'DEFPROP'

    Vals = Get_Property(Ctrls,Props)

    WOQty	= ICONV(Vals[1,@RM],'MD0')
    RxQty	= ICONV(Vals[COL2()+1,@RM],'MD0')

    IF RxQty >= WOQty THEN
        Set_Property(@WINDOW:'.SCAN_BUTTON','ENABLED',-1)	;* Already RX'd complete
    END ELSE
        Set_Property(@WINDOW:'.SCAN_BUTTON','ENABLED',1)	;* Not yet received complete
    END

    * QBF buttons

    Ctrls  = @WINDOW:'.QBF_FIRST_FIX':@RM		; Props  = 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_PREV_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_ABS_FIX':@RM			; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_NEXT_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_LAST_FIX':@RM		; Props := 'ENABLED':@RM
    Ctrls := @WINDOW:'.QBF_STOP_FIX'			; Props := 'ENABLED'

    IF Get_Property(@WINDOW,'QBFLIST') = '' THEN
        Vals = 0:@RM:0:@RM:0:@RM:0:@RM:0:@RM:0
    END ELSE
        Vals = 1:@RM:1:@RM:1:@RM:1:@RM:1:@RM:1
    END

    Set_Property(Ctrls,Props,Vals)

    * Turn edit table symbolic column backgrounds to green

    ETSymbolics = Get_Property(@WINDOW,'@ET_SYMBOLICS')		;* Loaded during 'Create' in obj_Appwindow

    ETCtrls	= ETSymbolics<1>
    ETCols	= ETSymbolics<2>

    FOR I = 1 TO COUNT(ETCtrls,@VM) + (ETCtrls NE '')
        ETCtrl	= ETCtrls<1,I>
        IF ETCtrl NE @WINDOW:'.ALL_RDS_KEYS' THEN
            ETList = Get_Property(ETCtrl,'LIST')
            FOR Line = 1 TO COUNT(ETList,@FM) + (ETList NE '')
                IF ETList<Line,1> NE '' THEN
                    FOR N = 1 TO COUNT(ETCols<1,I>,@SVM) + (ETCols<1,I> NE '')
                        stat = Send_Message(ETCtrl,'COLOR_BY_POS',ETCols<1,I,N>,Line,GREEN$)
                    NEXT N
                END
            NEXT Line
        END
    NEXT I

RETURN


* * * * * * *
DueInWONos:
* * * * * * *

    OPEN 'DICT.WO_LOG' TO DictWOLogTable ELSE
        RETURN
    END

    MsgUp = Msg(@WINDOW,'','SELECT_OPEN_WO')

    WOKeys = ''

    SelectStatement = 'CURR_STATUS_STATIC':@VM:'ASN':@VM:'AWM':@VM:'RTP':@FM

    Btree.Extract(SelectStatement,'WO_LOG',DictWOLogTable,WOKeys,'','')

    IF Get_Status(errCode) THEN
        ErrMsg(errCode)
        Msg(@WINDOW,MsgUp)
        RETURN
    END

    Msg(@WINDOW,MsgUp)

    TypeOver = ''
    TypeOver<PDISPLAY$> = WOKeys

    DueInWONo = Popup(@WINDOW,TypeOver,'DUE_IN_WORK_ORDERS')

    IF DueInWONo NE '' THEN
        obj_AppWindow('LoadFormKeys',@WINDOW:@RM:DueInWONo)
    END

RETURN


* * * * * * *
LUWONo:
* * * * * * *

    Set_Status(0)

    WONo = Dialog_Box( 'DIALOG_WO_DUE_IN', @WINDOW, '' )

    IF Get_Status(errCode) THEN ErrMsg(ErrCode)

    IF WONo NE '' THEN
        obj_Appwindow('LoadFormKeys',@WINDOW:@RM:WONo)
    END

RETURN


* * * * * * * 
OpenWOS:
* * * * * * *

    OpenWONo = obj_WO_Log('OpenWONos','')

    IF OpenWONo NE '' THEN
        obj_AppWindow('LoadFormKeys',@WINDOW:@RM:OpenWONo)
    END

RETURN


* * * * * * *
PrintVoucher:
* * * * * * *

    WONo = Get_Property(@WINDOW:'.WO_NO','TEXT')

    IF WONo = '' THEN RETURN

    Send_Event(@WINDOW,'WRITE')

    Print_RX_Voucher(WONo)

    obj_Appwindow('LoadFormKeys',@WINDOW:@RM:WONo)

    Set_Property('SYSTEM','FOCUS','VSPRINTER')

RETURN


* * * * * * *
Scan:
* * * * * * *
    
    WONo        = Get_Property(@WINDOW:'.WO_NO','TEXT')
    CtrlEntID   = @WINDOW:'.CASS_NO'
    CassList    = Get_Property(CtrlEntID,'LIST')
    CassArray   = Get_Property(CtrlEntID,'DEFPROP')
    CassListCnt = COUNT(CassList,@FM)

    CassPointer = 1
    LOOP
        IF CassList<CassPointer,COL$CASS_NO> NE '' THEN
            CassPointer += 1
        END ELSE
            CassList = DELETE(CassList,CassPointer,0,0)
        END
    UNTIL CassList<CassPointer> = ''
        
    REPEAT

    ExistCassCnt = COUNT(CassList,@FM) + (CassList NE '')
    WORec        = XLATE('WO_LOG',WONo,'','X')
    WOMatKeys    = WORec<WO_LOG_WO_MAT_KEY$>									;* List of WO_MAT Keys associated with this WO_LOG Record  * * * * * * *
    OpenQty      = ICONV(Get_Property(@WINDOW:'.OPEN_QTY','DEFPROP'),'MD0')	;* Scan button is disabled if there isn't anything to receive
    EPIPartNo    = WORec<WO_LOG_EPI_PART_NO$>
    EPIPartRec   = XLATE('EPI_PART',EpiPartNo,'','X')
    SubSuppBy    = EPIPartRec<EPI_PART_SUB_SUPP_BY$>		;* L - EpiSvcs supplied, C - Customer Supplied
    SAPMaterial  = EPIPartRec<EPI_PART_SAP_MATERIAL$>	;* 0 = 
    OrderNo      = Get_Property(@WINDOW:'.ORDER_NO','TEXT')
    
    IF OrderNo = '' THEN

        ProdVerNo       = WORec<WO_LOG_PROD_VER_NO$>
        ProdVerRec 		= XLATE('PROD_VER',ProdVerNo,'','X')
        SubPartNo		= ProdVerRec<PROD_VER_SUB_PART_NO$>
        ProdVerStepPSNs	= ProdVerRec<PROD_VER_PROC_STEP_PSN$>	;* Added 6/24/2016 JCH - GaN receipt
        
        Vendor = WORec<WO_LOG_EXP_VEND_CD$>				;* Added 4/14/2014
        IF LEN(Vendor) NE 2 THEN Vendor = ''
        
        IF SubSuppBy = 'L' THEN
            VendorDef = Vendor
        END ELSE
            VendorDef = ''
        END
        
        CheckArray = ''
        CheckArray<CA$ITEM_NO,1>		= 1
        CheckArray<CA$LOT_NO,1>			= WORec<WO_LOG_CUST_LOT_NO$>
        CheckArray<CA$LOT_QTY,1> 		= OpenQty						;* Qty of wafers left to receive
        
        CustPartNo = WORec<WO_LOG_CUST_PART_NO$>
        
        IF CustPartNo = '' THEN
            CheckArray<CA$CUST_PART_NO,1>	= WORec<WO_LOG_EPI_PART_NO$>		;******** This bites us farther in ****** JCH 10/13/2011  check with DK and then dump
        END ELSE
            CheckArray<CA$CUST_PART_NO,1>	= CustPartNo
        END
        
        CheckArray<CA$SUB_PART_NO,1>	= WORec<WO_LOG_ORD_SUB_PART_NO$>	;* This is the Substrate Part No received from SAP
        CheckArray<CA$VERIFY_PART_NO,1>	= ''
        CheckArray<CA$SUB_SUPP_BY>		= SubSuppBy

        CheckArray = VendorDef:@FM:CheckArray
     
    END ELSE

        OrderDetailList = Get_Property(@WINDOW:'.ORDER_ITEMS','LIST')	;* Get Order Items from the control on the 2nd page

        ORDCnt = COUNT(OrderDetailList,@FM) + (OrderDetailList NE '')

        FOR I = OrdCnt TO 1 STEP -1
        WHILE OrderDetailList<I,COL$OD_ITEM_NO> = ''
            OrderDetailList = DELETE(OrderDetailList,I,0,0)				;* Strip blank lines from control data
        NEXT I

        CheckArray = ''
        CALine = 1		
        FOR I = 1 TO COUNT(OrderDetailList,@FM) + (OrderDetailList NE '')
            OrdItem = OrderDetailList<I,COL$OD_ITEM_NO>
            
            IF OrderDetailList<I,COL$OD_CUST_PN_INBOUND> NE '' THEN
                VerifyPartNo = OrderDetailList<I,COL$OD_CUST_PN_INBOUND>
            END ELSE
                VerifyPartNo = OrderDetailList<I,COL$OD_CUST_PART_NO>
            END
            
            ItemLotNos = WORec<WO_LOG_CUST_LOT_NO$>
            ItemLotQtys = WORec<WO_LOG_CUST_LOT_QTY$>
            
            IF ItemLotNos = '' THEN
                ItemLotNos = XLATE('ORDER_DET',OrderNo:'*':OrdItem,ORDER_DET_CUST_LOT_NO$,'X')		;* Get the list of expected lot numbers on that item
                ItemLotQtys = XLATE('ORDER_DET',OrderNo:'*':OrdItem,ORDER_DET_CUST_LOT_QTY$,'X')	;* Get the list of expected lot qtys for associated item
            END
            
            IF ItemLotNos = '' THEN
                IF OrderDetailList<I,COL$OD_WAFER_QTY> NE '' THEN
                
                    CheckArray<CA$ITEM_NO,CALine>			= OrderDetailList<I,COL$OD_ITEM_NO>
                    CheckArray<CA$LOT_NO,CALine>			= ''
                    CheckArray<CA$LOT_QTY,CALine>			= ICONV(OrderDetailList<I,COL$OD_WAFER_QTY>,'MD0')
                    CheckArray<CA$CUST_PART_NO,CALine>		= OrderDetailList<I,COL$OD_CUST_PART_NO>
                    CheckArray<CA$SUB_PART_NO,CALine>		= OrderDetailList<I,COL$OD_SUB_PART_NO>
                    CheckArray<CA$VERIFY_PART_NO,CALine>	= VerifyPartNo		
                    CheckArray<CA$SUB_SUPP_BY>				= SubSuppBy				
                END
            
            END ELSE
            
                FOR N = 1 TO COUNT(ItemLotNos,@VM) + (ItemLotNos NE '')
                
                    LOCATE ItemLotNos<1,N> IN CheckArray<CA$LOT_NO> USING @VM SETTING Pos THEN
                        CheckArray<CA$LOT_QTY,Pos> = CheckArray<CA$LOT_QTY,Pos> + ItemLotQtys<1,N>
                    END ELSE
                        CheckArray = INSERT(CheckArray,CA$ITEM_NO,Pos,0,OrderDetailList<I,COL$OD_ITEM_NO>)
                        CheckArray = INSERT(CheckArray,CA$LOT_NO,Pos,0,ItemLotNos<1,N>)
                        CheckArray = INSERT(CheckArray,CA$LOT_QTY,Pos,0,ItemLotQtys<1,N>)
                        CheckArray = INSERT(CheckArray,CA$CUST_PART_NO,Pos,0,OrderDetailList<I,COL$OD_CUST_PART_NO>)
                        CheckArray = INSERT(CheckArray,CA$SUB_PART_NO,Pos,0,OrderDetailList<I,COL$OD_SUB_PART_NO>)
                        CheckArray = INSERT(CheckArray,CA$VERIFY_PART_NO,Pos,0,VerifyPartNo)
                        CheckArray = INSERT(CheckArray,CA$SUB_SUPP_BY,Pos,0,SubSuppBy)
                    END
                    
                NEXT N
            END
            
        NEXT I

        FOR I = 1 TO COUNT(CassList,@FM) + (CassList NE '')
            CassLotNo	= CassList<I,COL$CASS_LOT_NO>
            CassQty		= CassList<I,COL$CASS_QTY>
            LOCATE CassLotNo IN CheckArray<CA$LOT_NO> USING @VM SETTING Pos THEN
                CheckArray<CA$LOT_QTY,Pos> = CheckArray<CA$LOT_QTY,Pos> - CassQty		;* Back out lot qtys already scanned
            END
        NEXT I

        CheckArray = '':@FM:CheckArray
        
    END	;* End of check for Order Number present ***********************************

    NewCassetteCnt         = 0
    CheckArray<CA$WO_NO>   = WONo
    CheckArray<CA$REC_DTM> = Datetime()
    ProcIds                = Dialog_Box('DIALOG_WO_SCAN', @WINDOW, CheckArray)	
    
    WOMatCreateStartTime = Time()
    
    Done = False$
    IF ( (ProcIds NE 'Cancel') and (ProcIds NE '') ) THEN
        
        Timeout          = 180000
        
        NumProcIds       = DCount(ProcIds, @FM)
        Def              = ''
        Def<MCAPTION$>   = 'Receiving and Releasing Cassettes...'
        Def<MTYPE$>      = 'G'
        Def<MEXTENT$>    = NumProcIds
        Def<MTEXTWIDTH$> = 600
        MsgUp            = Msg(@WINDOW,Def)
        
        Start            = GetTickCount()
        Done             = False$
        NumCompleteProcs = 0
        Loop
            RemainingProcs   = DCount(ProcIds, @FM)
            CompletedProcIds = ''
            For ProcIndex = 1 to RemainingProcs
                ProcId = ProcIds<ProcIndex>
                If RowExists('PROC_QUEUE2', ProcId) then
                    // Proc is still processing. Check if error recorded.
                    ErrorMsg = Xlate('PROC_QUEUE2', ProcId, PROC_QUEUE2.ERROR$, 'X')
                    If ErrorMsg NE '' then
                        Msg(@Window, '', 'OK', '', 'Process Error':@FM:ErrorMsg)
                        Database_Services('DeleteDataRow', 'PROC_QUEUE2', ProcId, True$, False$)
                    end
                end else
                    // Proc is done or failed
                    CompletedProcIds<-1> = ProcId
                end
            Next ProcIndex
            If CompletedProcIds NE '' then
                NumCompleteProcs += DCount(CompletedProcIds, @FM)
                ProcIds           = SRP_Array('Join', ProcIds, CompletedProcIds, 'XOR', @FM)
            end
            Now         = GetTickCount()
            Runtime     = Now - Start
            Msg(@WINDOW, MsgUp, NumCompleteProcs, MSGINSTUPDATE$)
        Until (ProcIds EQ '') or (Runtime GT Timeout)
        Repeat

        // Take down gas guage
        Msg(@window, MsgUp)
        
        If (Runtime GT Timeout) then
			// Notify OI_SYSADMIN group
			Recipients   = ''
			SentFrom     = 'SYSTEM'
			Subject      = 'Receiving and Releasing Error for Work Order ':WONo
			Message      = OConv(Datetime(), 'DT/^S')
			Swap @FM with CRLF$ in CompletedProcIds
			Swap @FM with CRLF$ in ProcIds
			Message<2>   = 'Completed ProcIds: ':CompletedProcIds
			Message<3>   = 'Incomplete ProcIds: ':ProcIds
			AttachWindow = ''
			AttachKey    = ''
			SendToGroup  = 'OI_SYSADMIN'
			Parms        = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
			obj_Notes('Create',Parms)			
            
            ErrorMsg = 'The server is taking longer than expected to process the receive / ':CRLF$:'release requests. FI has been alerted to the issue.'
            Msg(@Window, '', 'OK', '', 'Process Error':@FM:ErrorMsg)
        end
        
        WOMatCreateStopTime  = Time()
        FormRefreshStartTime = Time()
        FormRefreshStopTime  = Time()
        WOMatCreateDuration  = WOMatCreateStopTime - WOMatCreateStartTime
        FormRefreshDuration  = FormRefreshStopTime - FormRefreshStartTime
        TotalDuration        = WOMatCreateDuration + FormRefreshDuration

        LogData       = ''
        LogData<1>    = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS')
        LogData<2>    = WONo
        LogData<3>    = @User4
        LogData<4>    = NewCassetteCnt
        LogData<5>    = WOMatCreateDuration
        LogData<6>    = FormRefreshDuration
        LogData<7>    = TotalDuration

        If (NewCassetteCnt GT 0) then
            LogData<8>    = TotalDuration / NewCassetteCnt
        end else
            LogData<8>    = 'N/A'
        end
        Logging_Services('AppendLog', objReceiveLog, LogData, @RM, @FM)  
        
        Service_Services('PostProcedure', 'WORK_ORDER_SERVICES', 'UpdateWorkOrderData':SD$:WONo)
        
        Post_Event(@Window, 'READ')
    end

RETURN


* * * * * * *
RecGaN:
* * * * * * *

    WfrsRxd			= SUM(ScanResults<3>)									;* Total Wafers received
    CassettesRxd 	= COUNT(ScanResults<1>,@VM) + (ScanResults<1> NE  '')	;* Total Cassettes received

    * IF CassShipQty <= 0 THEN CassShipQty = 25
    CassShipQty     = 25                                                    ;! We are hardcoding this to 25
    WOMatReq 		= INT(WfrsRxd/CassShipQty)								;* Qty of WO_MAT records required

    IF MOD(WfrsRxd,CassShipQty) THEN
        WOMatReq += 1														;* Add another WO_MAT for a short qty box at the end
    END

    PSNo = ProdVerStepPSNs<1,1>											;* This is GaN => single WO Step 

    WfrSigProfile = obj_Prod_Spec('GetWfrSigProfile',PSNo)				;* Final QA signature on the shipping cassette. (like EpiPro)

    LastInCassNo = ''
    LastOutCassNo = ''

    * * * *  Loop through existing WOMatKeys and set pointers for newly received information  * * * *

    IF WOMatKeys NE '' THEN
        womCnt = COUNT(WOMatKeys,@VM) + (WOMatKeys NE '')
        FOR I = 1 TO womCnt
            WOMatKey	= WOMatKeys<1,I>
            RxDTM 		= XLATE('WO_MAT',WOMatKey,WO_MAT_RX_DTM$,'X')
            IF RxDTM NE '' THEN
                LastInCassNo = I		;* This assumes cassettes received are in numerical order and none have been deleted out of sequence
            END
            LastOutCassNo = I
        NEXT I
    END


    Def = ''
    Def<MCAPTION$>		= 'Receiving Cassettes...'
    Def<MTYPE$>			= 'G'
    Def<MEXTENT$>		= CassettesRxD
    Def<MTEXTWIDTH$>	= 600
    MsgUp = Msg(@WINDOW,Def)	

    NextInCassNo = LastInCassNo + 1
    NextOutCassNo = LastOutCassNo + 1

    FOR I = 1 TO WOMatReq

        Msg(@WINDOW, MsgUp, I, MSGINSTUPDATE$)
            
        WOMatExists = ''
        
        CassNo = NextInCassNo
        WOMatKey = WONo:'*':CassNo
        
        LOCATE WOMatKey IN WOMatKeys BY 'AR' USING @VM SETTING NewPos ELSE
            WOMatKeys = INSERT(WOMatKeys,1,NewPos,0,WOMatKey)
        END

        ErrorMsg = ''
        
        IF  ScanResults<1,I> NE '' THEN
        
            otParms = 'WO_MAT':@RM:WOMatKey
        
            WOMatRec = obj_Tables('ReadRec',otParms)		;* WOMat record may be an outbound on
            
            IF Get_Status(errCode) THEN ErrorMsg = 'Error in COMM_WO_REC("RecGaN"). Error message: ':errCode
            
            IF WOMatRec NE '' THEN WOMatExists = 1
            
            RxDTM = ScanResults<COL$CASS_TIME_STAMP,I>
            
            RxDTM	= ICONV( ScanResults<COL$CASS_TIME_STAMP,I> , 'DT' )
            RxBy	= ScanResults<COL$CASS_SCAN_BY,I>
        
            IF WOMatExists THEN
                
                * * Add Receiving information to existing   * * WO_MAT record
                    
                WOMatRec<WO_MAT_LOT_NO$>		= ScanResults<COL$CASS_LOT_NO,I>
                WOMatRec<WO_MAT_WAFER_QTY$>		= ScanResults<COL$CASS_QTY,I>
                WOMatRec<WO_MAT_CUST_PART_NO$>	= ScanResults<COL$CASS_CUST_PART_NO,I>
                WOMatRec<WO_MAT_ORDER_ITEM$>	= ScanResults<COL$CASS_ORDER_ITEM,I>
                WOMatRec<WO_MAT_SUB_PART_NO$>	= ScanResults<COL$CASS_SUB_PART_NO,I>
                WOMatRec<WO_MAT_SUB_VEND_CD$>	= ScanResults<COL$CASS_SUB_VEND_CD,I>
                WOMatRec<WO_MAT_INV_DTM$>		= RxDTM
                WOMatRec<WO_MAT_INV_USER$>		= RxBy
                WOMatRec<WO_MAT_INV_WH$>		= 'SR'		;* Shipping/Receiving
                WOMatRec<WO_MAT_INV_LOCATION$>	= 'RB'		;* Receiving bench
                WOMatRec<WO_MAT_INV_ACTION$>	= 'RCVD'
                WOMatRec<WO_MAT_INV_DTM$>		= RxDTM
                WOMatRec<WO_MAT_INV_TAG$>		= ''			;* No tag actually scanned -> so no tag value
                WOMatRec<WO_MAT_INV_USER$>		= RxBy
                WOMatRec<WO_MAT_RX_DTM$>		= RxDTM
                WOMatRec<WO_MAT_RX_BY$>			= RxBy
                
                
                WaferCnt	= WOMatRec<WO_MAT_WAFER_QTY$>		;* Changed to add slots for both EpiPRO and standard reactor types 8/13/2010 JCH		
                ShipCnt		= WOMatRec<WO_MAT_CASS_SHIP_QTY$>	

                BEGIN CASE
                    CASE ShipCnt = ''		; SlotCnt = WaferCnt
                    CASE WaferCnt > ShipCnt ; SlotCnt = WaferCnt
                    CASE WaferCnt < ShipCnt	; SlotCnt = ShipCnt
                    CASE WaferCnt = ShipCnt	; SlotCnt = ShipCnt
                END CASE

                    
                FOR S = 1 TO SlotCnt
                    WOMatRec<WO_MAT_SLOT_NO$,S> = S			
                NEXT S
                
                otParms = FIELDSTORE(otParms,@RM,4,0,WOMatRec)
                obj_Tables('WriteRec',otParms)
                
                IF Get_Status(errCode) THEN ErrorMsg = 'Error in COMM_WO_REC("RecGaN"). Error message: ':errCode
                
            END ELSE
        
                * * Create new WO_MAT record with Receiving Data * *
                
                WOMatRec = ''
                
                WOMatRec<WO_MAT_LOT_NO$>		= ScanResults<COL$CASS_LOT_NO,I>
                WOMatRec<WO_MAT_WAFER_QTY$>		= ScanResults<COL$CASS_QTY,I>
                WOMatRec<WO_MAT_CUST_PART_NO$>	= ScanResults<COL$CASS_CUST_PART_NO,I>
                WOMatRec<WO_MAT_ORDER_ITEM$>	= ScanResults<COL$CASS_ORDER_ITEM,I>
                
                WOMatRec<WO_MAT_SUB_PART_NO$>	= ScanResults<COL$CASS_SUB_PART_NO,I>
                WOMatRec<WO_MAT_SUB_VEND_CD$>	= ScanResults<COL$CASS_SUB_VEND_CD,I>
                WOMatRec<WO_MAT_INV_DTM$>		= RxDTM
                WOMatRec<WO_MAT_INV_USER$>		= RxBy
                WOMatRec<WO_MAT_INV_WH$>		= 'SR'		;* Shipping/Receiving
                WOMatRec<WO_MAT_INV_LOCATION$>	= 'RB'		;* Receiving bench
                WOMatRec<WO_MAT_INV_ACTION$>	= 'RCVD'
                WOMatRec<WO_MAT_INV_DTM$>		= RxDTM
                WOMatRec<WO_MAT_INV_TAG$>		= ''			;* No tag actually scanned -> so no tag value
                WOMatRec<WO_MAT_INV_USER$>		= RxBy
                WOMatRec<WO_MAT_RX_DTM$>		= RxDTM
                WOMatRec<WO_MAT_RX_BY$>			= RxBy
                
                WOMatRec<WO_MAT_PROD_VER_NO$>		= ProdVerNo
                WOMatRec<WO_MAT_SUB_SUPPL_BY$>		= SubSuppBy
                WOMatRec<WO_MAT_CASS_SHIP_QTY$>		= CassShipQty
                WOMatRec<WO_MAT_SIG_PROFILE$>		= obj_WO_Mat('CassSigProfile',WOMatKey) ;*******************
                
                WaferCnt	= WOMatRec<WO_MAT_WAFER_QTY$>		;* Changed to add slots for both EpiPRO and standard reactor types 8/13/2010 JCH		
                ShipCnt		= WOMatRec<WO_MAT_CASS_SHIP_QTY$>
                
                BEGIN CASE
                    CASE ShipCnt = ''		; SlotCnt = WaferCnt
                    CASE WaferCnt > ShipCnt ; SlotCnt = WaferCnt
                    CASE WaferCnt < ShipCnt	; SlotCnt = ShipCnt
                    CASE WaferCnt = ShipCnt	; SlotCnt = ShipCnt
                END CASE
        
                FOR S = 1 TO SlotCnt
                    WOMatRec<WO_MAT_SLOT_NO$,S> = S			
                NEXT S
                
                otParms = FIELDSTORE(otParms,@RM,4,0,WOMatRec)
                obj_Tables('WriteRec',otParms)
                
                IF Get_Status(errCode) THEN ErrorMsg = 'Error in COMM_WO_REC("RecGaN"). Error message: ':errCode
                
            END 	;* End of check for existing WO_MAT record
            
            NextInCassNo += 1
            
            IF NextInCassNo >= NextOutCassNo THEN
                NextOutCassNo += 1
            END
            
        END	ELSE
        
            * * Create new WO_MAT record without Receiving Data * *
            
            WOMatRec = ''
            
            WOMatRec<WO_MAT_PROD_VER_NO$>		= ProdVerNo
            WOMatRec<WO_MAT_SUB_SUPPL_BY$>		= SubSuppBy
            WOMatRec<WO_MAT_CASS_SHIP_QTY$>		= CassShipQty
            WOMatRec<WO_MAT_SIG_PROFILE$>		= obj_WO_Mat('CassSigProfile',WOMatKey)
            
            SlotCnt	= WOMatRec<WO_MAT_CASS_SHIP_QTY$>	

            FOR S = 1 TO SlotCnt
                WOMatRec<WO_MAT_SLOT_NO$,S> = S			
            NEXT S
                
            otParms = 'WO_MAT':@RM:WOMatKey:@RM:@RM:WOMatRec
            obj_Tables('WriteRec',otParms)
            
            IF Get_Status(errCode) THEN ErrorMsg = 'Error in COMM_WO_REC("RecGaN"). Error message: ':errCode
            
            NextOutCassNo += 1
        
        END		;* End of check to see if a new Out Only WO_MAT is needed
        
    NEXT I

    Msg(@WINDOW,MsgUp)		;* Take down processing message

    If ErrorMsg NE '' then Msg(@Window, '', 'OK', '', 'Process Error':@FM:ErrorMsg)

    IF LastInCassNo > 0 THEN

        ScanResults = CassArray
        
        Scheduled = XLATE('WO_LOG',WONo,'SCHEDULED','X')
        
        IF Scheduled THEN
            
            * Message to production about change in Work Order Size
                
            Recipients 		= XLATE('NOTIFICATION','MAST_SCHED_BEG',NOTIFICATION_USER_ID$,'X')		;* Added 10/03/2005 JCH - J.C. Henry & Co., Inc
            OtherRecipients	= XLATE('NOTIFICATION','MAST_SCHED_END',NOTIFICATION_USER_ID$,'X')		;* Added 10/03/2005 JCH - J.C. Henry & Co., Inc
            
            FOR N = 1 TO COUNT(OtherRecipients,@VM) + (OtherRecipients NE '')
                OtherRecip = OtherRecipients<1,N>
                LOCATE OtherRecip IN Recipients USING @VM SETTING Pos ELSE
                    Recipients = INSERT(Recipients,1,Pos,0,OtherRecip)
                END
            NEXT N
            
            SentFrom		= @USER4
            Subject			= 'Cassettes Added to Work Order'
            Message			= CassettesRxd:" Cassettes have been added to Scheduled Work Order ":WONo
            AttachWindow	= 'WO_PROD'
            AttachKey		= WONo
            SendToGroup		= ''

            Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
            *obj_Notes('Create',Parms)
            
        END

    END	;* End of check for previously received material

    Set_Property(CtrlEntID,'DEFPROP',ScanResults)

    IF ScanResults NE '' THEN
        Recipients = XLATE('NOTIFICATION','MATERIAL_RECEIPT',NOTIFICATION_USER_ID$,'X')		;* Added 10/04/2005 JCH - J.C. Henry & Co., Inc
        SentFrom   = @USER4
        Subject    = 'Cassettes Received for Work Order'
        Message    = "Cassettes have been received for Work Order ":WONo
        NewForm    = Xlate('APP_INFO', 'NEW_WO_FORM', '', 'X')
        If NewForm then
            AttachWindow	= 'NDW_WO_LOG'
        end else
            AttachWindow	= 'WO_LOG2'
        end
        AttachKey		= WONo
        SendToGroup		= ''

        Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
        obj_Notes('Create',Parms)
    END

    Set_Property(@WINDOW:'.RX_BY','DEFPROP',OCONV(@USER4,'[XLATE_CONV,LSL_USERS*FIRST_LAST]'))		;* Current user
    Set_Property(@WINDOW:'.RX_DTM','DEFPROP',OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS') )			;* Current timestamp
    Set_Property(@WINDOW:'.WO_MAT_KEY','DEFPROP',WOMatKeys)

    Send_Event(@WINDOW,'WRITE')

    obj_AppWindow('LoadFormKeys','WO_REC':@RM:WONo)

RETURN


* * * * * * *
AddLeftover:
* * * * * * *

RETURN

