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

    This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
    permission from SRP Computer Solutions, Inc.

    Name        :   PTI_Services

    Description :   Handler program for all Scan services.

    Notes       :   

    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)
        10/11/19    djs     Original programmer.

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

$insert SERVICE_SETUP
$insert SCANS_EQUATES
$insert APP_INSERTS
$insert WO_MAT_EQUATES

Declare function    Scan_Services, Memory_Services, Database_Services, SRP_JSON, RTI_CreateGUID, Memberof
Declare function    Get_Property, RDS_Services, EpiPro_Services, DateTime, Signature_Services
Declare subroutine  Scan_Services, Memory_Services, Database_Services, SRP_JSON, Security_Services, obj_Notes
Declare subroutine  obj_WO_Mat_Log, obj_WO_Mat, Set_Status, SAP_Services, Hold_Services

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

Return Response or ""

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options SCAN_TYPES        = 'EMPLOYEE', 'CASSETTE_1', 'CASSETTE_2', 'POLY', 'TRILAM', 'SUPPLIER', 'PASSWORD'

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

//----------------------------------------------------------------------------------------------------------------------
// ProcessScanData
//
// Processes new scan data and updates the SCANS database row for the indicated Scan ID. This service should parse the
// scan data and identify its intended field and then evaluate if the scan data is valid. Note: just because the scan
// resource is not ready to be accepted, it does not mean this scan data is invalid. Each scan data will have to be
// evaluated on a case by case basis.
//----------------------------------------------------------------------------------------------------------------------
Service ProcessScanData(ScanData, ScanType = SCAN_TYPES, Param1, Param2, Param3)
    
    If (ScanData NE '') then
        // Code 3of9 encodes the asterisk and underscore characters. These need to be decoded.
        ScanData    = Scan_Services('DecodeScanData', ScanData)
        
        If Error_Services('NoError') then
            
            ColumnIndex = ''
            ColumnValue = ''
            // Identify the scan data based on the data identifier prefix (if any). Otherwise, assume this is a
            // type of cassette ID (i.e., RDS or WMO).
            Begin Case
                Case ScanType EQ 'EMPLOYEE'
                    If ScanData[1, 2] EQ '1H' then                        
                        // Valid Employee ID scan.
                        UserID       = ScanData[3, 999]
                        EmployeeAuthorized  = Memberof(UserID, 'PACKAGING')
                        If EmployeeAuthorized EQ False$ then                       
                            Error_Services('Add', 'User ':UserID:' is not certified to perform packaging operation.')
                        end
                        Response = UserID
                    end else
                        Error_Services('Add', 'Invalid employee ID scan.')
                    end
                    
                Case ScanType EQ 'SUPPLIER'
                    If ScanData[1, 2] EQ '2T' then
                        
                        // Valid Supplier Lot scan.
                        ScanSupplierID = ScanData[3, 999]
                        FirstCassID    = Param1
                        SecondCassID   = Param2
                        OperatorID     = Param3
                        RDSKey         = FirstCassID
                        WMOKey         = FirstCassID
                        LotMismatch    = False$
                        ExpectedLotNo  = ''
                        Convert '.' to '*' in WMOKey
                        
                        Begin Case
                            
                            Case RowExists('RDS', RDSKey) EQ True$
                                // RDS number
                                RDSLotNo = Xlate('RDS', RDSKey, 'LOT_NUM', 'X')                                
                                If (ScanSupplierID NE RDSLotNo) then
                                    LotMismatch   = True$
                                    WOMatKey      = Xlate('RDS', RDSKey, 'WO_MAT_KEY', 'X')
                                    HoldEntity    = 'RDS'
                                    HoldEntityID  = RDSKey
                                    ExpectedLotNo = RDSLotNo                        
                                end
                                
                            Case RowExists('WM_OUT', WMOKey) EQ True$                                
                                // WM_OUT key
                                WONo        = Field(WMOKey, '*', 1, 1)
                                CassNo      = Field(WMOKey, '*', 3, 1)
                                WOMatKey    = WONo:'*':CassNo
                                WOMatLotNo  = Xlate('WO_MAT', WOMatKey, 'LOT_NO', 'X')
                                If (ScanSupplierID NE WOMatLotNo) then
                                    LotMismatch   = True$
                                    HoldEntity    = 'WM_OUT'
                                    HoldEntityID  = WMOKey
                                    ExpectedLotNo = WOMatLotNo                              
                                end
                                
                            Case Otherwise$
                                ErrorMessage = 'Invalid cassette ID ':FirstCassID
                                Error_Services('Add', ErrorMessage)
                                
                        End Case
                        
                        If LotMismatch EQ True$ then
                            
                            // Place cassette on hold
                            CtrlEntID		= False$		;* Control checked/unchecked
                            PackagingFlag   = True$         ;* Flag to indicate a hold initiated from the packagaing form
                            Parms           = WOMatKey:@RM:HoldEntity:@RM:HoldEntityID:@RM:CtrlEntID:@RM:PackagingFlag:@RM:OperatorID
                            //obj_WO_Mat('ToggleHold', Parms)
                            Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, CtrlEntID, PackagingFlag, '', OperatorID)
                            
                            // Write fail packaging record in material log for first cassette ID
                            LogDate = OCONV( Date(), 'D2/' )
                            LogTime = OCONV( Time(), 'MTS' )  
                            LogFile = 'WO_MAT'               
                            LogDTM  = LogDate:' ':LogTime    
                            Action  = 'PACK'                
                            WhCd    = 'CR'
                            LocCd   = 'PACK'
                            UserID  = OperatorID
                            Tags    = 'Supp Lot Mismatch (':ScanSupplierID:')'
                            ToolID  = ''
                            
                            If ( RDS_Services('IsEpiPro', FirstCassID) EQ True$) then
                                WONo    = Field(FirstCassID, '.', 1, 1)
                                CassNo  = Field(FirstCassID, '.', 3, 1)
                            end else
                                WONo   = Xlate('RDS', FirstCassID, 'WO', 'X')
                                CassNo = Xlate('RDS', FirstCassID, 'CASS_NO', 'X')
                            end
                            
                            WOMLParms  = LogFile:@RM
                            WOMLParms := LogDTM:@RM
                            WOMLParms := Action:@RM
                            WOMLParms := WhCd:@RM
                            WOMLParms := LocCd:@RM
                            WOMLParms := WONo:@RM
                            WOMLParms := CassNo:@RM
                            WOMLParms := UserID:@RM
                            WOMLParms := Tags:@RM
                            WOMLParms := ToolID 
                            
                            obj_WO_Mat_Log('Create',WOMLParms)
                            errCode = ''                   
                            IF Get_Status(errCode) THEN
                                ErrorMsg = 'Error calling obj_WO_Mat_Log("Create"). Error code: ':errCode
                                Error_Services('Add', ErrorMsg)
                            end
                            
                            // Send scan mismatch notification
                            Recipients = Xlate('NOTIFICATION', 'PACKAGING', 'USER_ID', 'X')
                            
                            SentFrom		= OperatorID
                            Subject			= 'Packaging Verification Mismatch'
                            Message			= 'Supplier lot number verification failed at packaging. Cassette placed on hold and Supervisor, Lead, or Engineering disposition required.':CRLF$ |
                            : 'RDS Label #1: ':FirstCassID:CRLF$            | 
                            : 'RDS Label #2: ':SecondCassID:CRLF$           |
                            : 'Scanned Lot Number: ':ScanSupplierID:CRLF$   |
                            : 'Expected Lot Number: ':ExpectedLotNo:CRLF$   |
                            : 'Operator: ':OperatorID
                            AttachWindow	= ''
                            AttachKey		= ''
                            SendToGroup		= ''   
                            
                            Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
                            obj_Notes('Create',Parms)
                            errCode = ''
                            IF Get_Status(errCode) THEN Error_Services('Add', 'Error code ':errCode:' in ':Service:' service.')                            
                            
                            // Add error to error stack
                            ErrorMessage = 'Lots do not match â€“ operation cannot continue. '|
                            : 'Lot has been put on hold - place lot on hold shelf and notify Supervisor, Lead, or Engineering'
                            Error_Services('Add', ErrorMessage)
                        end
                        
                        If Error_Services('NoError') then Response = ScanSupplierID
                        
                    end else
                        Error_Services('Add', 'Invalid supplier lot scan.')
                    end
                    
                Case ScanType EQ 'PASSWORD'
                    If ScanData[1, 3] EQ 'PWD' then
                        // Password scan.
                        Username = Get_Property(@Window:'.EDL_USER_ID_SCAN', 'TEXT')
                        Password = ScanData[4, 999]
                        Security_Services('AuthenticateLSLCredentials', Username, Password)
                        If Error_Services('NoError') then
                            Response = Password              
                        end else
                            ErrorMessage = Error_Services('GetMessage')
                            Error_Services('Add', ErrorMessage)
                        end
                        
                    end else
                        Error_Services('Add', 'Invalid password scan.')
                    end
                    
                Case ScanType EQ 'POLY'
                    If ScanData[1, 5] EQ '1POLY' AND LEN(ScanData) EQ 5 then
                        // Valid Poly scan - has to be exact match
                        Response = ScanData[2, 999]
                    end else
                        Error_Services('Add', 'Location does not equal POLY â€“ operation cannot continue.')
                    end
                    
                Case ScanType EQ 'TRILAM'
                    If ScanData[1, 7] EQ '1TRILAM' AND LEN(ScanData) EQ 7 then
                        // Valid Trilam scan - has to be exact match
                        Response = ScanData[2, 999]
                    end else
                        Error_Services('Add', 'Location does not equal TRILAM â€“ operation cannot continue.')
                    end
                    
                Case ScanType EQ 'CASSETTE_1'
                    
                    // Assume this is intended to be a Cassette ID scan (either WMO or RDS). Only if this is a
                    // non-existent carrier will the scan data be considered invalid.
                    // Strip '1T', 'I', and 'O' prefixes.
                    If ScanData[1, 2] EQ '1T' then
                        ScanData[1, 2] = ''
                        If ( (ScanData[1, 1] EQ 'O') or (ScanData[1, 1] EQ 'I') ) then ScanData[1, 1] = ''
                    end                    
                    If ( (ScanData[1, 1] EQ 'O') or (ScanData[1, 1] EQ 'I') ) then ScanData[1, 1] = ''
                    If ScanData[1, 3] EQ 'PWD' then ScanData = '********'
                    CassetteID      = ScanData
                    ValidCassetteID = False$  ; // Assume Cassette ID is not valid for now.
                    
                    RDSCass = Count(CassetteID, '.') EQ 0 AND Num(CassetteID)
                    GaNCass = Count(CassetteID, '.') EQ 1 AND not(RDSCass)
                    EPPCass = Count(CassetteID, '.') EQ 2 AND not(RDSCass) AND not(GaNCass)
                    
                    Begin Case
                        Case GaNCass
                            // GaN
                            Convert '.' to '*' in CassetteID
                            // Need to check if PSN has ANKO flag. If so, throw error.
                            RDSNo = Xlate('WO_MAT', CassetteID, 'RDS_NO', 'X')
                            PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X')
                            ANKO = Xlate('PROD_SPEC', PSNo, 'ANKO', 'X')
                            If ANKO NE True$ then                           
                                WOMatRow    = Database_Services('ReadDataRow', 'WO_MAT', CassetteID)
                                If Error_Services('NoError') then
                                    ValidCassetteID = True$
                                    FQAComp = Signature_Services('FinalSigComp', CassetteID)
                                    If FQAComp EQ True$ then
                                        Null                             
                                    end else
                                        ErrorMessage = 'FQA is not complete, operation cannot continue. ' |
                                        : 'Please place lot in FQA area and notify Supervisor or Lead.'
                                        Error_Services('Add', ErrorMessage)
                                    end
                                end
                            end else
                                ErrorMessage = 'ANKO cassettes cannot go through packaging. They must be retained.'
                                Error_Services('Add', ErrorMessage)
                            end
                        Case EPPCass
                            // EpiPro
                            Convert '.' to '*' in CassetteID
                            WMOutRow    = Database_Services('ReadDataRow', 'WM_OUT', CassetteID)
                            If Error_Services('NoError') then
                                ValidCassetteID = True$
                                FQAComp = Epipro_Services('GetFinalQAStatus', CassetteID)
                                If FQAComp EQ True$ then
                                    HoldStatus = Xlate('WM_OUT', CassetteID, 'HOLD', 'X')
                                    If (HoldStatus EQ True$) then
                                        ErrorMessage = 'Lot is currently on hold â€“ operation cannot continue. ' |
                                        : 'Place lot on hold shelf and notify Supervisor, Lead, or Engineering.'
                                        Error_Services('Add', ErrorMessage)                    
                                    end
                                end else
                                    ErrorMessage = 'FQA is not complete, operation cannot continue. ' |
                                    : 'Please place lot in FQA area and notify Supervisor or Lead.'
                                    Error_Services('Add', ErrorMessage)
                                end
                            end
                        Case RDSCass
                            // RDS
                            RDSRow  = Database_Services('ReadDataRow', 'RDS', CassetteID)
                            If Error_Services('NoError') then
                                ValidCassetteID = True$
                                FQAComp = Rds_Services('GetFinalQAStatus', CassetteID)
                                If FQAComp EQ True$ then                               
                                    HoldStatus = Xlate('RDS', CassetteID, 'HOLD', 'X')
                                    If (HoldStatus EQ True$) then
                                        ErrorMessage = 'Lot is currently on hold â€“ operation cannot continue.' |
                                        : 'Place lot on hold shelf and notify Supervisor, Lead, or Engineering.'
                                        Error_Services('Add', ErrorMessage)                    
                                    end
                                end else
                                    ErrorMessage = 'FQA is not complete, operation cannot continue. ' |
                                    : 'Please place lot in FQA area and notify Supervisor or Lead.'
                                    Error_Services('Add', ErrorMessage)
                                end
                            end 
                    End Case

                    If ValidCassetteID EQ False$ then
                        Error_Services('Add', 'Unrecognized scan data: ':ScanData)
                    end
                    
                    Response = ScanData
                    
                Case ScanType EQ 'CASSETTE_2'
                    
                    // Assume this is intended to be a Cassette ID scan (either WMO or RDS). Only if this is a
                    // non-existent carrier will the scan data be considered invalid.
                    // Strip '1T', 'I', and 'O' prefixes.
                    If ScanData[1, 2] EQ '1T' then
                        ScanData[1, 2] = ''
                        If ( (ScanData[1, 1] EQ 'O') or (ScanData[1, 1] EQ 'I') ) then ScanData[1, 1] = ''
                    end                    
                    If ( (ScanData[1, 1] EQ 'O') or (ScanData[1, 1] EQ 'I') ) then ScanData[1, 1] = ''
                    If ScanData[1, 3] EQ 'PWD' then ScanData = '********'
                    SecondCassID    = ScanData
                    FirstCassID     = Param1
                    OperatorID      = Param2
                    ValidCassetteID = False$  ; // Assume Cassette ID is not valid for now.
                    ScanMismatch    = False$
                    
                    Begin Case
                        Case DCount(SecondCassID, '.') EQ 3
                            // EpiPro
                            Convert '.' to '*' in SecondCassID
                            WMOutRow    = Database_Services('ReadDataRow', 'WM_OUT', SecondCassID)
                            Convert '*' to '.' in SecondCassID
                            If Error_Services('NoError') then
                                ValidCassetteID = True$
                                If (SecondCassID NE FirstCassID) then
                                    ScanMismatch = True$
                                end
                            end
                            
                        Case Index(SecondCassID, '.', 1) > 1
                            // GaN
                            Convert '.' to '*' in SecondCassID
                            Convert '.' to '*' in FirstCassID
                            WOMatRow    = Database_Services('ReadDataRow', 'WO_MAT', SecondCassID)
                            If Error_Services('NoError') then
                                ValidCassetteID = True$
                                If (SecondCassID NE FirstCassID) then
                                    ScanMismatch = True$
                                end
                            end
                        Case Num(SecondCassID)
                            // RDS
                            RDSRow  = Database_Services('ReadDataRow', 'RDS', SecondCassID)
                            If Error_Services('NoError') then
                                ValidCassetteID = True$
                                If (SecondCassID NE FirstCassID) then
                                    ScanMismatch = True$
                                end
                            end
                    End Case
                    
                    If ValidCassetteID EQ False$ then Error_Services('Add', 'Unrecognized scan data: ':ScanData)
                    
                    If ScanMismatch EQ True$ then
                        
                        // Write fail packaging record in material log for first cassette ID  
                        LogFile = 'WO_MAT'               
                        LogDTM  = DateTime()    
                        Action  = 'PACK'                
                        WhCd    = 'CR'
                        LocCd   = 'PACK'
                        UserID  = OperatorID
                        Tags    = 'RDS Mismatch (':SecondCassID:')'
                        ToolID  = ''
                        
                        // Check if first cassette ID is a valid RDS or WM_OUT key
                        Convert '.' to '*' in FirstCassID                           
                        ValidCass = False$
                        Begin Case
                            Case ( RowExists('RDS', FirstCassID) EQ True$ )
                                WONo         = Xlate('RDS', FirstCassID, 'WO', 'X')
                                CassNo       = Xlate('RDS', FirstCassID, 'CASS_NO', 'X')
                                HoldEntity   = 'RDS'                             
                            Case ( RowExists('WM_OUT', FirstCassID) EQ True$ )
                                WONo         = Field(FirstCassID, '*', 1, 1)
                                CassNo       = Field(FirstCassID, '*', 3, 1)
                                HoldEntity   = 'WM_OUT'
                            Case ( RowExists('WO_MAT', FirstCassID) EQ True$ )
                                WONo         = Field(FirstCassID, '*', 1, 1)
                                CassNo       = Field(FirstCassID, '*', 2, 1)
                                HoldEntity   = 'WO_MAT'                    
                            Case Otherwise$
                                Null
                                // To do: Throw Error                               
                        End Case
                        Convert '*' to '.' in FirstCassID
                        
                        HoldEntityID = FirstCassID 
                        
                        // Manually add work order material log entry
                        WOMatKey      = WONo:'*':CassNo
                        WOMatRec      = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
                        NumTimestamps = Dcount(WOMatRec<WO_MAT_INV_WH$>, @VM)
                        NewEntryPos   = NumTimestamps + 1
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_WH$,         NewEntryPos, 0, WhCd)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_LOCATION$,   NewEntryPos, 0, LocCd)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_ACTION$,     NewEntryPos, 0, Action)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_DTM$,        NewEntryPos, 0, LogDTM)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_USER$,       NewEntryPos, 0, UserID)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_TAG$,        NewEntryPos, 0, Tags)
                        WOMatRec = INSERT(WOMatRec, WO_MAT_INV_TOOL_ID$,    NewEntryPos, 0, ToolID)
                        Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
                        
                        // Place first cassette on hold
                        WOMatKey        = WONo:'*':CassNo
                        CtrlEntID		= False$		;* Control checked/unchecked
                        PackagingFlag   = True$         ;* Flag to indicate a hold initiated from the packagaing form
                        Parms           = WOMatKey:@RM:HoldEntity:@RM:HoldEntityID:@RM:CtrlEntID:@RM:PackagingFlag:@RM:OperatorID
                        //obj_WO_Mat('ToggleHold', Parms)
                        Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, CtrlEntID, PackagingFlag, '', OperatorID)
                        
                        // Check if second cassette ID is a valid RDS or WM_OUT key
                        Convert '.' to '*' in SecondCassID                           
                        ValidCass = False$
                        Begin Case
                            Case ( RowExists('RDS', SecondCassID) EQ True$ )
                                ValidCass  = True$
                                WONo         = Xlate('RDS', SecondCassID, 'WO', 'X')
                                CassNo       = Xlate('RDS', SecondCassID, 'CASS_NO', 'X')
                                HoldEntity   = 'RDS'                              
                            Case ( RowExists('WM_OUT', SecondCassID) EQ True$ )
                                ValidCass  = True$
                                WONo         = Field(SecondCassID, '*', 1, 1)
                                CassNo       = Field(SecondCassID, '*', 3, 1)
                                HoldEntity   = 'WM_OUT'
                            Case ( RowExists('WO_MAT', FirstCassID) EQ True$ )
                                WONo         = Field(FirstCassID, '*', 1, 1)
                                CassNo       = Field(FirstCassID, '*', 2, 1)
                                HoldEntity   = 'WO_MAT'                           
                            Case Otherwise$
                                Null
                                
                        End Case
                        Convert '*' to '.' in SecondCassID
                        
                        // Write fail packaging record in material log for second cassette ID
                        If ValidCass EQ True$ then  
                            LogFile = 'WO_MAT'               
                            LogDTM  = DateTime()     
                            Action  = 'PACK'                
                            WhCd    = 'CR'
                            LocCd   = 'PACK'
                            UserID  = OperatorID
                            Tags    = 'RDS Mismatch (':FirstCassID:')'
                            ToolID  = ''                                                      
                            
                            HoldEntityID = SecondCassID 
                            
                            // Manually add work order material log entry
                            WOMatKey      = WONo:'*':CassNo
                            WOMatRec      = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
                            NumTimestamps = Dcount(WOMatRec<WO_MAT_INV_WH$>, @VM)
                            NewEntryPos   = NumTimestamps + 1
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_WH$,         NewEntryPos, 0, WhCd)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_LOCATION$,   NewEntryPos, 0, LocCd)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_ACTION$,     NewEntryPos, 0, Action)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_DTM$,        NewEntryPos, 0, LogDTM)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_USER$,       NewEntryPos, 0, UserID)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_TAG$,        NewEntryPos, 0, Tags)
                            WOMatRec = INSERT(WOMatRec, WO_MAT_INV_TOOL_ID$,    NewEntryPos, 0, ToolID)
                            Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
                            
                            //pause before putting second cassette on hold
                            
                            // Place second cassette on hold
                            CtrlEntID		= False$		;* Control checked/unchecked
                            PackagingFlag   = True$         ;* Flag to indicate a hold initiated from the packagaing form
                            Parms           = WOMatKey:@RM:HoldEntity:@RM:HoldEntityID:@RM:CtrlEntID:@RM:PackagingFlag:@RM:OperatorID
                            //obj_WO_Mat('ToggleHold', Parms)
                            Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, CtrlEntID, PackagingFlag, '', OperatorID)
                        end
                        
                        // Send scan mismatch notification
                        Recipients = Xlate('NOTIFICATION', 'PACKAGING', 'USER_ID', 'X')
                        
                        SentFrom		= OperatorID
                        Subject			= 'Packaging Verification Mismatch'
                        Message			= 'RDS label verification failed at packaging. Both cassettes placed on hold - Supervisor, Lead, or Engineering disposition required.':CRLF$ |
                        : 'RDS Label #1: ':FirstCassID:CRLF$ | 
                        : 'RDS Label #2: ':SecondCassID:CRLF$ |
                        : 'Operator: ':OperatorID
                        AttachWindow	= ''
                        AttachKey		= ''
                        SendToGroup		= ''   
                        
                        Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
                        obj_Notes('Create',Parms)
                        errCode = ''
                        IF Get_Status(errCode) THEN Error_Services('Add', 'Error code ':errCode:' in ':Service:' service.')
                        Error_Services('Add', 'Cassette scans did not match! Both cassettes placed on hold - Supervisor, Lead, or Engineering disposition required.')
                        
                    end
                    If ScanData[1, 3] EQ 'PWD' then ScanData = ''
                    Response = ScanData
                    
            End Case
            
        end
    end else
        Error_Services('Add', 'ScanData argument was missing in the ' : Service : ' service.')
    end
    
