Compile function TEST_RUN_Services(@Service, @Params)
#pragma precomp SRP_PreCompiler
$insert LOGICAL
$Insert APP_INSERTS
$Insert TEST_WAFER_PROD_EQUATES
$Insert TEST_WAFER_TYPES_DISPO_OPTIONS_EQUATES
$Insert TEST_RUN_EQUATES
$Insert TEST_RUN_WAFER_EQUATES
$Insert TEST_RUN_OBJ_EQUATES
$Insert LOT_EQUATES
$Insert LOT_OPERATION_EQUATES

Declare function Nextkey, Error_Services, Environment_Services, OConv, Logging_Services, SRP_Hashtable, Lot_Services
Declare function SRP_Datetime, Database_Services, Test_Run_Services, File_Services, Status, delete, Insert, Datetime, SRP_Json
Declare subroutine Database_Services, Btree.Extract, Error_Services, Logging_Services, Rlist, Test_Run_Services, Lot_Services, SRP_Json

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

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

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

GoToService

Return Response or ""

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


//Test Wafer Product Methods - related to TEST_WAFER_PROD table

/*
Create New Test Wafer Product
Creates a new entry in the TEST_WAFER_PROD table.
*/
Service CreateNewTestWaferProduct(ProductName)
    If ProductName NE '' then
        //Check for existing
        table = 'TEST_WAFER_PROD'
        Open "DICT ":table To @DICT Else
            Error_Services('Add', 'Error opening Test wafer product table')
            Return
        End
        Column          = "PART_NAME"
        Value           = ProductName
        search_criteria = Column:@VM:Value:@FM
        keylist         = ""
        option          = ""
        flag            = ""
        Btree.Extract(search_criteria, table, @DICT, keylist, option, flag)
        IF keylist EQ '' then
            NewTestWaferProdRec                             = ''
            NewTestWaferProdRec<TEST_WAFER_PROD_PART_NAME$> = ProductName
            NewTestWaferProdKey                             = Nextkey('TEST_WAFER_PROD')
            Database_Services('WriteDataRow', table, NewTestWaferProdKey, NewTestWaferProdRec)
            If Error_Services('NoError') then
                LogData       = ''
                LogData<1, 1> = LoggingDTM
                LogData<1, 2> = @User4
                LogData<1, 3> = 'Successfully created new product type with ID of ' : NewTestWaferProdKey
                Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
                Response      = NewTestWaferProdKey
            end else
                //Todo Add Logging for failure
                LogData       = ''
                
                LogData<1, 1> = LoggingDTM
                LogData<1, 2> = @User4
                LogData<1, 3> = 'Error Creating new test wafer product. ' : Error_Services('GetMessage')
                Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
                Response      = ''
            end
        end else
            
            LogData       = ''
            LogData<1, 1> = LoggingDTM
            LogData<1, 2> = @User4
            LogData<1, 3> = 'Error Creating new test wafer product. Product already exists!'
            Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
            Error_Services('Add', 'Product already exists!')
            Response      = ''
        end
    end else
        //Todo Add logging for failure
        LogData       = ''
        LogData<1, 1> = LoggingDTM
        LogData<1, 2> = @User4
        LogData<1, 3> = 'Product name was missing'
        Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
        Error_Services('Add', 'Product name was missing')
        Response      = ''
    end
end service

Service DisableTWProd(TWProdKey)
    If TWProdKey NE '' then
        TWProdRec                              = Database_Services('ReadDataRow', 'TEST_WAFER_PROD', TWProdKey)
        TWProdRec<TEST_WAFER_PROD_SORT_ORDER$> = 0
        Database_Services('WriteDataRow', 'TEST_WAFER_PROD', TWProdKey, TWProdRec)
    end else
        Error_Services('Add', 'Error in TEST_RUN_SERVICES -> DisableTWProd: No TWProdKeySupplied')
    end
end service

