Compile function Lot_Operation_Services(@Service, @Params)
#pragma precomp SRP_PreCompiler

Declare function Lot_Services, Database_Services, Error_Services, Srp_Sort_Array, Lot_Operation_Services
Declare function RTI_CreateGUID, MemberOf, SRP_JSON, Operation_Services, Datetime, Met_Test_Services, PSN_Services
Declare function Date_Services, SRP_Stopwatch
Declare subroutine Database_Services, Error_Services, SRP_JSON, Lot_Services, Lot_Event_Services, Lot_Operation_Services, SRP_Stopwatch

$insert LOGICAL
$insert LOT_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert OPERATION_EQUATES
$Insert MET_TEST_EQUATES
$Insert WAFER_COUNTER_EQUATES

Options OPERATION_TYPE = 'CLEAN', 'THICK_METROLOGY', 'RES_METROLOGY', 'SURFACE_METROLOGY', 'VISUAL_INSPECTION', 'PACKAGING'

GoToService

Return Response or ""

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

Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
    
    Operation = ''
    ErrorMessage = ''
    If RowExists('LOT', LotId) then
        If RowExists('OPERATION', OperationId) then
        	OperationActive = XLATE('OPERATION', OperationId, OPERATION_ACTIVE$, 'X')
        	If OperationActive then
				If PrescribedSequence AND Num(PrescribedSequence) then
					If Lot_Services('CanUserModifyLot', UserId) then
						LotCurrOperation      = Lot_Services('GetLotCurrOperationId', LotId)
						CurrOperationSequence = Xlate('LOT_OPERATION', LotCurrOperation, LOT_OPERATION_OPERATION_SEQUENCE$, 'X')
						If CurrOperationSequence LT PrescribedSequence then
							//Get Curr Operation Sequence
							Done                     = False$
							LotCurrOperationSequence = Lot_Services('GetLotOperationSequence', LotId)
							for each Operation in LotCurrOperationSequence using @Fm setting OpPos
								ThisOperationRec      = Database_Services('ReadDataRow', 'LOT_OPERATION', Operation)
								ThisOperationSequence = ThisOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>
								If ThisOperationSequence GE PrescribedSequence then
									NewOperationSequence                                = ThisOperationSequence + 1
									ThisOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = NewOperationSequence
									Database_Services('WriteDataRow', 'LOT_OPERATION', Operation, ThisOperationRec)
									If Error_Services('HasError') then
										Done         = True$
										ErrorMessage = Error_Services('GetMessage')
									end
								end
							Until Done
							Next Operation 
							If ErrorMessage EQ '' then
								LotOperationRecID                                  = RTI_CreateGUID()
								If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then
									OperationRec = Database_Services('ReadDataRow', 'OPERATION', OperationId)
									Class = OperationRec<OPERATION_CLASS_ID$>
									Type = OperationRec<OPERATION_TYPE$>
									Rework = OperationRec<OPERATION_REWORK$>
									ThisNewOperationRec = Database_Services('ReadDataRow', 'OPERATION', OperationId)
									LotOperationRec                                    = ''
									LotOperationRec<LOT_OPERATION_LOT_ID$>             = LotId
									LotOperationRec<LOT_OPERATION_OPERATION_ID$>       = OperationId
									LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = PrescribedSequence
									LotOperationRec<LOT_OPERATION_REWORK$> = Rework
									LotOperationRec<LOT_OPERATION_OPERATION_TYPE$> = Type
									LotOperationRec<LOT_OPERATION_OPERATION_CLASS$> = Class
									LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$> = OperationRec<OPERATION_MET_TEST_TYPE_REQUIRED$>
									LotOperationRec<LOT_OPERATION_MET_TEST_REQUIRED$> = OperationRec<OPERATION_MET_TEST_REQUIRED$>
									LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$> = OperationRec<OPERATION_PACKAGING_REQUIRED$>
									LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$> = OperationRec<OPERATION_CLEAN_REQUIRED$>
									LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$> = OperationRec<OPERATION_WAFER_COUNTER_REQUIRED$>
									IsOperationRework = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_REWORK$)
									Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec)
									If Error_Services('NoError') then
										OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
										Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'ADD_LOT_OPERATION', 'Added operation ' : Quote(OperationDesc) : ' to lot.', '', UserId)
									end else
										ErrorMessage = Error_Services('GetMessage')
									end
								end else
									ErrorMessage = 'Lot Operation already existed, cannot overwrite'
								end
							end
						end else
							ErrorMessage = 'Not allowed to add new operations prior to current operation'
						end
					end else
						ErrorMessage = 'User ' : UserId : ' does not have permission to modify lots.'
					end
				end else
					ErrorMessage = 'Invalid operation sequence entered.'
				end
            end else
            	ErrorMessage = 'Operation is inactive. Unable to add.'
            end
        end else
            ErrorMessage = 'Operation ' : OperationId : 'not found in OPERATION table.' 
        end
    end else
        ErrorMessage = 'Lot ' : LotId : ' not found in LOT table.'
    end    
    
    If ErrorMessage EQ '' then
        Response = Operation
    end else
        Error_Services('Add', 'Error in ' : Service : '.' : ErrorMessage)
    end
    
