Compile function NCR_Services(@Service, @Params) #pragma precomp SRP_PreCompiler /*********************************************************************************************************************** Name : NCR_Services Description : Handler program for all NCR services. Notes : Application errors should be logged using the Error Services module. There are a few methodological assumptions built into way errors are managed which are important to understand in order to properly work with Error Services: - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger this will appear backwards since the originating procedure always appears at the bottom of the list and the current routine appears at the top of the list. We are using this orientation because it is common to refer to the process of calling other procedures as 'drilling down'. - The reason for defining the orientation of the call stack is because Error_Services allows for multiple error conditions to be appended to an original error. In most cases this will happen when a procedure at the bottom of the stack generates an error condition and then returns to its calling procedure. This higher level procedure can optionally add more information relevant to itself. This continues as the call stack 'bubbles' its way back to the top to where the originating procedure is waiting. - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus) preserve their error state until explicitly cleared. This can hinder the normal execution of code since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists. Our philosophy is that error conditions should automatically be cleared before a new procedure is executed to avoid this problem. However, the nature of Basic+ does not make this easy to automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our philosophy then it should include a call into the 'Clear' service request at the top of the program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.) - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any error conditions that were set before. Parameters : Service [in] -- Name of the service being requested Param1-10 [in/out] -- Additional request parameter holders Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure Metadata : History : (Date, Initials, Notes) 08/29/24 djm Add ProcessScanData service and Service header. ***********************************************************************************************************************/ $insert APP_INSERTS $Insert SERVICE_SETUP $Insert NCR_EQUATES $Insert REACTOR_EQUATES Declare subroutine Set_Status, Logging_Services, Error_Services, Obj_Notes, Set_Property, Obj_Wo_Mat, Hold_Services Declare subroutine Btree.Extract, SRP_JSon Declare function Environment_Services, Logging_Services, SRP_Datetime, Utility, Scan_Services, Error_Services Declare function Database_Services, Signature_Services, Epipro_Services, Rds_Services, Memberof, Datetime Declare function Get_Property, SRP_Json, obj_ncr EQU COL$RDS_NO TO 1 EQU COL$REACTOR TO 2 EQU COL$REJ_CNT TO 3 GoToService Return Response or "" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options SCAN_TYPES = 'CASSETTE_1', 'CASSETTE_2', 'WM_IN_1', 'WM_IN_2' //---------------------------------------------------------------------------------------------------------------------- // SERVICES //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- // ProcessScanData // // ScanData - [Required] // ScanType - [Required] // FirstCassID - [Required] // OperatorID - [Required] // // Returns the current stage of a lot. Replaces CURR_STAGE calculated column. //---------------------------------------------------------------------------------------------------------------------- Service ProcessScanData(ScanData, ScanType = SCAN_TYPES, FirstCassID, OperatorID) If (ScanData NE '') then Convert @Lower.Case to @Upper.Case in ScanData // 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 'WM_IN_1' ValidCassID = False$ cnt = Count(ScanData, '|') if cnt NE 0 then Error_Services('Add', 'Wrong label - Scan 2D Top Label') return end else CassetteID = ScanData Swap 'FDI' with '' in CassetteID Swap '^FS' with '' in CassetteID Swap 'I' with '' in CassetteID Convert '.' to '*' in CassetteID WMIRow = Database_Services('ReadDataRow', 'WM_IN', CassetteID) If Error_Services('NoError') then ValidCassID = True$ end ScanData = CassetteID If ScanData NE FirstCassID then Error_Services('Add', 'Lot Label does not match the expected lot in OI. | Please correct this issue and then retry.') end end If ValidCassID EQ False$ then Error_Services('Add', 'Unrecognized scan data: ':ScanData) end Response = ScanData Case ScanType EQ 'WM_IN_2' ValidCassID = False$ ScanMismatch = False$ cnt = Count(ScanData, '|') if cnt NE 0 then Error_Services('Add', 'Wrong label - Scan 2D Bottom Label') return end else CassetteID = ScanData Swap 'FDI' with '' in CassetteID Swap '^FS' with '' in CassetteID Swap 'I' with '' in CassetteID Convert '.' to '*' in CassetteID WMIRow = Database_Services('ReadDataRow', 'WM_IN', CassetteID) If Error_Services('NoError') then ValidCassID = True$ end ScanData = CassetteID If ScanData NE FirstCassID then ScanMismatch = True$ end end If ScanMismatch EQ True$ then ValidCassID = False$ If (RowExists('WM_IN', FirstCassID) EQ True$) And (RowExists('WM_IN', CassetteID) EQ True$) then // Place first cassette on hold WONo = Field(FirstCassID, '*', 1, 1) CassNo = Field(FirstCassID, '*', 3, 1) HoldEntity = 'WM_IN' HoldEntityID = FirstCassID WOMatKey = WONo:'*':CassNo CtrlEntID = 'NCR_SERVICES' ;* Control checked/unchecked OriginFlag = '' ;* Flag to indicate a hold initiated from the packagaing form HoldData = '' HoldData<1> = OperatorID HoldData<2> = 'Lot placed on hold due to NCR Barcode verification mismatch.' HoldData<3> = False$ Hold_Services('OnHold', WOMatKey, HoldEntity, HoldEntityID, 'HOLD', HoldData, OperatorID) // Place Second cassette on hold WONo = Field(CassetteID, '*', 1, 1) CassNo = Field(CassetteID, '*', 3, 1) HoldEntity = 'WM_IN' HoldEntityID = CassetteID WOMatKey = WONo:'*':CassNo CtrlEntID = 'NCR_SERVICES' ;* Control checked/unchecked OriginFlag = '' ;* Flag to indicate a hold initiated from the packagaing form HoldData = '' HoldData<1> = OperatorID HoldData<2> = 'Lot placed on hold due to NCR Barcode verification mismatch.' HoldData<3> = False$ Hold_Services('OnHold', WOMatKey, HoldEntity, HoldEntityID, 'HOLD', HoldData, OperatorID) Message = 'NCR Label verification failed due to mismatched barcodes. Both cassettes placed on hold - Supervisor, Lead, or Engineering disposition required.':CRLF$ | : 'WM_IN Label #1: ':FirstCassID:CRLF$ | : 'WM_IN Label #2: ':CassetteID:CRLF$ | : 'Operator: ':OperatorID Error_Services('Add', Message) end else Error_Services('Add', 'Unrecognized scan data: ':ScanData) end end If ValidCassID EQ False$ then Error_Services('Add', 'Unrecognized scan data: ':ScanData) end Response = ScanData 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. cnt = DCount(ScanData, '|') if cnt NE 8 then CassetteID = 0 Error_Services('Add', 'Wrong label - Scan 2D Top Label') return end else // RDS should be 3rd position CassetteID = Field(ScanData, '|', 3) Seq1 = Field(ScanData, '|', 8) end // Strip '1T', 'I', and 'O' prefixes. If CassetteID[1, 2] EQ '1T' then CassetteID[1, 2] = '' If ((CassetteID[1, 1] EQ 'O') or (CassetteID[1, 1] EQ 'I')) then CassetteID[1, 1] = '' end If ( (CassetteID[1, 1] EQ 'O') or (CassetteID[1, 1] EQ 'I') ) then CassetteID[1, 1] = '' ValidCassID = 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 Convert '.' to '*' in CassetteID WOMatRow = Database_Services('ReadDataRow', 'WO_MAT', CassetteID) If Error_Services('NoError') then ValidCassID = True$ end Case EPPCass Convert '.' to '*' in CassetteID WMOutRow = Database_Services('ReadDataRow', 'WM_OUT', CassetteID) If Error_Services('NoError') then ValidCassID = True$ end Case RDSCass RDSRow = Database_Services('ReadDataRow', 'RDS', CassetteID) If Error_Services('NoError') then ValidCassID = True$ end End Case If ( (Seq1 EQ 'SEQ1') or (Seq1 EQ 'SEQ2') ) then Set_Property(@Window, '@SEQ1', Seq1) end else Error_Services('Add', 'Error reading sequence information') end If ValidCassID EQ False$ then Error_Services('Add', 'Unrecognized scan data: ':ScanData) end ScanData = CassetteID If ScanData NE FirstCassID then Error_Services('Add', 'Lot Label does not match the expected lot in OI. | Please correct this issue and then retry.') 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. cnt = DCount(ScanData, '|') if cnt NE 8 then CassetteID = 0 Error_Services('Add', 'Wrong label - Scan 2D Bottom Label') return end else // RDS should be 3rd position SecondCassID = Field(ScanData, '|', 3) Seq2 = Field(ScanData, '|', 8) end // Strip '1T', 'I', and 'O' prefixes. If SecondCassID[1, 2] EQ '1T' then SecondCassID[1, 2] = '' If ( (SecondCassID[1, 1] EQ 'O') or (SecondCassID[1, 1] EQ 'I') ) then SecondCassID[1, 1] = '' end If ( (SecondCassID[1, 1] EQ 'O') or (SecondCassID[1, 1] EQ 'I') ) then SecondCassID[1, 1] = '' ValidCassID = False$ ; // Assume Cassette ID is not valid for now. ScanMismatch = False$ SeqMismatch = False$ SeqError = False$ Convert '*' to '.' in FirstCassID If Error_Services('NoError') then ValidCassID = True$ If (SecondCassID NE FirstCassID) then ScanMismatch = True$ end else Seq1 = Get_Property(@Window, '@SEQ1') Begin Case Case ( (Seq2 NE 'SEQ1') and (Seq2 NE 'SEQ2') ) SeqError = True$ Case (Seq2 EQ Seq1) SeqMismatch = True$ End Case end end If ValidCassID EQ False$ then Error_Services('Add', 'Unrecognized scan data: ':ScanData) If (ScanMismatch EQ True$) AND (ValidCassID EQ True$) then // Check if first cassette ID is a valid RDS or WM_OUT key Convert '.' to '*' in FirstCassID ValidCassID = False$ Begin Case Case ( RowExists('RDS', FirstCassID) EQ True$ ) ValidCassID = True$ WONo = Xlate('RDS', FirstCassID, 'WO', 'X') CassNo = Xlate('RDS', FirstCassID, 'CASS_NO', 'X') HoldEntity = 'RDS' Case ( RowExists('WM_OUT', FirstCassID) EQ True$ ) ValidCassID = True$ WONo = Field(FirstCassID, '*', 1, 1) CassNo = Field(FirstCassID, '*', 3, 1) HoldEntity = 'WM_OUT' Case ( RowExists('WM_IN', FirstCassID) EQ True$ ) ValidCassID = True$ WONo = Field(FirstCassID, '*', 1, 1) CassNo = Field(FirstCassID, '*', 3, 1) HoldEntity = 'WM_IN' Case ( RowExists('WO_MAT', FirstCassID) EQ True$ ) ValidCassID = True$ WONo = Field(FirstCassID, '*', 1, 1) CassNo = Field(FirstCassID, '*', 2, 1) HoldEntity = 'WO_MAT' Case Otherwise$ Null End Case HoldEntityID = FirstCassID // Place first cassette on hold WOMatKey = WONo:'*':CassNo CtrlEntID = 'NCR_SERVICES' ;* Control checked/unchecked OriginFlag = '' ;* Flag to indicate a hold initiated from the packagaing form HoldData = '' HoldData<1> = OperatorID HoldData<2> = 'Lot placed on hold due to NCR Barcode verification mismatch.' HoldData<3> = False$ Hold_Services('OnHold', WOMatKey, HoldEntity, HoldEntityID, 'HOLD', HoldData, OperatorID) // Check if second cassette ID is a valid RDS or WM_OUT key Convert '.' to '*' in SecondCassID ValidCassID = False$ Begin Case Case ( RowExists('RDS', SecondCassID) EQ True$ ) ValidCassID = True$ WONo = Xlate('RDS', SecondCassID, 'WO', 'X') CassNo = Xlate('RDS', SecondCassID, 'CASS_NO', 'X') HoldEntity = 'RDS' ValidCassID = True$ Case ( RowExists('WM_OUT', SecondCassID) EQ True$ ) ValidCassID = True$ WONo = Field(SecondCassID, '*', 1, 1) CassNo = Field(SecondCassID, '*', 3, 1) HoldEntity = 'WM_OUT' Case ( RowExists('WM_IN', SecondCassID) EQ True$ ) WONo = Field(SecondCassID, '*', 1, 1) CassNo = Field(SecondCassID, '*', 3, 1) HoldEntity = 'WM_IN' ValidCassID = True$ Case ( RowExists('WO_MAT', SecondCassID) EQ True$ ) WONo = Field(SecondCassID, '*', 1, 1) CassNo = Field(SecondCassID, '*', 2, 1) HoldEntity = 'WO_MAT' ValidCassID = True$ Case Otherwise$ Null End Case If ValidCassID EQ True$ then HoldEntityID = SecondCassID WOMatKey = WONo:'*':CassNo // Place second cassette on hold CtrlEntID = 'NCR_SERVICES' ;* Control checked/unchecked OriginFlag = '' ;* Flag to indicate a hold initiated from the packagaing form HoldData = '' HoldData<1> = OperatorID HoldData<2> = 'Lot placed on hold due to NCR Barcode verification mismatch.' HoldData<3> = False$ Hold_Services('OnHold', WOMatKey, HoldEntity, HoldEntityID, 'HOLD', HoldData, OperatorID) end Message = 'NCR Label verification failed due to mismatched barcodes. Both cassettes placed on hold - Supervisor, Lead, or Engineering disposition required.':CRLF$ | : 'Cassette Label #1: ':FirstCassID:CRLF$ | : 'Cassette Label #2: ':SecondCassID:CRLF$ | : 'Operator: ':OperatorID Error_Services('Add', Message) end else if (SeqMismatch EQ True$) then //do sequence mismatch stuff here Message = 'NCR Label verification failed due to operator double-scanning barcode.':CRLF$ | : 'Cassette: ':FirstCassID:CRLF$ | : 'Operator: ':OperatorID Error_Services('Add', Message) end else if (SeqError EQ True$) then Error_Services('Add', 'Error reading sequence information') end ScanData = '' ScanData = SecondCassID Response = ScanData End Case end end else Error_Services('Add', 'ScanData argument was missing in the ' : Service : ' service.') end end service Service SendToSPC(NCRNo, RDSList, ReactorType, PSNo, DeptResp, LossCode, LossDesc, LossStage, LossBy, ACCode, ACDesc) Headers = 'Logging DTM' : @FM : 'Machine' : @FM : 'Level' : @FM : 'Log' ColumnWidths = 20 : @FM : 12 : @FM : 7 : @FM : 500 Machine = Environment_Services('GetServer') LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\NCR' makeDirSuccess = Utility("MAKEDIR", LogPath) LogDate = Oconv(Date(), 'D4/') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : '_NcrSendToSpc.csv' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, ColumnWidths, False$, False$) RdsNos = '' RdsCount = 0 ReactorList = '' ReactorCount = 0 RejCntList = '' RejCntCount = 0 RDSCnt = DCOUNT(RDSList<1>,@VM) If RDSCnt GT 0 then FOR I = 1 TO RDSCnt If RdsNos NE '' then RdsNos := ', ' end RdsNos := RDSList