/*
Add disposition option to a test wafer product
Creates a new disposition entry in the TEST_WAFER_TYPES_DISPO_OPTION table, related to a TEST_WAFER_PROD record
*/
Service AddTestWaferProductDispo(TestWaferProdID, DispoName)
    If TestWaferProdID NE '' then
        IF DispoName NE '' then
            MatchingIDs     = False$
            CurrentDispoIDs = XLATE('TEST_WAFER_PROD', TestWaferProdID, TEST_WAFER_PROD_WAFER_DISPO_IDS$, 'X')
            For i = 1 to DCount(CurrentDispoIDs, @VM)
                DispoID          = CurrentDispoIDs<1, i>
                DispoDescription = Xlate('TEST_WAFER_TYPES_DISPO_OPTIONS', DispoID, TEST_WAFER_TYPES_DISPO_OPTIONS_DISPO_DESCRIPTION$, 'X')
                if DispoName EQ DispoDescription then MatchingIDs = true$
            Until MatchingIDs    
            Next i
            if NOT(MatchingIDs) then
                NewTestWaferProdDispoRec                                                     = ''
                NewTestWaferProdDispoRec<TEST_WAFER_TYPES_DISPO_OPTIONS_TEST_WAFER_PROD_ID$> = TestWaferProdID
                NewTestWaferProdDispoRec<TEST_WAFER_TYPES_DISPO_OPTIONS_DISPO_DESCRIPTION$>  = DispoName
                NewTestWaferProdDispoKey                                                     = Nextkey('TEST_WAFER_TYPES_DISPO_OPTIONS')
                Database_Services('WriteDataRow', 'TEST_WAFER_TYPES_DISPO_OPTIONS', NewTestWaferProdDispoKey, NewTestWaferProdDispoRec)
                If Error_Services('NoError') then
                    LogData       = ''
                    LogData<1, 1> = LoggingDTM
                    LogData<1, 2> = @User4
                    LogData<1, 3> = 'Dispo added to ' : TestWaferProdID : '. The dispo key is ' : NewTestWaferProdDispoKey
                    Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
                end else
                    LogData       = ''
                    LogData<1, 1> = LoggingDTM
                    LogData<1, 2> = @User4
                    LogData<1, 3> = 'Error adding dispo to TW Prod, ' : Error_Services('GetMessage')
                    Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
                end
            end else
                LogData       = ''
                LogData<1, 1> = LoggingDTM
                LogData<1, 2> = @User4
                LogData<1, 3> = 'Error adding dispo to TW Prod. dispo option already existed.'
                Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
                Error_Services('Add', 'Error adding dispo to TW Prod. dispo option already existed.')
            end
        end else
            LogData       = ''
            LogData<1, 1> = LoggingDTM
            LogData<1, 2> = @User4
            LogData<1, 3> = 'Error adding dispo to TW Prod. The dispo name was missing'
            Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
        end
    end else
        LogData       = ''
        LogData<1, 1> = LoggingDTM
        LogData<1, 2> = @User4
        LogData<1, 3> = 'Error adding dispo to TW Prod. The product name was missing'
        Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
    end
end service

Service DeleteTestWaferProductDispo(DispoID)
    If DispoID NE '' then
        If RowExists('TEST_WAFER_TYPES_DISPO_OPTIONS', DispoID) then
            Database_Services('DeleteDataRow', 'TEST_WAFER_TYPES_DISPO_OPTIONS', DispoID, True$, False$)
        end else
            errorMessage  = 'Error deleting dispo to TW Prod. The dispo id was not found.'
            LogData       = ''
            LogData<1, 1> = LoggingDTM
            LogData<1, 2> = @User4
            LogData<1, 3> = errorMessage
            Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
            Error_Services('Add', errorMessage)
        end
    end else
        errorMessage  = 'Error deleting dispo to TW Prod. The dispo id was missing'
        LogData       = ''
        LogData<1, 1> = LoggingDTM
        LogData<1, 2> = @User4
        LogData<1, 3> = errorMessage
        Logging_Services('AppendLog', objLogTWP, LogData, @FM, @VM)
        Error_Services('Add', errorMessage)
    end
end service

Service GetAllTWProdKeysUnformatted()
    keylist  = ''
    RList("SELECT TEST_WAFER_PROD WITH SORT_ORDER NE '' BY SORT_ORDER", 5, '', '', '')
    Done     = False$
    Loop
        Readnext TWProdKey else Done = True$
    Until Done
        keylist<-1> = TWProdKey
    Repeat
    
    Response = keylist
end service