end service


Service CompletePackaging(CassetteID, OperatorID)
    
    *    1.	Write success packaging record in Material Log
    *    2.	Write success PTO record in Material Log
    *    3.	Send SAP Cassette Complete transaction (up to now, this has been done at FQA)
    
    RDSKey = CassetteID
    WMOKey = CassetteID
    Convert '.' to '*' in WMOKey
    
    Begin Case
        Case RowExists('RDS', RDSKey) EQ True$            
            // RDS number
            WOMatKey = Xlate('RDS', RDSKey, 'WO', 'X')
            WOMatKey = WoMatKey:'*':Xlate('RDS', RDSKey, 'CASS_NO', 'X')            
            
        Case RowExists('WM_OUT', WMOKey) EQ True$           
            // WM_OUT key
            WOMatKey = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X')
            
        Case RowExists('WO_MAT', CassetteID) EQ True$
            // WO_MAT key
            WOMatKey = CassetteID
            
        Case Otherwise$
            ErrorMessage = 'Invalid cassette ID ':CassetteID
            Error_Services('Add', ErrorMessage)
            
    End Case
    
    If Error_Services('NoError') then
        
        // Write success packaging
        LogFile = 'WO_MAT'               
        Action  = 'PACK'                
        WhCd    = 'CR'
        LocCd   = 'PACK'
        UserID  = OperatorID
        Tag     = 'Packaging complete'
        ToolID  = ''
        WONo    = Field(WOMatKey, '*', 1, 1)
        CassNo  = Field(WOMatKey, '*', 2, 1)
        InvDTM  = OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS')	        
        
        WOMLParms  = LogFile:@RM
        WOMLParms := InvDTM:@RM
        WOMLParms := Action:@RM
        WOMLParms := WhCd:@RM
        WOMLParms := LocCd:@RM
        WOMLParms := WONo:@RM
        WOMLParms := CassNo:@RM
        WOMLParms := UserID:@RM
        WOMLParms := Tag:@RM
        WOMLParms := ToolID 
        
        Set_Status(0)
        obj_WO_Mat_Log('Create',WOMLParms)
        
        errCode = ''                   
        IF Get_Status(errCode) THEN
            swap @SVM with CRLF$ in errCode
            ErrorMsg = 'Errors calling obj_WO_Mat_Log("Create"). Error code: ':errCode:', Len(errCode)=':Len(errCode)
            Error_Services('Add', ErrorMsg)
            if LEN(errCode) > 5 then
                Gosub SendErrorNotification
            end
        end
        
        // Add CassComp transaction to SAP queue
        SAP_Services('AddCassCompTransaction', WOMatKey)
    end
    
end service

SendErrorNotification:
    Recipients		= XLATE('SEC_GROUPS', 'OI_ADMIN', 'USER', 'X')
    SentFrom		= "PACKAGING_SERVICES"
    Subject			= 'ERROR CALLING OBJ_WO_MAT '
    Message			= 'Error occured while attempting to write WO_MAT_LOG at packaging':CRLF$:ErrorMsg
    AttachKey		= WoMatKey
    AttachWindow	= ''   
    SendToGroup		= ''   
    
    Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
    obj_Notes('Create',Parms)
    
return

