Compile function WO_MAT_Services(@Service, @Params)
/***********************************************************************************************************************

    Name        :   WO_MAT_Services

    Description :   Handler program for all WO_MAT services.

    Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
                    assumptions built into way errors are managed which are important to understand in order to properly
                    work with Error Services:

                    - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
                      the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
                      this will appear backwards since the originating procedure always appears at the bottom of the
                      list and the current routine appears at the top of the list. We are using this orientation because
                      it is common to refer to the process of calling other procedures as 'drilling down'.

                    - The reason for defining the orientation of the call stack is because Error_Services allows for
                      multiple error conditions to be appended to an original error. In most cases this will happen when
                      a procedure at the bottom of the stack generates an error condition and then returns to its
                      calling procedure. This higher level procedure can optionally add more information relevant to
                      itself. This continues as the call stack 'bubbles' its way back to the top to where the
                      originating procedure is waiting.

                    - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
                      preserve their error state until explicitly cleared. This can hinder the normal execution of code
                      since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
                      Our philosophy is that error conditions should automatically be cleared before a new procedure
                      is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
                      automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
                      philosophy then it should include a call into the 'Clear' service request at the top of the
                      program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)

                    - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
                      error conditions that were set before.

    Parameters  :
        Service         [in] -- Name of the service being requested
        Param1-10   [in/out] -- Additional request parameter holders
        Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure

    Metadata    :

    History     :   (Date, Initials, Notes)
        05/14/18    djs     Added VerifyWOLogWOMatKeyColumn service.

***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler

$insert LOGICAL
$Insert APP_INSERTS
$insert WO_MAT_EQUATES
$Insert WO_LOG_EQUATES
$Insert SERVICE_SETUP
$Insert DICT_EQUATES

Declare function   Database_Services, Error_Services, SRP_Json, SRP_Com, Environment_Services, Logging_Services
Declare function   Datetime, Rds_Services, GetTickCount, SRP_Array, Date_Services
Declare subroutine Error_Services, SRP_Json, SRP_Com, Wo_Mat_Services, Database_Services, Logging_Services
Declare subroutine obj_wo_mat_log, Set_Status, Rds_Services, Signature_Services, Mona_Services, Btree.Extract
Declare subroutine Transaction_Services

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_Mat\InvActionsSyncUp'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' InvActionsSyncUpLog.csv'
Headers		= 'Logging DTM' : @FM : 'WOMatKey' : @FM : 'Missing Signature' : @FM : 'Missing Signature Dtm' : @FM : 'Message' 
objSyncLog	= Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

IsProd = Environment_Services('IsProd')
If IsProd EQ True$ then
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_WOMATSERVICES'
end else
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_DEV_WOMATSERVICES'
end

GoToService else
	Error_Services('Set', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
end

Return Response or ""

//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------

Service ConvertRecordToJSON(WOMatKey, Record, ItemURL)
    
    jsonRecord = ''
    IF WOMatKey NE '' then
        If Record EQ '' then Record = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
        If Error_Services('NoError') then
            @DICT   = Database_Services('GetTableHandle', 'DICT.WO_MAT')
            @ID     = WOMatKey
            @RECORD = Record
            objJSON = ''
            If SRP_JSON(objJSON, 'New', 'Object') then
                objWOMat = ''
                If SRP_JSON(objWOMat, 'New', 'Object') then
                    SRP_JSON(objWOMat, 'SetValue', 'KeyId', @ID)
                    SRP_JSON(objWOMat, 'SetValue', 'WoNo', {WO_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'CassNo', {CASS_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'Ver', {REC_VER})
                    SRP_JSON(objWOMat, 'SetValue', 'ProdOrdNo', {PROD_ORD_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'SapBatchNo', {SAP_BATCH_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'SapTxDtm', OConv({SAP_TX_DTM}, 'DT'))
                    SRP_JSON(objWOMat, 'SetValue', 'ReactorType', {REACTOR_TYPE})
                    SRP_JSON(objWOMat, 'SetValue', 'CustInfo', {CUST_INFO})
                    SRP_JSON(objWOMat, 'SetValue', 'LotNo', {LOT_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'WaferQty', {WAFER_QTY})
                    SRP_JSON(objWOMat, 'SetValue', 'CustPartNo', {CUST_PART_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'SubPartNo', {SUB_PART_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'ProdVerNo', {PROD_VER_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'ShipNo', {SHIP_NO})
                    SRP_JSON(objWOMat, 'SetValue', 'Hold', {HOLD})
                    SRP_JSON(objWOMat, 'SetValue', 'Makeup', {MAKEUP_BOX})
                    SRP_JSON(objWOMat, 'SetValue', 'HotLot', {HOT_LOT})
                    SRP_JSON(objWOMat, 'SetValue', 'Cancelled', {CANCELLED})
                    SRP_JSON(objWOMat, 'SetValue', 'Void', {VOID})
                    SRP_JSON(objWOMat, 'SetValue', 'RetReject', {RET_REJECTS})
                    SRP_JSON(objWOMat, 'SetValue', 'CassShipQty', {CASS_SHIP_QTY})
                    SRP_JSON(objWOMat, 'SetValue', 'GrQty', {SAP_GR_QTY})
                    SRP_JSON(objWOMat, 'SetValue', 'SapYield', {SAP_YIELD})
                    SRP_JSON(objWOMat, 'SetValue', 'SapMuQty', {SAP_MU_QTY})
                    SRP_JSON(objWOMat, 'SetValue', 'SapRawScrapQty', {SAP_RAW_SCRAP_QTY})
                    SRP_JSON(objWOMat, 'SetValue', 'SapScrapQty', {SAP_CONFIRM_SCRAP})
                    objInvActions = ''
                    If SRP_JSON(objInvActions, 'New', 'Array') then
                        InventoryActions = {INV_DTM}
                        If InventoryActions NE '' then
                            for each InvAction in InventoryActions using @VM setting vPos
                                //Add in each indv. inventory action
                                InvTimestamp = {INV_DTM}<1, vPos>
                                InvWhCd      = {INV_WH}<1, vPos>
                                InvWarehouse = {INV_WH_DESC}<1, vPos>
                                InvLocCd     = {INV_LOCATION}<1, vPos>
                                InvLocation  = {INV_LOC_DESC}<1, vPos>
                                InvAction    = {INV_ACTION}<1, vPos>
                                InvUserId    = {INV_USER}<1, vPos>
                                InvTag       = {INV_TAG}<1, vPos>
                                InvToolId    = {INV_TOOL_ID}<1, vPos>
                                objInvAction = ''
                                If SRP_JSON(objInvAction, 'New', 'Object') then
                                    SRP_JSON(objInvAction, 'SetValue', 'InvTimestamp', Oconv(InvTimeStamp, 'DT'))
                                    SRP_JSON(objInvAction, 'SetValue', 'InvWhCd', InvWhCd)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvWarehouse', InvWarehouse)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvLocCd', InvLocCd)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvLocation', InvLocation)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvAction', InvAction)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvUserId', InvUserId)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvTag', InvTag)
                                    SRP_JSON(objInvAction, 'SetValue', 'InvToolId', InvToolId)
                                    SRP_JSON(objInvActions, 'Add', objInvAction)
                                    SRP_JSON(objInvAction, 'Release')
                                end
                            Next InvAction
                        end else
                            SRP_JSON(objWOMat, 'SetValue', 'InventoryActions', '')
                        end
                        SRP_JSON(objWOMat, 'Set', 'InventoryActions', objInvActions)
                        SRP_JSON(objInvActions, 'Release')
                    end
                    objSlots = ''
                    If SRP_JSON(objSlots, 'New', 'Array') then
                        SlotCount = 25
                        for Slot = 1 to SlotCount
                            SlotNo        = Slot
                            WaferId       = {SLOT_WAFER_ID}<1, Slot>
                            NcrId         = {SLOT_NCR}<1, Slot>
                            MetNo         = {SLOT_MET_NO}<1, Slot>
                            MovedToSlot   = {SLOT_MOVED_TO}<1, Slot>
                            MuWaferId     = {SLOT_REP_WAFER_ID}<1, Slot>
                            MovedFromSlot = {SLOT_MOVED_FROM}<1, Slot>
                            objSlot       = ''
                            If SRP_JSON(objSlot, 'New', 'Object') then
                                SRP_JSON(objSlot, 'SetValue', 'SlotNo', SlotNo)
                                SRP_JSON(objSlot, 'SetValue', 'WaferId', WaferId)
                                SRP_JSON(objSlot, 'SetValue', 'NcrId', NcrId)
                                SRP_JSON(objSlot, 'SetValue', 'MetNo', MetNo)
                                SRP_JSON(objSlot, 'SetValue', 'MovedToSlot', MovedToSlot)
                                SRP_JSON(objSlot, 'SetValue', 'MuWaferId', MuWaferId)
                                SRP_JSON(objSlot, 'SetValue', 'MovedFromSlot', MovedFromSlot)
                                SRP_JSON(objSlots, 'Add', objSlot)
                                SRP_JSON(objSlot, 'Release')
                            end
                        Next Slot
                        SRP_JSON(objWOMat, 'Set', 'Slots', objSlots)
                        SRP_JSON(objSlots, 'Release')
                    end
                    objNCRs = ''
                    If SRP_JSON(objNCRs, 'New', 'Array') then
                        NCRs = {NCR_KEYS}
                        if DCount(NCRs, @VM) GT 0 then
                            for each NCRKey in NCRs setting nPos
                                NcrId          = NCRKey
                                NcrStatus      = {NCR_STATUS}<1, nPos>
                                NcrQty         = {NCR_REJ_CNT}<1, nPos>
                                NcrResp        = {NCR_LOSS_BY}<1, nPos>
                                NcrStage       = {NCR_LOSS_STAGE}<1, nPos>
                                NcrLossDesc    = {NCR_LOSS_DESC}<1, nPos>
                                NcrLossComment = {NCR_LOSS_COMMENT}<1, nPos>
                                objNCR         = ''
                                If SRP_JSON(objNCR, 'New', 'Object') then
                                    SRP_JSON(objNCR, 'SetValue', 'NcrId', NcrId)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrStatus', NcrStatus)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrQty', NcrQty)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrResp', NcrResp)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrStage', NcrStage)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrLossDesc', NcrLossDesc)
                                    SRP_JSON(objNCR, 'SetValue', 'NcrLossComment', NcrLossComment)
                                    SRP_JSON(objNCRs, 'Add', objNCR)
                                    SRP_JSON(objNCR, 'Release')
                                end
                            Next NCRKey
                        

                            SRP_JSON(objWOMat, 'Set', 'NCRs', objNCRs)
                            SRP_JSON(objNCRs, 'Release')
                        end else
                            SRP_JSON(objWOMat, 'SetValue', 'NCRs', '')
                        end
                        objHolds = ''
                        If SRP_JSON(objHolds, 'New', 'Array') then
                        HoldDtms = {HOLD_START_DTM}
                        if DCount(HoldDtms, @VM) GT 0 then
                            for each HoldDtm in HoldDtms setting hPos
                                OnHoldDtm     = OConv(HoldDtm, 'DT')
                                HoldUser      = {HOLD_START_USER}<1, hPos>
                                OnHoldReason  = {HOLD_START_REASON}<1, hPos>
                                OffHoldDtm    = {HOLD_STOP_DTM}<1, hPos>
                                OffHoldUser   = {HOLD_STOP_USER}<1, hPos>
                                OffHoldReason = {HOLD_STOP_REASON}<1, hPos>
                                HoldEntity    = {HOLD_ENTITY}<1, hPos>
                                HoldEntityId  = {HOLD_ENTITY_ID}<1, hPos>
                                objHold       = ''
                                If SRP_JSON(objHold, 'New', 'Object') then
                                    SRP_JSON(objHold, 'SetValue', 'OnHoldDtm', OnHoldDtm)
                                    SRP_JSON(objHold, 'SetValue', 'HoldUser', HoldUser)
                                    SRP_JSON(objHold, 'SetValue', 'OnHoldReason', OnHoldReason)
                                    SRP_JSON(objHold, 'SetValue', 'OffHoldDtm', OffHoldDtm)
                                    SRP_JSON(objHold, 'SetValue', 'OffHoldUser', OffHoldUser)
                                    SRP_JSON(objHold, 'SetValue', 'OffHoldReason', OffHoldReason)
                                    SRP_JSON(objHold, 'SetValue', 'HoldEntity', HoldEntity)
                                    SRP_JSON(objHold, 'SetValue', 'HoldEntityId', HoldEntityId)
                                    SRP_JSON(objHolds, 'Add', objHold)
                                    SRP_JSON(objHold, 'Release')
                                end
                            Next HoldDtm
                            SRP_JSON(objWOMat, 'Set', 'Holds', objHolds)
                            SRP_JSON(objHolds, 'Release')
                        end else
                            SRP_JSON(objWOMat, 'SetValue', 'Holds', '')
                        end
                        end
                        SRP_JSON(objJSON, 'Set', 'WO_Mat', objWOMat)
                        SRP_JSON(objWOMat, 'Release')
                    end
                end
                If itemURL NE '' then
                    // The itemURL was passed in so add HAL+JSON properties.
                    // Create the _links property and then all link objects needed for this resource.
                    objLinks = ''
                    If SRP_JSON(objLinks, 'New', 'Object') then
                        // Create a self link.
                        objLink = ''
                        If SRP_JSON(objLink, 'New', 'Object') then
                            SRP_JSON(objLink, 'SetValue', 'href', ItemURL, 'String')
                            SRP_JSON(objLink, 'SetValue', 'title', 'Self', 'String')
                            SRP_JSON(objLinks, 'Set', 'self', objLink)
                            SRP_JSON(objLink, 'Release')
                        end
                        SRP_JSON(objJSON, 'Set', '_links', objLinks)
                        SRP_JSON(objLinks, 'Release')
                    end

                    // Create the _class property for this resource.
                    SRP_JSON(objJSON, 'SetValue', '_class', 'resource')
                end
                jsonRecord = SRP_JSON(objJSON, 'Stringify', 'Styled')
                SRP_JSON(objJSON, 'Release')
            end else
                Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
            end
        end
    end else
        Error_Services('Add', 'KeyID argument was missing in the ' : Service : ' service.')
    end
    Response    = jsonRecord
    
End Service


Service ConvertRecordToJsonOIWizard(WOMatKey, WOMatRec)
    
    Json = ''
    If WOMatKey NE '' then
        If WOMatRec EQ '' then WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
        If Error_Services('NoError') then
            objJSON = ''
            If SRP_JSON(objJSON, 'New', 'Object') then
                objWOMat = ''
                If SRP_JSON(objWOMat, 'New', 'Object') then                   
                    SRP_JSON(objWOMat, 'SetValue', 'KeyId', WOMatKey)
                    SRP_JSON(objWOMat, 'SetValue', 'CassNo', Field(WOMatKey, '*', 2, 1))
                    SRP_JSON(objWOMat, 'SetValue', 'SAPBatchNo', WOMatRec<WO_MAT_SAP_BATCH_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'SAPTXDtm', Date_Services('ConvertDateTimeToISO8601', WOMatRec<WO_MAT_SAP_TX_DTM$>))
                    SRP_JSON(objWOMat, 'SetValue', 'RDSNo', WOMatRec<WO_MAT_RDS_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'ShipNo', WOMatRec<WO_MAT_SHIP_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'LotNo', WOMatRec<WO_MAT_LOT_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'Qty', WOMatRec<WO_MAT_WAFER_QTY$>)
                    SRP_JSON(objWOMat, 'SetValue', 'CustPartNo', WOMatRec<WO_MAT_CUST_PART_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'SubPartNo', WOMatRec<WO_MAT_SUB_PART_NO$>)
                    SRP_JSON(objWOMat, 'SetValue', 'VendorCd', WOMatRec<WO_MAT_SUB_VEND_CD$>)
                    SRP_JSON(objWOMat, 'SetValue', 'RecDtm', Date_Services('ConvertDateTimeToISO8601', WOMatRec<WO_MAT_RX_DTM$>))
                    SRP_JSON(objWOMat, 'SetValue', 'RelDtm', Date_Services('ConvertDateTimeToISO8601', WOMatRec<WO_MAT_REL_DTM$>))
                    SRP_JSON(objWOMat, 'SetValue', 'RecUser', OConv(WOMatRec<WO_MAT_RX_BY$>, '[XLATE_CONV,LSL_USERS*FIRST_LAST]'))
                    SRP_JSON(objWOMat, 'SetValue', 'RelUser', OConv(WOMatRec<WO_MAT_REL_BY$>, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ))
                    SRP_JSON(objJSON, 'Set', 'WO_Mat', objWOMat)
                    SRP_JSON(objWOMat, 'Release')                   
                    Json = SRP_JSON(objJSON, 'Stringify', 'Fast')
                end else
                    Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
                end
                SRP_JSON(objJSON, 'Release')
            end else
                Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
            end
        end
    end else
        Error_Services('Add', 'KeyID argument was missing in the ' : Service : ' service.')
    end
    Response    = Json
    
end service


//----------------------------------------------------------------------------------------------------------------------
// GetWaferMap
//
// Returns a @VM delimited array of boolean values, which represents which slots are filled.
// Note: The response is in the slot order 25, 24, ..., 2, 1.
//----------------------------------------------------------------------------------------------------------------------
Service GetWaferMap(WOMatKey)
    
    WaferMap = ''
    ErrorMsg = ''
    If WOMatKey NE '' then
        If RowExists('WO_MAT', WOMatKey) then
            ReactType    = Xlate('WO_MAT', WOMatKey, 'REACTOR_TYPE', 'X')
            If ReactType NE 'EPP' then 
                SlotWaferIDs = Xlate('WO_MAT', WOMatKey, 'SLOT_WAFER_ID', 'X')
                WaferMap     = ''
                For SlotIndex = 1 to 25
                    SlotWaferID            = SlotWaferIDs<0, SlotIndex>
                    WaferMap = Insert(WaferMap, 0, 1, 0, (SlotWaferID NE '') )
                Next SlotIndex
            end else
                ErrorMsg = 'Error in ':Service:' service. EpiPro is not supported by this service. Use WM_OUT_SERVICES instead.'
            end
        end else
            ErrorMsg = 'Error in ':Service:' service. WO_MAT record ':WOMatKey:' does not exist.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WOMatKey passed in.'
    end
    
    If ErrorMsg EQ '' then
        Response = WaferMap
    end else
        Error_Services('Add', ErrorMsg)
        Response = False$
    end
    
end service


Service CheckInvActionsSignatureSync()
    
	hSysLists  = Database_Services('GetTableHandle', 'SYSLISTS')
	Lock hSysLists, ServiceKeyID then
		Script = "SELECT WO_MAT_SIG_PROFILE.WO_NO, WO_MAT_SIG_PROFILE.CASS_NO,WO_MAT_SIG_PROFILE.CASS_ID_SAP, WO_MAT_SIG_PROFILE.SIG_DTM, WO_MAT_SIG_PROFILE.SIGNATURE, WMSP.SIG_PROFILE FROM WO_MAT_SIG_PROFILE "
		Script := "Left JOIN WO_MAT_SIG_PROFILE_AUDIT WMSP ON WO_MAT_SIG_PROFILE.WO_NO = WMSP.WO_NO AND WO_MAT_SIG_PROFILE.CASS_NO = WMSP.CASS_NO AND WO_MAT_SIG_PROFILE.SIG_PROFILE = WMSP.SIG_PROFILE "
		Script := "WHERE SIG_DTM != '' AND (WMSP.SIG_PROFILE IS NULL OR WMSP.SIG_PROFILE = '') AND WO_MAT_SIG_PROFILE.SIG_DTM > DATEADD(day, -1, GETDATE()) AND WO_MAT_SIG_PROFILE.SIGNATURE != 'AUTO_FQA' AND WO_MAT_SIG_PROFILE.SIGNATURE IS NOT NULL order by WO_NO desc"
		Connection = ''
		RecordSetResult = ''
		If SRP_Com(Connection, "CREATE", "ADODB.Connection") then
			ConnectionString = Environment_Services('GetSQLScrapeConnectionString')
			If SRP_Com(Connection, "CALL", "Open", ConnectionString) EQ "" then
				RecordSetResult = SRP_Com(Connection, "CALL", "Execute", Script)
				Records = SRP_Com(RecordSetResult, "CALL", "GetString", 2, -1, @VM, @FM)
				SRP_Com(RecordSetResult, "RELEASE")
			end else
				Ans = 'Unable to open connection to SQL server. SQL connection error: ':SRP_Com(Connection, "ERROR")
			end
			SRP_Com(Connection, "CALL", "Close")
			SRP_Com(Connection, "RELEASE")
		end else
			Ans = "Unable to create ADO connection."
		end
		if Records then
			for each WOMatRecord in Records using @FM
				WO = WOMatRecord<1,1>
				CassNo = WOMatRecord<1,2>
				WOMatKey = WO : '*' : CassNo
				WO_MAT_SERVICES('SyncWOMatInvActionsAndSigProfile', WoMatKey)
			Next WOMatRecord
		end
		Unlock hSysLists, ServiceKeyID else Null
	end
	
end service


Service SyncWOMatInvActionsAndSigProfile(WOMatKey)
    
	If RowExists('WO_MAT', WOMatKey) then
		OrigWOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
		WOMatRec     = OrigWOMatRec
		SigProfile     = WOMatRec<WO_MAT_SIG_PROFILE$>
		Sigs           = WOMatRec<WO_MAT_SIGNATURE$>
		SigDtms        = WOMatRec<WO_MAT_SIG_DTM$>
		OrigInvActions = WOMatRec<WO_MAT_INV_ACTION$>           
		For each Stage in SigProfile using @VM setting vPos
			if SigDtms<0, vPos> NE '' then
				Locate Stage in OrigInvActions using @VM setting dummy else
				// Stage missing from material log
					InvDtms     = WOMatRec<WO_MAT_INV_DTM$>
					StageSigDtm = SigDtms<0, vPos>
					Done        = False$
					For each InvDtm in InvDtms using @VM setting Pos
						If InvDtm _GTX StageSigDtm then Done = True$
					Until Done
					Next InvDtm
					// Insert stage into material log
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_WH$,Pos,0,'CR')
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_LOCATION$,Pos,0,'FE')
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_ACTION$,Pos,0,Stage)
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_DTM$,Pos,0,StageSigDtm)
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_USER$,Pos,0,Sigs<0, vPos>)
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_TAG$,Pos,0,'')
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_TOOL_ID$,Pos,0,'')
					WOMatRec = INSERT(WOMatRec,WO_MAT_INV_SCAN_ENTRY$,Pos,0,0)
					
					LogData = ''
					LogData<1> = LoggingDtm
					LogData<2> = WOMatKey
					LogData<3> = Stage
					LogData<4> = StageSigDtm
					LogData<5> = 'Adding To Record.'
					Logging_Services('AppendLog', objSyncLog, LogData, @RM, @FM)
				end
			end
		Next Stage
		If WOMatRec NE OrigWOMatRec then 
			Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
			If Error_Services('NoError') then
				LogData = ''
				LogData<1> = LoggingDtm
				LogData<2> = WOMatKey
				LogData<3> = ''
				LogData<4> = ''
				LogData<5> = 'Successfully Wrote WO_Mat Record'
				Logging_Services('AppendLog', objSyncLog, LogData, @RM, @FM)
			end else
				LogData = ''
				LogData<1> = LoggingDtm
				LogData<2> = WOMatKey
				LogData<3> = ''
				LogData<4> = ''
				LogData<5> = 'Error writing WO_MAT record.'
				Logging_Services('AppendLog', objSyncLog, LogData, @RM, @FM)
			end
		end
	end else
		LogData = ''
		LogData<1> = LoggingDtm
		LogData<2> = WOMatKey
		LogData<3> = ''
		LogData<4> = ''
		LogData<5> = 'WO_MAT record did not exist in OpenInsight.'
		Logging_Services('AppendLog', objSyncLog, LogData, @RM, @FM)
	end
	
end service


Service CassetteIsLastInWo(WoMatKey)
    
	StartTick = GetTickCount()
    MetricName = 'CassetteIsLastInWo'
	
	IsLastInWo = False$
	
	ErrMsg = ''
	If Unassigned(WoMatKey) or WoMatKey EQ '' or RowExists('WO_MAT', WoMatKey) NE True$ then
		ErrMsg = 'invalid WO_MAT key'
	end
	
	WO = Field(WoMatKey, '*', 1)
	If WO EQ '' then
		ErrMsg = 'WO# not found in WO_MAT record'
	end
	If ErrMsg EQ '' and Num(WO) EQ False$ then
		ErrMsg = 'WO# is not numeric'
	end
	
	CassNo = Field(WoMatKey, '*', 2)
	If ErrMsg EQ '' and CassNo EQ '' then
		ErrMsg = 'Cassette# not found in WO_MAT record'
	end
	If ErrMsg EQ '' and Num(CassNo) EQ False$ then
		ErrMsg = 'Cassette# is not numeric'
	end
	
	If ErrMsg EQ '' then
		WoMatKeys = Xlate('WO_LOG', WO, WO_LOG_WO_MAT_KEY$, 'X')
		If WoMatKeys NE '' then
			TotalCassettes = DCount(WoMatKeys, @VM)
			IsLastInWo = TotalCassettes EQ CassNo
		end else
			ErrMsg = 'WO_MAT keys not found in WO_LOG for WO ':WO
		end
	end
	
	Response = IsLastInWo
	
	EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    If ErrMsg NE '' then
		LogData = ''
		LogData<1> = LoggingDtm
		LogData<2> = WOMatKey
		LogData<3> = ''
		LogData<4> = ''
		LogData<5> = 'Error in ' : Service:': ' : ErrMsg
		Logging_Services('AppendLog', objSyncLog, LogData, @RM, @FM)
		
		Error_Services('Add', ErrMsg)
	end
    
end service


Service SetWoMatVoidFlag(WoMatKey, Username)
    
	ErrorMessage = ''
	If RowExists('WO_MAT', WoMatKey) then
			WoMatRec = Database_Services('ReadDataRow', 'WO_MAT', WoMatKey, True$, 0, False$)
			If Error_Services('NoError') then
				WoMatRec<WO_MAT_VOID$> = True$
				HaveLock = Database_Services('GetKeyIDLock', 'WO_MAT', WoMatKey, True$)
				If HaveLock then
					Database_Services('WriteDataRow', 'WO_MAT', WoMatKey, WoMatRec, True$, False, False$)
					If Error_Services('NoError') then
					    Set_Status(0)
					    WONo = Field(WoMatKey, '*', 1)
					    CassNo = Field(WoMatKey, '*', 2)
						WOMLParms = ''
                        LogFile	= 'WO_MAT'					; WOMLParms  = LogFile:@RM
                        LogDTM	= OConv(Datetime(), 'DT')	; WOMLParms := LogDTM:@RM
                        Action	= 'VOID'					; WOMLParms := Action:@RM
                        WhCd	= 'CR'						; WOMLParms := WhCd:@RM
                        LocCd	= 'VOID'					; WOMLParms := LocCd:@RM
                        WONos	= WONo						; WOMLParms := WONos:@RM
                        CassNos	= CassNo					; WOMLParms := CassNos:@RM
                        UserID	= Username					; WOMLParms := UserID:@RM
                        Tags	= ''						; WOMLParms := Tags:@RM
                        ToolID	= ''						; WOMLParms := ToolID:@RM
                        WOMLParms := ''
                        obj_WO_Mat_Log('Create',WOMLParms)
                        IF Get_Status(errCode) THEN
                            ErrorMessage = 'Error writing inventory transactions'
                        end
					end else
					    ErrorMessage = 'Failed to write to the WO_MAT record ' : WoMatKey : ' while attempting to set void status.'
					end
				end else
					ErrorMessage = 'Failed to get lock on WO_MAT record ' : WoMatKey : ' while attempting to set void status.'
				end
			end else
				ErrorMessage = 'Failed to read WO_MAT record ' : WoMatKey : ' while attempting to set void status.'
			end
	end else
		ErrorMessage = 'Invalid WoMat Key ' : WoMatKey : ' passed to SetWoMatVoidFlag routine.'
	end
	If ErrorMessage NE '' then
		Error_Services('Add', ErrorMessage)
	end
	
end service


Service MakeupFlagOn(WOMatKey)
   
	ErrorMsg = ''
	If (WOMatKey NE '') then
		If RowExists('WO_MAT', WOMatKey) then
			RDSNo    = Database_Services('ReadDataColumn', 'WO_MAT', WOMatKey, WO_MAT_RDS_NO$)
			If Error_Services('NoError') then
				EpiCheck   = Rds_Services('IsEpiPro', RDSNo)
				BioRadDown = False$
				Bio4Down   = False$
				Bio5Down   = False$
				Bio4LogKey = Xlate('TOOL', 'BIORAD4', 'CURR_MODE_KEY', 'X')
				Bio5LogKey = Xlate('TOOL', 'BIORAD5', 'CURR_MODE_KEY', 'X')
				Bio4Mode   = Xlate('TOOL_LOG', Bio4LogKey, 'TOOL_MODE', 'X')
				Bio5Mode   = Xlate('TOOL_LOG', Bio5LogKey, 'TOOL_MODE', 'X')
				
				If (Bio4Mode NE 'PROD') AND (Bio4Mode NE 'LIM') then Bio4Down = True$
				If (Bio5Mode NE 'PROD') AND (Bio5Mode NE 'LIM') then Bio5Down = True$
				
				If (Bio4Down) AND (Bio5Down) then BioRadDown = True$
				
				If EpiCheck EQ False$ then
					WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
					WOMatQARec = XLATE('WO_MAT_QA',WOMatKey,'','X')
					PropRow = WOMatQARec<3>
					If (Count(PropRow, 'THICK') NE 0) AND (BioRadDown EQ False$) then
						CurrentStage = Rds_Services('GetCurrentStage', RDSNo)
						If CurrentStage EQ 'COMP' then
							Signature_Services('UnsignFQAStage', RDSNo)
						end
						Rds_Services('ApplyQA100PercentADE', RDSNo)
					end
				end				
			end else
				ErrorMsg  = 'Error in ':Service:' service. Error reading RDS_NO from WO_MAT record ':WOMatKey:'. '
				ErrorMsg := 'Error message: ':Error_Services('GetMessage')
			end
		end else
			ErrorMsg  = 'Error in ':Service:' service. WO_MAT record ':WOMatKey:' does not exist.'
		end
	end else
		ErrorMsg  = 'Error in ':Service:' service. Null WOMatKey passed into service.'
	end
    
end service


Service GetWOMatData(WOMatKeys, Columns)
    
    Response = ''
    ErrorMsg = ''
    If ( (WOMatKeys NE '') and (Columns NE '') ) then
        For each Column in Columns using @VM setting ColPos
            Vals = Xlate('WO_MAT', WOMatKeys, Column, 'X')
            Conv = Xlate('DICT.WO_MAT', Column, DICT_CONV$, 'X')
            If Conv EQ '' then
                Response<ColPos> = Vals
            end else
                Response<ColPos> = OConv(Vals, Conv)
            end
        Next Column
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WOMatKeys or Columns passed into service'
    end
    
    If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
    
end service


Service GetWOMatKeys(WONo)
    
    Response = ''
    ErrorMsg = ''
    If (WONo NE '') then
        If RowExists('WO_LOG', WONo) then
            Open 'DICT.WO_MAT' to hDict then
                Query     = 'WO_NO':@VM:WONo:@FM
                Query     := 'CURR_STATUS':@VM:'#VOID':@FM
                WOMatKeys = ''
                Flag      =  ''
                ErrCode   = ''
                Btree.Extract(Query, 'WO_MAT', hDict, WOMatKeys, 'E', Flag)
                If Not(Get_Status(ErrCode)) then
                    If WOMatKeys NE '' then
                        Response = SRP_Array('SortRows', WOMatKeys, 'AR2', 'LIST', @VM, '*')
                    end
                end else
                    ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract. Error code: ':ErrCode
                end
            end
        end else
            ErrorMsg = 'Error in ':Service:' service. WO_LOG ':WONo:' does not exist.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WONo passed into service.'
    end
    
    If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
    
end service


Service VerifyWOLogWOMatKeyColumn(WOMatKey)
    
    LogPath               = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_MAT'
    LogDate               = Oconv(Date(), 'D4/')
    LogTime               = Oconv(Time(), 'MTS')
    LogFileName           = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WO_MAT WO_LOG{WO_MAT_KEY} Log.csv'
    Headers               = 'Logging DTM':@FM:'WOMatKey':@FM:'Result'
    objVerifyWOMatKeysLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$)
    LoggingDTM            = LogDate : ' ' : LogTime   ; // Logging DTM    
    
    LogData    = ''
    LogData<1> = LoggingDtm
    LogData<2> = WOMatKey
    LogData<3> = 'Begin ':Service
    Logging_Services('AppendLog', objVerifyWOMatKeysLog, LogData, @RM, @FM)    
    
    ErrorMsg = ''
    If WOMatKey NE '' then
        If RowExists('WO_MAT', WOMatKey) then
            WONo = Field(WOMatKey, '*', 1, 1)
            If WONo NE '' then
                If RowExists('WO_LOG', WONo) then
                    WOLogWOMatKeys = Database_Services('ReadDataColumn', 'WO_LOG', WONo, WO_LOG_WO_MAT_KEY$, True$, 0)
                    If Error_Services('NoError') then 
                        Locate WOMatKey in WOLogWOMatKeys using @VM setting vPos then
                            LogData<3> = 'WOMatKey found in WO_LOG record. Nothing to update.'
                            Logging_Services('AppendLog', objVerifyWOMatKeysLog, LogData, @RM, @FM)                            
                        end else
                            LogData<3>            = 'WOMatKey not found in WO_LOG record. Posting transaction to update column.'
                            Logging_Services('AppendLog', objVerifyWOMatKeysLog, LogData, @RM, @FM)                                
                            WOLogWOMatKeys<0, -1> = WOMatKey
                            WOLogWOMatKeys        = SRP_Array('SortRows', WOLogWOMatKeys, 'AR2', 'LIST', @VM, '*')
                            Transaction_Services('PostWriteFieldTransaction', 'WO_LOG', WONo, WO_LOG_WO_MAT_KEY$, WOLogWOMatKeys)
                        end
                    end else
                        ErrorMsg = 'Error in ':Service:' service. ':Error_Services('GetMessage')
                    end
                end else
                    ErrorMsg = 'Error in ':Service:' service. WO_LOG ':WONo:' does not exist.'
                end
            end else
                ErrorMsg = 'Error in ':Service:' service. WO_NO is null.'
            end
        end else
            ErrorMsg = 'Error in ':Service:' service. WO_MAT ':WOMatKey:' does not exist.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WOMatKey passed into service.'
    end
    
    LogData<3> = 'End ':Service
    Logging_Services('AppendLog', objVerifyWOMatKeysLog, LogData, @RM, @FM)   
    
    If ErrorMsg NE '' then
        LogData<3> = ErrorMsg
        Logging_Services('AppendLog', objVerifyWOMatKeysLog, LogData, @RM, @FM)
    end
    
    If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
    
end service