Service GetAllTWProdKeys(ShowSorted)
    keylist  = ''
    ProdList = ''
    If ShowSorted then
        RList("SELECT TEST_WAFER_PROD WITH SORT_ORDER NE 0 AND WITH SORT_ORDER NE '' BY SORT_ORDER", 5, '', '', '')
    end else
        RList("SELECT TEST_WAFER_PROD BY SORT_ORDER", 5, '', '', '')
    end
    
    Done     = False$
    Loop
        Readnext TWProdKey else Done = True$
    Until Done
        keylist<1, -1> = TWProdKey
    Repeat
    for each ProdKey in keylist using @VM setting pPos
        ProdName = Xlate('TEST_WAFER_PROD', ProdKey, TEST_WAFER_PROD_PART_NAME$, 'X')
        if ProdName NE '' then
            ProdList<1, pPos> = ProdKey
            ProdList<2, pPos> = ProdName
        end
    Next ProdKey
    Response = ProdList
end service

Service UpdateTWProdSortOrder(TWProdKey, NewOrder)
    //First get current sort order
    TWProdRec        = Database_Services('ReadDataRow', 'TEST_WAFER_PROD', TWProdKey)
    OldSortOrder     = TWProdRec<TEST_WAFER_PROD_SORT_ORDER$>
    AllTWProdsSorted = Test_Run_Services('GetAllTWProdKeysUnformatted')
    //Get rid of all zero value sort orders
    i                = 1
    LOOP
    UNTIL AllTWProdsSorted<i> = ''
        currSortOrder = Xlate('TEST_WAFER_PROD', AllTWProdsSorted<i>, TEST_WAFER_PROD_SORT_ORDER$, 'X')
        If currSortOrder EQ 0 then
            //Remove it from the list of TWProds with Sorting enabled. The zero's will screw up the next part.
            AllTWProdsSorted = delete(AllTWProdsSorted, i, 0, 0)
        end
        i = i + 1
    REPEAT
    If NewOrder GT 0 then
        AllTWProdsSorted = Insert(AllTWProdsSorted, NewOrder, 0, 0, TWProdKey)
        //Locate the old order and remove it
        i                = 1
        LOOP
        UNTIL AllTWProdsSorted<i> = ''
            If i NE NewOrder AND AllTWProdsSorted<i> EQ TWProdKey then
                //Remove it from the list of TWProds with Sorting enabled. The zero's will screw up the next part.
                AllTWProdsSorted = delete(AllTWProdsSorted, i, 0, 0)
            end
            i = i + 1
        REPEAT
    end else
        //Disabling
        Locate TWProdKey in AllTWProdsSorted using @FM setting tPos then
            AllTWProdsSorted                              = delete(AllTWProdsSorted, tPos, 0, 0)
        end
        TWProdRecToWrite                              = Database_Services('ReadDataRow', 'TEST_WAFER_PROD', TWProdKey)
        TWProdRecToWrite<TEST_WAFER_PROD_SORT_ORDER$> = 0
        Database_Services('WriteDataRow', 'TEST_WAFER_PROD', TWProdKey, TWProdRecToWrite, 1, 0, 1)
    end
    //Rewrite the entire sort order for all prods
    For each TWProd in AllTWProdsSorted using @FM setting SortOrder
        TWProdRecToWrite                              = Database_Services('ReadDataRow', 'TEST_WAFER_PROD', TWProd)
        TWProdRecToWrite<TEST_WAFER_PROD_SORT_ORDER$> = SortOrder
        Database_Services('WriteDataRow', 'TEST_WAFER_PROD', TWProd, TWProdRecToWrite, 1, 0, 1)
    Next TWProd
end service

Service GetAllTestRunTypes()
    keylist = ''
    rtList  = ''
    RList('SELECT TEST_RUN_TYPE BY RUN_TYPE', 5, '', '', '')
    Done    = False$
    Loop
        Readnext RunTypeKey else Done = True$
    Until Done
        keylist<1, -1> = RunTypeKey
    Repeat
    for each RTKey in keylist using @VM setting rPos
        RunTypeName = Xlate('TEST_RUN_TYPE', RTKey, TEST_RUN_TYPE_RUN_TYPE$, 'X')
        if RunTypeName NE '' then
            rtList<1, rPos> = RTKey
            rtList<2, rPos> = RunTypeName
        end
    Next ProdKey
    Response = rtList
end service

Service GetTestWaferLots(ShowOnlyOpenLots)
    ErrorMessage     = ''
    TestWaferLotKeys = ''
    SearchString     = 'TYPE':@VM:'TW':@FM
    If ShowOnlyOpenLots then
        SearchString := 'OPEN':@VM:True$:@FM
    end
    Open 'DICT.LOT' to @DICT then
        Btree.Extract(SearchString, 'LOT', @DICT, TestWaferLotKeys, '', '')
    end else
        ErrorMessage = 'Error opening LOT dictionary.'
    end
    If ErrorMessage NE '' then
        Error_Services('Add', ErrorMessage)
    end
    Response = TestWaferLotKeys