end service

Service RemoveLotOperation(LotOperationId, UserId)
    
    //Todo User permission check
    ErrorMessage = ''
    Success = False$

    If RowExists('LOT_OPERATION', LotOperationId) then
        If Lot_Services('CanUserModifyLot', UserId) then
            LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
            LotId           = LotOperationRec<LOT_OPERATION_LOT_ID$>
            MoveInTime      = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
            MoveOutTime     = LotOperationRec<LOT_OPERATION_DATETIME_OUT$>
            Sequence        = LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>
            OperationId     = LotOperationRec<LOT_OPERATION_OPERATION_ID$>
            OperationClass  = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X')
            If OperationClass NE 'RTF_DEFAULT' AND OperationClass NE 'RTF_DEFAULT_END' then
                If MoveInTime EQ '' AND MoveOutTime EQ '' then
                    LotOperationRec<LOT_OPERATION_LOT_ID$> = '';//Nulling this value out should disassociated the lot operation record from the lot.
                    Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec)
                    If Error_Services('NoError') then
                        Lot_Operation_Services('UpdateLotOperationSequence', LotId, Sequence)
                        If Error_Services('NoError') then
                           Success = True$
                        end else
                           ErrorMessage = Error_Services('GetMessage') 
                        end
                        OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
                        Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REMOVE_LOT_OPERATION', 'Removed operation ' : Quote(OperationDesc) : ' from lot.', '', UserId)
                    end else
                        ErrorMessage = Error_Services('GetMessage')
                    end
                end else
                    ErrorMessage = 'Lot has already started processing on operation ' : OperationId
                end
            end else
                ErrorMessage = 'Unable to remove default operations.'
            end
        end else
            ErrorMessage = 'User ' : UserId : ' does not have permission modify lots.'
        end
    end else
        ErrorMessage = 'Lot Operation record not found'
    end
    
    If ErrorMessage NE '' then
        Error_Services('Add', ErrorMessage)
    end
    
    Response = Success
    
end service

Service UpdateLotOperationSequence(LotId, StartSequence)
    
    ErrorMessage = ''
    If StartSequence EQ '' then
        StartSequence = 1
    end
    
    If RowExists('LOT', LotId) then
        LotOperationSequence = Lot_Services('GetLotOperationSequence', LotId)
        Offset = 0
        for each LotOperationId in LotOperationSequence using @FM setting SeqPos
            If LotOperationId NE '' then
                ThisLotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
                OrigSeq = ThisLotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>
                NewSeq = OrigSeq - Offset
                ThisLotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = NewSeq
                Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, ThisLotOperationRec)
                If Error_Services('HasError') then
                    ErrorMessage = Error_Services('GetMessage')
                end
            end else
                Offset += 1
            end
        Until ErrorMessage NE ''
        Next LotOperation
    end else
        ErrorMessage = 'Lot Id not found'
    end
    
    If ErrorMessage NE '' then
        Error_Services('Add', 'Error in ' : Service : ' : ' : ErrorMessage)
    end
    