end service

Service CreateTestRunRecord(RunTypeID, EqpType, EqpID, PSNo, RDSNo, UserID, TWLotIds, TWLotQtys)
    
    TWRunKey     = ''
    Response     = ''
    ErrorMessage = ''
    If RunTypeID NE '' AND EqpType NE '' AND EqpID NE '' AND UserID NE '' then
        RunDTM                             = SRP_Datetime('Now')
        TWRunRec                           = ''
        TWRunRec<TEST_RUN_RUN_DTM$>        = RunDTM
        TWRunRec<TEST_RUN_RUN_TYPE_ID$>    = RunTypeID
        TWRunRec<TEST_RUN_EQUIPMENT_ID$>   = EqpID
        TWRunRec<TEST_RUN_EQUIPMENT_TYPE$> = EqpType
        TWRunRec<TEST_RUN_PROD_SPEC_ID$>   = PSNo
        TWRunRec<TEST_RUN_LSL_USER_ID$>    = UserID
        TWRunRec<TEST_RUN_RDS_ID$>         = RDSNo
        TWRunKey                           = nextkey('TEST_RUN')
        Database_Services('WriteDataRow', 'TEST_RUN', TWRunKey, TWRunRec)
        If Error_Services('NoError') then
            If RowExists('TEST_RUN', TWRunKey) then
                LogData       = ''
                LogData<1, 1> = LoggingDTM
                LogData<1, 2> = UserID
                LogData<1, 3> = 'Successfully created new TEST_RUN record with ID of ' : TWRunKey
                Logging_Services('AppendLog', objLogTR, LogData, @FM, @VM)
                //Now create the test wafer usages
                Success       = False$
                If TWLotIds NE ''  then
                    //Supports new logging methods.
                    for each TWLotId in TWLotIds using @VM setting twlPos
                        LotRec                 = Database_Services('ReadDataRow', 'LOT', TWLotId, True$, 0, False$)
                        IsThisLotOnHold        = LotRec<LOT_HOLD$>
                        IsThisLotOpen          = LotRec<LOT_OPEN$>
                        IsThisLotATWLot        = LotRec<LOT_TYPE$> EQ 'TW'
                        ThisLotCurrQty         = LotRec<LOT_WAFER_QTY$>
                        ThisLotPartId          = LotRec<LOT_PROD_ID$>
                        
                        //
                        ThisUsageQty           = TWLotQtys<1, twlPos>
                        
                        If IsThisLotOpen then
                            If Not(IsThisLotOnHold) then
                                If IsThisLotATWLot then
                                    InAtTWInUse = False$
                                    Loop
                                        LotMovedIn             = Lot_Services('IsLotMovedIn', TWLotId)
                                        ThisLotCurrOperationId = Lot_Services('GetLotCurrOperationId', TWLotId)
                                        ThisLotCurrOperation   = Database_Services('ReadDataColumn', 'LOT_OPERATION', ThisLotCurrOperationId, LOT_OPERATION_OPERATION_ID$, True$, 0, False$)
                                        Begin Case
                                            Case ThisLotCurrOperation EQ 'TW_IN_USE'
                                                
                                                    If Not(LotMovedIn) then
                                                        Lot_Services('CreateLotEvent', TWLotId, 'TW', Datetime(), 'MOVE_IN', 'Move into TW_IN_USE', '', 0, 0, '', UserID) 
                                                        If Error_Services('HasError') then
                                                            ErrorMessage = Error_Services('GetMessage')
                                                        end
                                                    end else
                                                        InAtTWInUse = True$
                                                    end
                                                
                                            Case ThisLotCurrOperation EQ 'TW_READY_TO_USE'
                                                
                                                If Not(LotMovedIn) then
                                                   Lot_Services('CreateLotEvent', TWLotId, 'TW', Datetime(), 'MOVE_IN', 'Move into TW_READY_TO_USE', '', 0, 0, '', UserID)
                                                end else
                                                   Lot_Services('CreateLotEvent', TWLotId, 'TW', Datetime(), 'MOVE_OUT', 'Move out of TW_READY_TO_USE', '', 0, 0, '', UserID) 
                                                end
                                                If Error_Services('HasError') then
                                                    ErrorMessage = Error_Services('GetMessage')
                                                end
                                            Case Otherwise$
                                                ErrorMessage = 'Error: Lot ':TWLotId:' is currently at  ' : ThisLotCurrOperation : '. It cannot be used at this time.'
                                        End Case
                                    Until ErrorMessage NE '' Or InAtTWInUse
                                    Repeat
                                    If InAtTWInUse then
                                        if Num(ThisUsageQty) then
                                            If ThisUsageQty GT 0 then
                                               //Now check that the usage QTY can be consumed from the TW Lot
                                                ThisLotCurrQty = Database_Services('ReadDataColumn', 'LOT', TWLotId, LOT_WAFER_QTY$, True$, 0, False$)
                                                If ThisUsageQty LE ThisLotCurrQty then
                                                    Abort   = false$
                                                    for i = 1 to ThisUsageQty
                                                        Test_Run_Services('CreateTestRunWaferRecord',TWRunKey, ThisLotPartId, RunTypeID, TWLotId, UserID)
                                                        If Error_Services('HasError') then
                                                            ErrorMessage = Error_Services('GetMessage')
                                                        end
                                                    until ErrorMessage NE ''
                                                    Next i
                                                    If ErrorMessage EQ '' then
                                                        Lot_Services('CreateLotEvent', TWLotId, 'TW', Datetime(), 'REDUCE_WAFER_QTY', ThisUsageQty : ' wafers consumed from lot.', EqpID, ThisUsageQty, 0, '', UserID) 
                                                    end
                                                end else
                                                    ErrorMessage = 'Error in Create Test Run Record routine, ' : TWLotId : ' does not have enough wafers.'
                                                end
                                            end
                                        end else
                                            ErrorMessage = 'Error in Create Test Run Record routine, Invalid qty for lot ' : TWLotId : ' passed to routine.'
                                        end
                                    end
                                    
                                end else
                                    //Lot is not classified as a test wafer lot.
                                end
                            end else
                                //Lot is on hold
                            end
                        end else
                            //Lot is not open
                        end
                    until ErrorMessage NE ''
                    Next TWLotId
                    If ErrorMessage EQ '' then
                        //commit everything
                    end else
                        //commit nothing, there was an error.
                    end
                end else
                    //Supports legacy TW logging
                    Response = TWRunKey
                end
            end else
                ErrorMessage = 'Error in Create Test Run Record routine, Generated Test Run Key did not exist in TEST Run table.'
            end
            
            Response      = TWRunKey
        end else
            ErrorMessage = Error_Services('GetMessage')
        end
    end else
        If RunTypeID EQ '' then
            ErrorMessage := 'Run Type ID Missing. '
        end
        If EqpType EQ '' then
            ErrorMessage := 'Equipment Type ID Missing. '
        end
        If EqpID EQ '' then
            ErrorMessage := 'Equipment ID Missing. '
        end
        If UserID EQ '' then
            ErrorMessage := 'User ID Missing. '
        end
    end
    If ErrorMessage NE '' then
        LogData       = ''
        LogData<1, 1> = LoggingDTM
        LogData<1, 2> = @User4
        LogData<1, 3> = 'Error writing TEST_RUN Record ' : TWRunKey : ': ' : ErrorMessage 
        Logging_Services('AppendLog', objLogTR, LogData, @FM, @VM)
        Error_Services('Add', ErrorMessage)
        Response      = ''
    end
end service

Service CreateTestRunWaferRecord(TestRunID, TWPartID, TWUsageTypeID, SourceLotId, Username)
    ErrorMessage = ''
    If TestRunID NE '' AND TWPartID NE '' then
        If RowExists('TEST_RUN', TestRunID) then
                //Legacy Code: Pre LOT usage
                TRWaferRec                                     = ''
                TRWaferRec<TEST_RUN_WAFER_TEST_RUN_ID$>        = TestRunID
                TRWaferRec<TEST_RUN_WAFER_TEST_WAFER_PROD_ID$> = TWPartID
                TRWaferRec<TEST_RUN_WAFER_TEST_USAGE_TYPE_ID$> = TWUsageTypeID
                TRWaferRec<TEST_RUN_WAFER_SOURCE_LOT_ID$>      = SourceLotID
                TRWaferKey                                     = Nextkey('TEST_RUN_WAFER')
                Database_Services('WriteDataRow', 'TEST_RUN_WAFER', TRWaferKey, TRWaferRec)
                If Error_Services('NoError') AND RowExists('TEST_RUN_WAFER', TRWaferKey) then
                    LogData       = ''
                    LogData<1, 1> = LoggingDTM
                    LogData<1, 2> = @User4
                    LogData<1, 3> = 'Successfully wrote ' : TRWaferKey : ' to the TEST_RUN_WAFER table.'
                    Logging_Services('AppendLog', objLogTR, LogData, @FM, @VM)
                    //Increment Usage in TEST_WAFER_PROD Record
                    If ErrorMessage = '' then
                        Test_Run_Services('IncrementTWProdUsage', TWPartID)
                        Response      = TRWaferKey
                    end
                end else
                    ErrorMessage := 'Error writing TEST_RUN_WAFER record with key of ' : TRWaferKey '. '
                end
        end else
            ErrorMessage := 'Unable to find parent TEST_RUN record. '
        end
    end else
        If TestRunID EQ '' then
            ErrorMessage := 'TestRunID parameter was not passed to CreateTestRunWaferRecord method. '
        end
        If TWPartID EQ '' then
            ErrorMessage := 'TWPartID parameter was not passed to CreateTestRunWaferRecord method. '
        end
    end
    If ErrorMessage NE ''  then
        LogData       = ''
        LogData<1, 1> = LoggingDTM
        LogData<1, 2> = @User4
        LogData<1, 3> = 'Error Writing to the TEST_RUN_WAFER table. ' : ErrorMessage
        Logging_Services('AppendLog', objLogTR, LogData, @FM, @VM)
        Error_Services('Add', 'Error creating new test run record: ' : ErrorMessage)
    end