end service

Service GetAvailableSequences(LotId)
    AvailableSequences = ''
    
    If RowExists('LOT', LotId) then
        CurrentLotOperations = Lot_Services('GetLotOperationSequence', LotId)
        For each LotOperationId in CurrentLotOperations using @FM setting Sequence
            LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
            OperationId = LotOperationRec<LOT_OPERATION_OPERATION_ID$>
            OperationClass = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_CLASS_ID$)
            StartDtm = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
            If StartDTM EQ '' then
                AvailableSequences<1, -1> = Sequence + 1
            end
        Next LotOperationId
    end
    
    Response = AvailableSequences
end service

Service ConvertRecordToJson(LotOperationId)
    
    JsonString   = ''
    objJSON = ''
    LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
    If SRP_JSON(objJSON, 'New', 'Object') then
        SRP_JSON(objJSON, 'SetValue', 'LotOperationId', LotOperationId)
        LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
        LegacyLotId = Database_Services('ReadDataColumn', 'LOT', LotId, LOT_LEGACY_LOT_ID$, True$, 0, False$)
        SRP_JSON(objJSON, 'SetValue', 'LotOperationId', LotOperationId)
        SRP_JSON(objJSON, 'SetValue', 'LotId', LotId, 'String')
        SRP_JSON(objJSON, 'SetValue', 'LegacyLotId', LegacyLotId, 'String')
        SRP_JSON(objJSON, 'SetValue', 'OperationId', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, 'String')
        OperationDesc = XLATE('OPERATION', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, OPERATION_OPERATION_DESCRIPTION$, 'X')
        SRP_JSON(objJSON, 'SetValue', 'Description', OperationDesc, 'String')
        OperationClass = XLATE('OPERATION', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, OPERATION_CLASS_ID$, 'X')
        SRP_JSON(objJSON, 'SetValue', 'OperationClass', OperationClass)
        DatetimeIn = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_IN$>)
        SRP_JSON(objJSON, 'SetValue', 'DateTimeIn', DatetimeIn)
        DatetimeOut = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_OUT$>)
        SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', DatetimeOut)
        EquipmentId = LotOperationRec<LOT_OPERATION_EQUIPMENT_ID$>
        SRP_JSON(objJSON, 'SetValue', 'EquipmentId', EquipmentId)
        SRP_JSON(objJSON, 'SetValue', 'WaferInQty', LotOperationRec<LOT_OPERATION_WAFER_IN_QTY$>, 'Number')
        SRP_JSON(objJSON, 'SetValue', 'WaferOutQty', LotOperationRec<LOT_OPERATION_WAFER_OUT_QTY$>, 'Number')
        SRP_JSON(objJSON, 'SetValue', 'OperatorInId', LotOperationRec<LOT_OPERATION_OPERATOR_IN_ID$>)
        SRP_JSON(objJSON, 'SetValue', 'OperatorOutId', LotOperationRec<LOT_OPERATION_OPERATOR_OUT_ID$>)
        SRP_JSON(objJSON, 'SetValue', 'OperationSequence', LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>)
        DatetimeStart = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_START$>)
        SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', DatetimeStart)
        DatetimeStop = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_STOP$>)
        SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', DatetimeStop)
        SRP_JSON(objJSON, 'SetValue', 'MetTestId', LotOperationRec<LOT_OPERATION_MET_TEST_ID$>)
        SRP_JSON(objJSON, 'SetValue', 'CleanId', LotOperationRec<LOT_OPERATION_CLEAN_ID$>)
        SRP_JSON(objJSON, 'SetValue', 'PackagingId', LotOperationRec<LOT_OPERATION_PACKAGING_ID$>)
        SRP_JSON(objJSON, 'SetValue', 'WaferCounterId', LotOperationRec<LOT_OPERATION_WAFER_COUNTER_ID$>)
        SRP_JSON(objJson, 'SetValue', 'MetTestTypeRequired', LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>, 'STRING')
        SRP_JSON(objJson, 'SetValue', 'MetTestRequired', LotOperationRec<LOT_OPERATION_MET_TEST_REQUIRED$>, 'Boolean')
        SRP_JSON(objJson, 'SetValue', 'PackagingRequired', LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>, 'Boolean')
        SRP_JSON(objJson, 'SetValue', 'CleanRequired', LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>, 'Boolean')
        SRP_JSON(objJson, 'SetValue', 'WaferCounterRequired', LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$>, 'Boolean')
        PSNo = Xlate('LOT', LotId, LOT_PROD_SPEC_ID$, 'X')
        RecipeToolInfo = PSN_Services('GetAllMetrologyRecipes', PSNo, True$, True$, True$, True$)
        objRecipeInfo = ''
        If SRP_Json(objRecipeInfo, 'New', 'Array') then
            for each RecipeLine in RecipeToolInfo using @FM
                If SRP_Json(objRecipeLine, 'New', 'Object') then
                    SRP_Json(objRecipeLine, 'SetValue', 'ToolClass', RecipeLine<1,1>, 'String')
                    SRP_Json(objRecipeLine, 'SetValue', 'Recipe', RecipeLine<1,2>, 'String')
                    SRP_Json(objRecipeLine, 'SetValue', 'Stage', RecipeLine<1,3>, 'String')
                    SRP_Json(objRecipeInfo, 'Add', objRecipeLine)
                    SRP_Json(objRecipeLine, 'Release')
                end
            Next RecipeLine
            SRP_Json(objJSON, 'Set', 'RecipeInfo', objRecipeInfo)
            SRP_Json(objRecipeInfo, 'Release')
        end
        SRP_JSON(objJSON, 'SetValue', 'OperationType', LotOperationRec<LOT_OPERATION_OPERATION_TYPE$>)
        //Add OPERATION Object
        OperationJson = Operation_Services('ConvertRecordToJSON', LotOperationRec<LOT_OPERATION_OPERATION_ID$>)
        If SRP_JSON(objOperationJson, 'Parse', OperationJson) EQ '' then
            SRP_Json(objJSON, 'Set', 'OperationInfo',objOperationJson)
            SRP_Json(objOperationJson, 'Release')
        end
        //Add Associated MET_TEST JSON Object
        AssocMetTestIds = LotOperationRec<LOT_OPERATION_MET_TEST_ID$>
        objAssocMetTest = ''
        If SRP_Json(objAssocMetTest, 'New', 'Array') then
            for each MetTestId in AssocMetTestIds using @VM
                MetTestJson = Met_Test_Services('ConvertRecordToJson', MetTestId)
                If SRP_Json(objMetTest, 'Parse', MetTestJson) EQ '' then
                    SRP_Json(objAssocMetTest, 'Add', objMetTest)
                    SRP_Json(objMetTest, 'Release')
                end
            Next MetTestId
            SRP_Json(objJSON, 'Set', 'AssociatedMetTests', objAssocMetTest)
            SRP_Json(objAssocMetTest, 'Release')
        end
        //Add Available Met Test Record
        RequiredClasses = LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>
        AvailMetTestIds = ''
        ThisOperationDTMIn = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
        ThisOperationDTMOut = LotOperationRec<LOT_OPERATION_DATETIME_OUT$>
        if RequiredClasses NE '' AND DatetimeIn NE '' AND DatetimeOut EQ '' then
            AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', True$, RequiredClasses, ThisOperationDTMIn, ThisOperationDTMOut)
        end
        objAvailMetTest = ''
        If SRP_Json(objAvailMetTest, 'New', 'Array') then
            if AvailMetTestIds NE '' then
                for each MetTestId in AvailMetTestIds using @VM
                    
                    SRP_Stopwatch('Start', 'MetTestJson')
                    MetTestJson = Met_Test_Services('ConvertRecordToJson', MetTestId)
                    SRP_Stopwatch('Stop', 'MetTestJson')
                    totalTime = SRP_Stopwatch('GetBenchmark', 'MetTestJson')
                    If SRP_Json(objMetTest, 'Parse', MetTestJson) EQ '' then
                        SRP_Json(objAvailMetTest, 'Add', objMetTest)
                        SRP_Json(objMetTest, 'Release')
                    end
                Next MetTestId
            end
            SRP_Json(objJSON, 'Set', 'AvailMetTests', objAvailMetTest)
            SRP_Json(objAvailMetTest, 'Release')
        end
        //Add in relevant recipes
        Recipes = ''
        ShowThickRecipes = False$
        ShowResRecipes = False$
        ShowCleanRecipes = False$
        ShowSurfscanRecipes = False$
        IsMetTestReqd = LotOperationRec<LOT_OPERATION_MET_TEST_REQUIRED$>
        IsCleanRequired = LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>
        If IsMetTestReqd then
            MetTestTypeRequired = LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>
            Begin Case
                Case MetTestTypeRequired EQ 'TENCOR'
                    ShowSurfscanRecipes = True$
                Case MetTestTypeRequired EQ 'THICK'
                    ShowThickRecipes = True$
                Case MetTestTypeRequired EQ 'RES'
                    ShowResRecipes = True$
            End Case
        end
        If IsCleanRequired then
            ShowCleanRecipes = True$
        end
        ProdSpecNo = XLATE('LOT', LotId, LOT_PROD_SPEC_ID$, 'X')
        Recipes = PSN_Services('GetAllMetrologyRecipes', ProdSpecNo, ShowSurfscanRecipes, ShowCleanRecipes, ShowResRecipes, ShowThickRecipes)
        If SRP_JSON(objRecipes, 'New', 'Array') then
            for each Recipe in Recipes using @FM
                //ToolClass : @VM : Recipe : @VM : Stage
                ToolClass = Recipe<1,1>
                RecipeName = Recipe<1,2>
                Stage = Recipe<1,3>
                If SRP_JSON(objRecipe, 'New', 'Object') then
                    SRP_JSON(objRecipe, 'SetValue', 'ToolClass', ToolClass, 'String')
                    SRP_JSON(objRecipe, 'SetValue', 'RecipeName', RecipeName, 'String')
                    SRP_JSON(objRecipe, 'SetValue', 'StageName', Stage, 'String')
                    SRP_JSON(objRecipes, 'Add', objRecipe)
                    SRP_JSON(objRecipe, 'Release')
                end
            Next Recipe
            SRP_JSON(objJSON, 'Set', 'RecipeParams', objRecipes)
            SRP_JSON(objRecipes, 'Release')
        end
        JsonString = SRP_JSON(objJSON, 'Stringify', 'Fast')
        SRP_JSON(objJSON, 'Release')
    end
    
    Response = JsonString