end service

Service UseTWFromLot(LotId, UsageQty, Username)
    ErrorMessage = ''
    If RowExists('LOT', LotId) then
        Lot_Services('CreateLotEvent', LotId, 'TW', Datetime(), 'REDUCE_WAFER_QTY', 'Consumed test wafer.', '', UsageQty, 0, '', Username)
    end else
        ErrorMessage = 'Error logging wafer consumption from Lot # ' : LotId : '. Lot does not exist in LOT table.'
    end
    If ErrorMessage EQ '' then
        
    end else
        //Log Error
    end
end service

Service GetTestRunById(TestRunID)
    If TestRunID NE '' then
        If RowExists('TEST_RUN', TestRunID) then
            TRRec    = Database_Services('ReadDataRow', 'TEST_RUN', TestRunID)
            Response = TRRec
        end else
            Error_Services('Add', 'Test Run ID does not exist in TEST_RUN table')
        end
    end else
        Error_Services('Add', 'Test Run ID parameter was not passed to routine.')
    end
end service

Service IncrementTWProdUsage(TWProdKey)
    If TWProdKey NE '' then
        TWProdRec                         = Database_Services('ReadDataRow', 'TEST_WAFER_PROD', TWProdKey)
        TWProdRec<TEST_WAFER_PROD_USAGE$> = TWProdRec<TEST_WAFER_PROD_USAGE$> + 1
        Database_Services('WriteDataRow', 'TEST_WAFER_PROD', TWProdKey, TWProdRec)
    end
end service

Service GetTestRunObj(TestRunID)
    TestRunObj                             = ''
    TestRunRec                             = Test_Run_Services('GetTestRunById', TestRunID)
    //Start getting translated values for object
    TestRunObj<TEST_RUN_OBJ_TEST_RUN_ID$>  = TestRunID
    TestRunObj<TEST_RUN_OBJ_RUN_DTM$>      = OConv(TestRunRec<TEST_RUN_RUN_DTM$>, 'DT')
    TestRunObj<TEST_RUN_OBJ_RUN_TYPE$>     = Xlate('TEST_RUN_TYPE', TestRunRec<TEST_RUN_RUN_TYPE_ID$>, TEST_RUN_TYPE_RUN_TYPE$, 'X')
    TestRunObj<TEST_RUN_OBJ_EQUIPMENT_ID$> = TestRunRec<TEST_RUN_EQUIPMENT_ID$>
    EqpType                                = TestRunRec<TEST_RUN_EQUIPMENT_TYPE$>
    Begin Case
        Case EqpType EQ 'R'
            TestRunObj<TEST_RUN_OBJ_EQUIPMENT_TYPE$> = 'Reactor'
        Case EqpType EQ 'T'
            TestRunObj<TEST_RUN_OBJ_EQUIPMENT_TYPE$> = 'Non-Reactor'
    End Case
    TestRunObj<TEST_RUN_OBJ_PROD_SPEC_ID$> = TestRunRec<TEST_RUN_PROD_SPEC_ID$>
    TestRunObj<TEST_RUN_OBJ_LSL_USER_ID$>  = TestRunRec<TEST_RUN_LSL_USER_ID$>
    TestRunObj<TEST_RUN_OBJ_RDS_ID$>       = TestRunRec<TEST_RUN_RDS_ID$>
    
    TWKeys                                = TestRunRec<TEST_RUN_TEST_RUN_WAFER_IDS$>
    TWUsageProds                       = ''
    TWUsageQtys                        = ''
    for each TWKey in TWKeys using @VM setting tPos
        TRWRec            = Test_Run_Services('GetTestRunWaferByID', TWKey)
        TestWaferProdName = XLATE('TEST_WAFER_PROD', TRWRec<TEST_RUN_WAFER_TEST_WAFER_PROD_ID$>, TEST_WAFER_PROD_PART_NAME$, 'X')
        Locate TestWaferProdName in TWUsageProds setting iPos then
            TWUsageProds<1,iPos> = TestWaferProdName
            TWUsageQtys<1,iPos>  = TWUsageQtys<1,iPos> + 1
        end else
            TWUsageProds<1,-1> = TestWaferProdName
            TWUsageQtys<1,-1>  = 1
        end
    Next TWKey
    TestRunObj<TEST_RUN_OBJ_TEST_RUN_WAFER_PRODS$>      = TWUsageProds
    TestRunObj<TEST_RUN_OBJ_TEST_RUN_WAFER_PRODS_QTYS$> = TWUsageQtys
    
    Response = TestRunObj
end service

Service GetTestWaferUsageByDateSpan(StartDtm, StopDtm)
    
    TestWaferData = ''
    if StopDTM EQ '' then
        StopDTM = SRP_Datetime('Now')
    end
    If StartDTM EQ '' then
        StartDTM = SRP_Datetime('AddDays', StopDtm, -30)
    end
    //Get a list of Test Run keys
    TestRunKeys = Test_Run_Services('GetTestRunKeysByDateSpan', StartDtm, StopDtm)
    
    For each TestRunKey in TestRunKeys using @VM setting tPos
        //Get all Product usages and their quantities
        TestRunRec  = Database_Services('ReadDataRow', 'TEST_RUN', TestRunKey)
        TWUsageKeys = TestRunRec<TEST_RUN_TEST_RUN_WAFER_IDS$>
        TWUsageData = ''
        for each TWUsageKey in TWUsageKeys using @VM setting twPos
            TWProdTypeKey = Xlate('TEST_RUN_WAFER', TWUsageKey, TEST_RUN_WAFER_TEST_WAFER_PROD_ID$, 'X')
            TWProdType    = Xlate('TEST_WAFER_PROD', TWProdTypeKey, TEST_WAFER_PROD_PART_NAME$, 'X')
            Locate TWProdType in TWUsageData<1>  using @VM setting twuPos then
                TWUsageData<2, twuPos> = TWUsageData<2, twuPos> + 1
            end else
                TWUsageData<1, -1> = TWProdType
                TWUsageData<2, -1> = 1
            end
            
            
        Next TWUsageKey
        
        For each TWUsage in TWUsageData<1> using @VM setting aPos
            TWLine                                             = ''
            TWLine<1, TEST_RUN_OBJ_TEST_RUN_ID$>               = TestRunKey
            TWLine<1, TEST_RUN_OBJ_RUN_DTM$>                   = OConv(TestRunRec<TEST_RUN_RUN_DTM$>, 'DT')
            TWLine<1, TEST_RUN_OBJ_RUN_TYPE$>                  = XLATE('TEST_RUN_TYPE', TestRunRec<TEST_RUN_RUN_TYPE_ID$>, 'RUN_TYPE', 'X')
            TWLine<1, TEST_RUN_OBJ_EQUIPMENT_ID$>              = TestRunRec<TEST_RUN_EQUIPMENT_ID$>
            TWLine<1, TEST_RUN_OBJ_EQUIPMENT_TYPE$>            = TestRunRec<TEST_RUN_EQUIPMENT_TYPE$>
            TWLine<1, TEST_RUN_OBJ_PROD_SPEC_ID$>              = TestRunRec<TEST_RUN_PROD_SPEC_ID$>
            TWLine<1, TEST_RUN_OBJ_LSL_USER_ID$>               = TestRunRec<TEST_RUN_LSL_USER_ID$>
            TWLine<1, TEST_RUN_OBJ_RDS_ID$>                    = TestRunRec<TEST_RUN_RDS_ID$>
            TWLine<1, TEST_RUN_OBJ_TEST_RUN_WAFER_PRODS$>      = TWUsage
            TWLine<1, TEST_RUN_OBJ_TEST_RUN_WAFER_PRODS_QTYS$> = TWUsageData<2, aPos>
            TestWaferData<-1>                                  = TWLine
        Next TWUsage
    Next TestRunKey
    
    Response = TestWaferData