end service



Service StartLotOperation(LotOperationId, UserId)
    
    ErrorMessage = ''
    
    If RowExists('LOT_OPERATION', LotOperationId) then
        If RowExists('LSL_USERS', UserId) then
            //We can also add additional checks like security checks, training checks, etc here if needed.
            LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
            LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
            LotCurrentLotOpId = Lot_Services('GetLotCurrOperationId', LotId)
            If LotOperationId EQ LotCurrentLotOpId then
                LotMovedIn = Lot_Services('IsLotMovedIn', LotId)
                If Not(LotMovedIn) then
                    Lot_Services('MoveInLot', LotId, UserId)
                    If Error_Services('HasError') then
                        ErrorMessage = Error_Services('GetMessage')
                    end
                end else
                    ErrorMessage = 'Lot is already moved into this operation.'  
                end
            end else
                
            end
        end else
            ErrorMessage = 'Invalid user passed to routine.'
        end
    end else
        ErrorMessage = 'Invalid Lot Operation passed to routine.'
    end
    
    If ErrorMessage EQ '' then
        Response = True$ 
    end else
        Response = False$
        Error_Services('Add', 'Error in ' : Service : '. ' : ErrorMessage) 
    end
    
end service

Service CompleteLotOperation(LotOperationId, UserId)

    ErrorMessage = ''
    If RowExists('LOT_OPERATION', LotOperationId) then
        If RowExists('LSL_USERS', UserId) then
            //We can also add additional checks like security checks, training checks, etc here if needed.
            LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
            LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
            LotCurrentLotOpId = Lot_Services('GetLotCurrOperationId', LotId)
            If LotOperationId EQ LotCurrentLotOpId then
                LotMovedIn = Lot_Services('IsLotMovedIn', LotId)
                If LotMovedIn then
                    //Perform Validation for the particular operation here.
                    OperationValid = Lot_Operation_Services('ValidateLotOperation', LotOperationId)
                    If OperationValid then
                        Lot_Services('MoveOutLot', LotId, UserId)
                        If Error_Services('HasError') then
                            ErrorMessage = Error_Services('GetMessage')
                        end
                    end else
                       ErrorMessage = 'Lot Operation has not finished processing and cannot be moved out.' 
                    end
                end else
                    ErrorMessage = 'Cannot complete operation because lot is not currently moved in.'
                end
            end else
                CurrOperationId = Xlate('LOT_OPERATION', LotCurrentLotOpId, LOT_OPERATION_OPERATION_ID$, 'X')
                CurrOperationDesc = Xlate('OPERATION', CurrOperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
                ErrorMessage = 'Cannot complete operation. Lot is currently at ' : CurrOperationDesc
            end
        end else
            ErrorMessage = 'Invalid user passed to routine.'
        end
    end else
        ErrorMessage = 'Invalid Lot Operation passed to routine.'
    end
    
    If ErrorMessage EQ '' then
       Response = True$ 
    end else
       Response = False$
       Error_Services('Add', ErrorMessage) 
    end
    
end service

Service ValidateLotOperation(LotOperationId)
    
    ErrorMessage = ''
    IsValid = True$
    If RowExists('LOT_OPERATION', LotOperationId) then
        LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
        OperationId = LotOperationRec<LOT_OPERATION_OPERATION_ID$>
        MetTestRequired = LotOperationRec<LOT_OPERATION_MET_TEST_REQUIRED$>
        MetTestTypeRequired = LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>
        PackagingRequired = LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>
        CleanRequired = LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>
        WaferCountRequired = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$>
        OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X')
        If MetTestRequired then
            MetTestsInSpec = True$
            AssociatedMetTestIds = LotOperationRec<LOT_OPERATION_MET_TEST_ID$>
            If AssociatedMetTestIds NE '' then
                for each MetTestId in AssociatedMetTestIds using @VM
                    MetTestOoS = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.OUT_OF_SPEC$, True$, 0, False)
                    If MetTestOoS AND OperationClass NE 'RTF' AND OperationClass NE 'RTF_DEFAULT' then
                        MetTestsInSpec = False$
                        ErrorMessage = 'An associated Met test record is out of spec.'
                    end
                Until MetTestsInSpec EQ False$
                Next MetTestId
            end else
                IsValid = False$
                ErrorMessage = 'Met tests are required and none are assigned.'
            end
        end
        If PackagingRequired AND IsValid then
            AssociatedPackagingIds = LotOperationRec<LOT_OPERATION_PACKAGING_ID$>
            If AssociatedPackagingIds NE '' then
                
            end else
                IsValid = False$
            end
        end
        If CleanRequired AND IsValid then
           AssociatedCleanIds = LotOperationRec<LOT_OPERATION_CLEAN_ID$>
            If AssociatedCleanIds NE '' then
                IsValid = True$
            end else
                IsValid = False$
            end 
        end
        If WaferCountRequired AND IsValid then
            AssociatedWaferCountIds = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_ID$>
            If AssociatedWaferCountIds NE '' then
                IsValid = True$
            end else
                IsValid = False$
            end 
        end
    end else
        ErrorMessage = 'Lot Operation not found' 
    end
    If ErrorMessage NE '' then
        IsValid = False$
        Error_Services('Add', ErrorMessage)
    end
    Response = IsValid
    
end service