end service

Service GetTestRunKeysByDateSpan(StartDtm, StopDtm)
    Begin Case
        Case StartDTM EQ '' AND StopDTM EQ ''
            //Set search date for last 24 hour period
            StopDTM  = SRP_Datetime('Now')
            StartDTM = SRP_Datetime('AddHours', StopDTM, -24)
        Case StartDTM EQ '' AND StopDTM NE ''
            //Set search start date 24 hours prior to stopDTM
            StartDTM = SRP_Datetime('AddHours', StopDTM, -24)
        Case StartDTM NE '' AND StopDTM EQ ''
            //Set search start date to current dtm
            StopDTM = SRP_Datetime('Now')
    End Case
    
    table = "TEST_RUN"
    Open "DICT ":table To @DICT Else
        Error_Services('Add', 'Error opening TEST_RUN dictionary')
    End
    If Error_Services('NoError') then
        srch_strng = "RUN_DTM":@VM:StartDTM:'~':StopDTM:@FM
        keylist         = ""
        option          = ""
        flag            = ""
        Btree.Extract(srch_strng, table, @DICT, keylist, option, flag)
        Response = keylist
    end
    
    
    
end service

Service GetTestRunKeysByEqp(EquipType, EquipID)
    
end service

Service GetTestRunKeysByEqpType(EqpType)
    
end service

Service GetTestRunKeysByPSN(PSNo)
    
end service

Service GetTestRunKeysByRDS(RDSNo)
    
end service

Service GetTestRunWaferByID(TRWaferID)
    If TRWaferID NE '' then
        If RowExists('TEST_RUN_WAFER', TRWaferID) then
            Response = Database_Services('ReadDataRow', 'TEST_RUN_WAFER', TRWaferID)
            If Error_Services('HasError') then
                Response = ''
                Error_Services('Add', 'Error reading TEST_RUN_WAFER record with ID ' : TRWaferID)
            end
        end else
            Error_Services('Add', 'No TEST_RUN_WAFER record found that matches key value.')
        end
    end else
        Error_Services('Add', 'TRWaferID was null')
    end
end service

Service GetTestRunWaferKeysByProdID(ProdID)
    
end service

Service GenerateTWCSVReport(StartDTM, StopDTM, SavePath)
    If SavePath NE '' then
        CSVData  = 'ID' : @VM : 'Run Time' : @VM : 'Test Run Type' : @VM : 'Equipment ID' : @VM : 'Equipment Type' : @VM : 'PSN' : @VM : 'User' : @VM : 'RDS' : @VM : 'Test Wafer Type' : @VM : 'Wfr Qty' : @FM
        CSVData := Test_Run_Services('GetTestWaferUsageByDateSpan', StartDTM, StopDTM)
        swap @VM with ',' in CSVData
        swap @FM with CRLF$ in CSVData
        If Not(File_Services('CheckFileExtension', SavePath, 'csv')) then
            SavePath = SavePath : '.csv'
        end
        OSWrite CSVData To SavePath
        WriteFailure = Status()
        If WriteFailure then
            Begin Case
                Case WriteFailure EQ 1
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, Bad OS filename.')
                Case WriteFailure EQ 2
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, Access denied by operating system.')
                Case WriteFailure EQ 3
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, Disk or directory full.')
                Case WriteFailure EQ 4
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, File does not exist.')
                Case WriteFailure EQ 5
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, Unknown error.')
                Case WriteFailure EQ 6
                    Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, Attempt to write to a read-only file.')
            End Case
        end
    end else
        Error_Services('Add', 'Error in TEST_RUN_SERVICES -> GenerateTWCSVReport, No SavePath provided.')
    end
    
end service








