Function Reactor_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 : Reactor_Services Description : Handler program for all module related services. Notes : The generic parameters should contain all the necessary information to process the services. Often this will be information like the data Record and Key ID. 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/10/17 dmb Original programmer. Adapted from Scheduling_Services. - [IREPIOI-8] 01/08/18 dmb Update the CreatePerformanceTrackers service so the CreateWeeklyPerformanceReport is called on Friday mornings for the upcoming week rather than Monday mornings for the current week. - [IREPIOI-14] 02/17/18 dmb Add logging to track reactor performance activities. - [IREPIOI-14] 05/30/18 dmb Update various services to allow newer reactors to be used for reporting. - [IREPIOI-17] 06/21/18 dmb Update the path where templates and reports are stored. - [IREPIOI-33] 06/26/18 dmb Add logging to track when this service is being called. - [IREPIOI-56] 06/26/18 dmb Update logic on how reactors are selected for reporting. - [IREPIOI-56] 04/20/21 djs Added PickPlace to objReactor JSON object in GetReactor service. 12/06/23 djm Add MD3 conversion to TargetThickness in metric increment and decrement services. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert APP_INSERTS $insert SERVICE_SETUP $insert REACTOR_EQUATES $insert RDS_EQUATES $insert RLIST_EQUATES $insert TOOL_EQUATES $Insert REACTOR_LOG_EQUATES $Insert REACTOR_CHILD_KEY_IDS_EQUATES $Insert REACTOR_MODES_EQUATES $Insert REACT_MODE_EQU ;* THESE ARE NOT THE SAME jch, Update 9/15/21. These are the equates for the CONFIG records $Insert REACT_MODE_NG_EQUATES $Insert REACT_UTIL_EQU $Insert SCHED_DET_NG_EQUATES $Insert REACT_STATUS_EQUATES $Insert WO_LOG_EQUATES $Insert REACTOR_DAILY_UPTIME_EQUATES $Insert REACT_LL_EQUATES $Insert IQS_VIOL_DATA_EQUATES $Insert FEATURE_FLAGS_EQUATES Equ WOCust$ to 2 // Uptime Percentage Equates Equ PRODUCTIVE$ to 1 Equ UNSCHED$ to 2 Equ SCHED$ to 3 Equ NONSCHED$ to 4 Equ ENG$ to 5 Declare subroutine Error_Services, Reactor_Services, Memory_Services, RList, Database_Services, SRP_JSON Declare subroutine Excel_Services, Schedule_Services, Logging_Services, Set_Status, obj_React_Status, Errmsg Declare subroutine Obj_Notes, Btree.Extract, SRP_Fastarray, Delay, Mona_Services, SRP_List, Msg, Rds_Services Declare subroutine React_Assign_Conv, Nica_Orders_Services, obj_React_Mode Declare function SRP_Array, Reactor_Services, Memory_Services, Database_Services, SRP_Sort_Array, Excel_Services Declare function SRP_Math, SRP_Hash, SRP_JSON, Epi_Part_Services, Schedule_Services, Date_Services, Environment_Services Declare function Logging_Services, GetCommandLine, NextKey, Reactor_Log_Services, SRP_DateTime, ole_getwebpage Declare function Datetime, Reactor_Modes_Services, Work_Order_Services, React_Mode_NG_Services, Lsl_Users_Services Declare function SRP_Time, Rds_Services, SRP_Fastarray, Httpclient_Services, SRP_List, Utility, Memberof, Error_Services Declare function Nica_Orders_Services // Report paths for various performance report services. TemplatesFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Templates\' DailyReportsFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Daily\' WeeklyReportsFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Weekly\' CommandLine = GetCommandLine() Machine = Environment_Services('GetServer') LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM GoToService else end Return Response else '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options BOOLEAN = True$, False$ Options REACTORMETRIC = 'TUBE_BELL_JAR_THK', 'TUBE_BELL_JAR_WFR_CNT', 'SUSC_THK', 'SUSC_WFR_CNT', 'LOWER_QUARTZ_THK', 'LOWER_QUARTZ_WFR', 'ARMS_WFR_CNT' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // IncrementWfrMetrics // // RDSNo. - [Required] // // Increment the REACTOR wafer count and thickness when RDS unload is signed. // //---------------------------------------------------------------------------------------------------------------------- Service IncrementWfrMetrics(RDSNo) // Get Reactor and run count details RDSRec = Xlate('RDS', RDSNo, '', 'X', '') TargetThickness = Xlate('RDS', RDSNo, 'THICK_TARGET_TOT', 'X', '') TargetThickness = OConv(TargetThickness, 'MD3') WaferCount = RDSRec ReactorNo = RDSRec OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) NewReactorRec = OldReactorRec ReactorType = OldReactorRec SusceptorSize = OldReactorRec SusceptorSize = SusceptorSize[-4,1] // Get Old Values CurrTubeBellJarThk = OldReactorRec CurrTubeBellJarCnt = OldReactorRec CurrSuscThk = OldReactorRec CurrSuscWfrCnt = OldReactorRec CurrLowerQuartzThk = OldReactorRec CurrLowerQuartzWfr = OldReactorRec // Arms are not used for EPP If ReactorType NE 'EPP' then CurrArmsWfrCnt = OldReactorRec If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0 end // Set values to 0 if blank If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0 If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0 If CurrSuscThk = '' then CurrSuscThk = 0 If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0 If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0 If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0 Begin Case Case ReactorType = 'EPP' NewReactorRec = CurrTubeBellJarThk + TargetThickness NewReactorRec = CurrTubeBellJarCnt + 1 NewReactorRec = CurrSuscThk + TargetThickness NewReactorRec = CurrSuscWfrCnt + 1 NewReactorRec = CurrLowerQuartzThk + TargetThickness NewReactorRec = CurrLowerQuartzWfr + 1 Case ReactorType = 'HTR' Begin Case Case SusceptorSize = 6 CntAddition = (WaferCount / 5) ThkAddition = (WaferCount / 5) * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + CntAddition NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + CntAddition NewReactorRec = CurrArmsWfrCnt + WaferCount Case SusceptorSize = 8 // Round up CntAddition = (WaferCount / 3) If Count(CntAddition, '.') EQ 1 Then CntAddition = Int(CntAddition) + 1 end ThkAddition = (WaferCount / 3) * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + CntAddition NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + CntAddition NewReactorRec = CurrArmsWfrCnt + WaferCount End Case Case ReactorType = 'ASM' OR ReactorType = 'ASM+' ThkAddition = WaferCount * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + WaferCount NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + WaferCount NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + WaferCount NewReactorRec = CurrArmsWfrCnt + WaferCount End Case Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0) end service Service GetWaferCntMetricsByReactorID(ReactorID) If ReactorID NE '' then If RowExists('REACTOR', ReactorID) then ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) ReactorType = ReactorRec ResponseData = '' Begin Case Case ReactorType EQ 'ASM' OR ReactorType EQ 'ASM+' ResponseData<1, 1> = ReactorID ResponseData<1, 2> = ReactorRec ResponseData<1, 3> = ReactorRec ResponseData<1, 4> = ReactorRec ResponseData<1, 5> = ReactorRec ResponseData<1, 6> = ReactorRec //These are the column titles to help us with API Responses ResponseData<2, 1> = 'ReactorID' ResponseData<2, 2> = 'SusceptorWaferCount' ResponseData<2, 3> = 'SusceptorThickness' ResponseData<2, 4> = 'TubeWaferCount' ResponseData<2, 5> = 'TubeThickness' ResponseData<2, 6> = 'ArmsWaferCount' Case ReactorType EQ 'HTR' ResponseData<1, 1> = ReactorID ResponseData<1, 2> = ReactorRec ResponseData<1, 3> = ReactorRec ResponseData<1, 4> = ReactorRec ResponseData<1, 5> = ReactorRec ResponseData<1, 6> = ReactorRec //These are the column titles to help us with API Responses ResponseData<2, 1> = 'ReactorID' ResponseData<2, 2> = 'SusceptorWaferCount' ResponseData<2, 3> = 'SusceptorThickness' ResponseData<2, 4> = 'TubeWaferCount' ResponseData<2, 5> = 'TubeThickness' ResponseData<2, 6> = 'ArmsWaferCount' Case ReactorType EQ 'EPP' ResponseData<1, 1> = ReactorID ResponseData<1, 2> = ReactorRec ResponseData<1, 3> = ReactorRec ResponseData<1, 4> = ReactorRec ResponseData<1, 5> = ReactorRec ResponseData<1, 6> = ReactorRec ResponseData<1, 7> = ReactorRec //These are the column titles to help us with API Responses ResponseData<2, 1> = 'ReactorID' ResponseData<2, 2> = 'SusceptorWaferCount' ResponseData<2, 3> = 'SusceptorThickness' ResponseData<2, 4> = 'BellJarWaferCount' ResponseData<2, 5> = 'BellJarThickness' ResponseData<2, 6> = 'LowerQuartzWaferCount' ResponseData<2, 7> = 'LowerQuartzThickness' End Case Response = ResponseData end else Error_Services('Add', 'Error: Invalid Reactor ID passed to REACTOR_SERVICES("GetWaferMetricsByReactorID"') end end else Error_Services('Add', 'Error: Null Reactor ID passed to REACTOR_SERVICES("GetWaferMetricsByReactorID"') end end service //---------------------------------------------------------------------------------------------------------------------- // DecrementWfrMetrics // // RDSNo. - [Required] // // Decrement the REACTOR wafer count and thickness when RDS unload is unsigned. // //---------------------------------------------------------------------------------------------------------------------- Service DecrementWfrMetrics(RDSNo) // Get Reactor and run count details RDSRec = Xlate('RDS', RDSNo, '', 'X', '') TargetThickness = Xlate('RDS', RDSNo, 'THICK_TARGET_TOT', 'X', '') TargetThickness = OConv(TargetThickness, 'MD3') WaferCount = RDSRec ReactorNo = RDSRec OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) NewReactorRec = OldReactorRec ReactorType = OldReactorRec SusceptorSize = OldReactorRec SusceptorSize = SusceptorSize[-4,1] // Get Old Values CurrTubeBellJarThk = OldReactorRec CurrTubeBellJarCnt = OldReactorRec CurrSuscThk = OldReactorRec CurrSuscWfrCnt = OldReactorRec CurrLowerQuartzThk = OldReactorRec CurrLowerQuartzWfr = OldReactorRec // Arms are not used for EPP If ReactorType NE 'EPP' then CurrArmsWfrCnt = OldReactorRec If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0 end // Set values to 0 if blank If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0 If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0 If CurrSuscThk = '' then CurrSuscThk = 0 If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0 If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0 If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0 Begin Case Case ReactorType = 'EPP' NewReactorRec = CurrTubeBellJarThk - TargetThickness NewReactorRec = CurrTubeBellJarCnt - 1 NewReactorRec = CurrSuscThk - TargetThickness NewReactorRec = CurrSuscWfrCnt - 1 NewReactorRec = CurrLowerQuartzThk - TargetThickness NewReactorRec = CurrLowerQuartzWfr - 1 Case ReactorType = 'HTR' Begin Case Case SusceptorSize = 6 CntAddition = (WaferCount / 5) ThkAddition = (WaferCount / 5) * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt - CntAddition NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - CntAddition NewReactorRec = CurrArmsWfrCnt - WaferCount Case SusceptorSize = 8 // Round up CntAddition = (WaferCount / 3) If Count(CntAddition, '.') EQ 1 Then CntAddition = Int(CntAddition) + 1 end ThkAddition = (WaferCount / 3) * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - CntAddition NewReactorRec = CurrSuscThk - ThkAddition NewReactorRec = CurrSuscWfrCnt - CntAddition NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - CntAddition NewReactorRec = CurrArmsWfrCnt - WaferCount End Case Case ReactorType = 'ASM' OR ReactorType = 'ASM+' ThkAddition = WaferCount * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - WaferCount NewReactorRec = CurrSuscThk - ThkAddition NewReactorRec = CurrSuscWfrCnt - WaferCount NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - WaferCount NewReactorRec = CurrArmsWfrCnt - WaferCount End Case Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0) end service //---------------------------------------------------------------------------------------------------------------------- // IncrementTestWfrMetrics // // TargetThickness - [Required] // WaferCount - [Required] // ReactorNo - [Required] // // Increment the REACTOR wafer count and thickness for test wafers. // //---------------------------------------------------------------------------------------------------------------------- Service IncrementTestWfrMetrics(TargetThickness, WaferCount, ReactorNo) OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) NewReactorRec = OldReactorRec ReactorType = OldReactorRec SusceptorSize = OldReactorRec SusceptorSize = SusceptorSize[-4,1] // Get Old Values CurrTubeBellJarThk = OldReactorRec CurrTubeBellJarCnt = OldReactorRec CurrSuscThk = OldReactorRec CurrSuscWfrCnt = OldReactorRec CurrLowerQuartzThk = OldReactorRec CurrLowerQuartzWfr = OldReactorRec // Arms are not used for EPP If ReactorType NE 'EPP' then CurrArmsWfrCnt = OldReactorRec If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0 end // Set values to 0 if blank If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0 If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0 If CurrSuscThk = '' then CurrSuscThk = 0 If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0 If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0 If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0 Begin Case Case ReactorType = 'EPP' NewReactorRec = CurrTubeBellJarThk + TargetThickness NewReactorRec = CurrTubeBellJarCnt + 1 NewReactorRec = CurrSuscThk + TargetThickness NewReactorRec = CurrSuscWfrCnt + 1 NewReactorRec = CurrLowerQuartzThk + TargetThickness NewReactorRec = CurrLowerQuartzWfr + 1 Case ReactorType = 'HTR' Begin Case Case SusceptorSize = 6 CntAddition = (WaferCount / 5) ThkAddition = (WaferCount / 5) * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + CntAddition NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + CntAddition NewReactorRec = CurrArmsWfrCnt + WaferCount Case SusceptorSize = 8 // Round up CntAddition = (WaferCount / 3) If Count(CntAddition, '.') EQ 1 Then CntAddition = Int(CntAddition) + 1 end ThkAddition = (WaferCount / 3) * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + CntAddition NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + CntAddition NewReactorRec = CurrArmsWfrCnt + WaferCount End Case Case ReactorType = 'ASM' OR ReactorType = 'ASM+' ThkAddition = WaferCount * TargetThickness NewReactorRec = CurrTubeBellJarThk + ThkAddition NewReactorRec = CurrTubeBellJarCnt + WaferCount NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt + WaferCount NewReactorRec = CurrLowerQuartzThk + ThkAddition NewReactorRec = CurrLowerQuartzWfr + WaferCount NewReactorRec = CurrArmsWfrCnt + WaferCount End Case Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0) end service //---------------------------------------------------------------------------------------------------------------------- // DecrementTestWfrMetrics // // TargetThickness - [Required] // WaferCount - [Required] // ReactorNo - [Required] // // Decrement the REACTOR wafer count and thickness for test wafers. // //---------------------------------------------------------------------------------------------------------------------- Service DecrementTestWfrMetrics(TargetThickness, WaferCount, ReactorNo) OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) NewReactorRec = OldReactorRec ReactorType = OldReactorRec SusceptorSize = OldReactorRec SusceptorSize = SusceptorSize[-4,1] // Get Old Values CurrTubeBellJarThk = OldReactorRec CurrTubeBellJarCnt = OldReactorRec CurrSuscThk = OldReactorRec CurrSuscWfrCnt = OldReactorRec CurrLowerQuartzThk = OldReactorRec CurrLowerQuartzWfr = OldReactorRec // Arms are not used for EPP If ReactorType NE 'EPP' then CurrArmsWfrCnt = OldReactorRec If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0 end // Set values to 0 if blank If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0 If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0 If CurrSuscThk = '' then CurrSuscThk = 0 If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0 If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0 If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0 Begin Case Case ReactorType = 'EPP' NewReactorRec = CurrTubeBellJarThk - TargetThickness NewReactorRec = CurrTubeBellJarCnt - 1 NewReactorRec = CurrSuscThk - TargetThickness NewReactorRec = CurrSuscWfrCnt - 1 NewReactorRec = CurrLowerQuartzThk - TargetThickness NewReactorRec = CurrLowerQuartzWfr - 1 Case ReactorType = 'HTR' Begin Case Case SusceptorSize = 6 CntAddition = (WaferCount / 5) ThkAddition = (WaferCount / 5) * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - CntAddition NewReactorRec = CurrSuscThk + ThkAddition NewReactorRec = CurrSuscWfrCnt - CntAddition NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - CntAddition NewReactorRec = CurrArmsWfrCnt - WaferCount Case SusceptorSize = 8 // Round up CntAddition = (WaferCount / 3) If Count(CntAddition, '.') EQ 1 Then CntAddition = Int(CntAddition) + 1 end ThkAddition = (WaferCount / 3) * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - CntAddition NewReactorRec = CurrSuscThk - ThkAddition NewReactorRec = CurrSuscWfrCnt - CntAddition NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - CntAddition NewReactorRec = CurrArmsWfrCnt - WaferCount End Case Case ReactorType = 'ASM' OR ReactorType = 'ASM+' ThkAddition = WaferCount * TargetThickness NewReactorRec = CurrTubeBellJarThk - ThkAddition NewReactorRec = CurrTubeBellJarCnt - WaferCount NewReactorRec = CurrSuscThk - ThkAddition NewReactorRec = CurrSuscWfrCnt - WaferCount NewReactorRec = CurrLowerQuartzThk - ThkAddition NewReactorRec = CurrLowerQuartzWfr - WaferCount NewReactorRec = CurrArmsWfrCnt - WaferCount End Case Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0) end service //---------------------------------------------------------------------------------------------------------------------- // ResetWfrMetric // // RDSNo. - [Required] // MetricType - [Required]('TUBE_BELL_JAR_THK', 'TUBE_BELL_JAR_WFR_CNT', 'SUSC_THK', 'SUSC_WFR_CNT', 'LOWER_QUARTZ_THK', 'LOWER_QUARTZ_WFR', 'ARMS_WFR_CNT') // // Reset a specified REACTOR metric to 0. // //---------------------------------------------------------------------------------------------------------------------- Service ResetWfrMetric(ReactorNo, MetricType = REACTORMETRIC) ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) Begin Case Case MetricType = 'TUBE_BELL_JAR_THK' ReactorRec = 0 Case MetricType = 'TUBE_BELL_JAR_WFR_CNT' ReactorRec = 0 Case MetricType = 'SUSC_THK' ReactorRec = 0 Case MetricType = 'SUSC_WFR_CNT' ReactorRec = 0 Case MetricType = 'LOWER_QUARTZ_THK' ReactorRec = 0 Case MetricType = 'LOWER_QUARTZ_WFR' ReactorRec = 0 Case MetricType = 'ARMS_WFR_CNT' ReactorRec = 0 End Case Database_Services('WriteDataRow', 'REACTOR', ReactorNo, ReactorRec, 1, 0, 0) end service //---------------------------------------------------------------------------------------------------------------------- // GetReactors // // Returns a JSON formatted array of reactor objects. Reactor number 0 will be ommitted. If the MatchType or MatchSize // arguments are populated, the array will be filterd accordingly. //---------------------------------------------------------------------------------------------------------------------- Service GetReactors(MatchType, MatchSize) ServiceKeyID := '*' : MatchType : '*' : MatchSize Reactors = '' If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then Reactors = Memory_Services('GetValue', ServiceKeyID) end else objReactors = '' If SRP_JSON(objReactors, 'NEW', 'OBJECT') then objReactorArray = '' If SRP_JSON(objReactorArray, 'NEW', 'ARRAY') then hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ Reactors = '' Loop Readnext ReactorNo else Done = True$ Until Done Reactor = Reactor_Services('GetReactor', ReactorNo) If SRP_JSON(objReactor, 'PARSE', Reactor) EQ '' then ReactorType = SRP_JSON(objReactor, 'GETVALUE', 'Type') ReactorSize = SRP_JSON(objReactor, 'GETVALUE', 'SusceptorSize') IncludeReactor = True$ ; // Assume reactor will be included in the response. Begin Case Case ReactorNo EQ 0 // Reactor number 0 is not a real reactor. IncludeReactor = False$ Case MatchType NE '' Begin Case Case MatchType[1, 3] EQ 'ASM' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS')) IncludeReactor = False$ Case MatchType EQ 'EPS' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS')) IncludeReactor = False$ Case MatchType EQ 'EPP' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro')) IncludeReactor = False$ Case MatchType EQ 'EpiPro' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro')) IncludeReactor = False$ Case MatchType _EQC 'GAN' AND Not(ReactorType _EQC 'GAN') IncludeReactor = False$ Case MatchType NE ReactorType IncludeReactor = False$ End Case Case MatchSize NE '' If MatchSize NE ReactorSize then IncludeReactor = False$ Case Not(RowExists('TOOL', 'R':ReactorNo)) // This tool does not exist IncludeReactor = False$ End Case If IncludeReactor then SRP_JSON(objReactorArray, 'ADD', objReactor) end SRP_JSON(objReactor, 'RELEASE') end Repeat SRP_JSON(objReactors, 'SET', 'Reactors', objReactorArray) Reactors = SRP_JSON(objReactors, 'STRINGIFY', 'FAST') Memory_Services('SetValue', ServiceKeyID, Reactors) end SRP_JSON(objReactorArray, 'RELEASE') end else Error_Services('Add', 'Error creating objReactorArray in the ' : Service : ' service.') end SRP_JSON(objReactors, 'RELEASE') end else Error_Services('Add', 'Error creating objReactors in the ' : Service : ' service.') end end Response = Reactors end service //---------------------------------------------------------------------------------------------------------------------- // GetReactorNumbers // // Returns an @FM delimited list of Reactor Numbers. //---------------------------------------------------------------------------------------------------------------------- Service GetReactorNumbers(MatchType, MatchSize) ServiceKeyID := '*' : MatchType : '*' : MatchSize ReactorNumbers = '' If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then ReactorNumbers = Memory_Services('GetValue', ServiceKeyID) end else hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ Reactors = '' Loop Readnext ReactorNo else Done = True$ Until Done Reactor = Reactor_Services('GetReactor', ReactorNo) If SRP_JSON(objReactor, 'PARSE', Reactor) EQ '' then ReactorType = SRP_JSON(objReactor, 'GETVALUE', 'Type') ReactorSize = SRP_JSON(objReactor, 'GETVALUE', 'SusceptorSize') IncludeReactor = True$ ; // Assume reactor will be included in the response. Begin Case Case ReactorType EQ '' IncludeReactor = False$ Case MatchType NE '' Begin Case Case MatchType[1, 3] EQ 'ASM' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS')) IncludeReactor = False$ Case MatchType EQ 'EPS' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS')) IncludeReactor = False$ Case MatchType EQ 'EPP' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro')) IncludeReactor = False$ Case MatchType EQ 'EpiPro' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro')) IncludeReactor = False$ Case MatchType _EQC 'GAN' AND Not(ReactorType _EQC 'GAN') IncludeReactor = False$ Case MatchType NE ReactorType IncludeReactor = False$ End Case Case MatchSize NE '' If MatchSize NE ReactorSize then IncludeReactor = False$ End Case If IncludeReactor then ReactorNumbers := ReactorNo : @FM end end Repeat ReactorNumbers[-1, 1] = '' Memory_Services('SetValue', ServiceKeyID, ReactorNumbers) end end Response = ReactorNumbers end service //---------------------------------------------------------------------------------------------------------------------- // GetReactor // // Returns a JSON formatted object of information related to the indicated reactor number. //---------------------------------------------------------------------------------------------------------------------- Service GetReactor(ReactorNo) ServiceKeyID := '*' : ReactorNo Reactor = '' If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then Reactor = Memory_Services('GetValue', ServiceKeyID) end else If (ReactorNo NE '') AND (ReactorNo NE 0) then ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) If SRP_JSON(objReactor, 'NEW', 'OBJECT') then ReactorType = ReactorRow SRP_JSON(objReactor, 'SETVALUE', 'ReactorNumber', ReactorNo, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'Type', ReactorType, 'STRING') Begin Case Case ReactorType _EQC 'ASM' ; ReactorTypeVerbose = 'ASM' Case ReactorType _EQC 'ASM+'; ReactorTypeVerbose = 'ASM+' Case ReactorType _EQC 'EPP' ; ReactorTypeVerbose = 'EpiPro' Case ReactorType _EQC 'EPS' ; ReactorTypeVerbose = 'ASM' Case ReactorType _EQC 'HTR' ; ReactorTypeVerbose = 'HTR' Case ReactorType _EQC 'GAN' ; ReactorTypeVerbose = 'GaN' Case ReactorType _EQC '' ; ReactorTypeVerbose = '***' End Case SRP_JSON(objReactor, 'SETVALUE', 'TypeVerbose', ReactorTypeVerbose, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'AssignmentCode', ReactorRow, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'AssignmentDescription', Oconv(ReactorRow, '[REACT_ASSIGN_CONV]'), 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'Location', ReactorRow, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'SusceptorSize', ReactorRow, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'SecondChamber', ReactorRow, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'PickPlace', ReactorRow, 'STRING') SRP_JSON(objReactor, 'SETVALUE', 'NotRepairable', ReactorRow, 'STRING') Reactor = SRP_JSON(objReactor, 'STRINGIFY', 'FAST') Memory_Services('SetValue', ServiceKeyID, Reactor) SRP_JSON(objReactor, 'RELEASE') end else Error_Services('Add', 'Error creating objReactor in the ' : Service : ' service.') end end else Error_Services('Add', 'ReactorNo argument was missing from the ' : Service : ' service.') end end Response = Reactor end service //---------------------------------------------------------------------------------------------------------------------- // CreatePerformanceTrackers // // Creates performance tracking database rows in the REACTOR_PERFORMANCE table. This creates a unique tracker for each // Reactor/Part pair based on the indicated dates scheduled work orders. //---------------------------------------------------------------------------------------------------------------------- Service CreatePerformanceTrackers(ScheduleDate, CreateReports) // Force the auto scheduler to run to make sure that all adjustments are being made to the scheduler. * Schedule_Services('AutoScheduler') If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() If CreateReports NE False$ then CreateReports = True$ // There will be two procedures. The first is a pass through the scheduled events to create the Reactor Performance // rows. The second is a pass through the recently created Reactor Performance records to adjust the expected // wafer count based part changes. // Get a list of all the scheduled events for the indicated schedule date. Note: this service expects to be ran // shortly after midnight for the indicated schedule date. ScheduleEvents = Schedule_Services('GetScheduleEvents', ScheduleDate, ScheduleDate, '', '', False$) If ScheduleEvents NE '' then PerfKeyIDs = '' For Each ScheduleEvent in ScheduleEvents using @FM KeyIDs = ScheduleEvent<0, 2> WorkOrderNo = KeyIDs[1, '*'] EpiPartNo = KeyIDs[Col2() + 1, '*'] ReactorNo = KeyIDs[Col2() + 1, '*'] ScheduleDate = KeyIDs[Col2() + 1, '*'] Sequence = KeyIDs[Col2() + 1, '*'] If EpiPartNo NE '' then PartUsedKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate : '*' : EpiPartNo If Memory_Services('KeyExists', PartUsedKeyID) EQ False$ then PartCountKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate NumParts = Memory_Services('GetValue', PartCountKeyID) NumParts += 1 Memory_Services('SetValue', PartCountKeyID, NumParts) Memory_Services('SetValue', PartUsedKeyID, True$) end // This is a work order event rather than a block out event. ScheduleEventSummary = Schedule_Services('GetScheduleEventSummary', ReactorNo, WorkOrderNo, ScheduleDate, Sequence, True$) StartDate = Iconv(ScheduleEventSummary<6>, 'D') ReactorType = ScheduleEventSummary<1> EndDate = Iconv(ScheduleEventSummary<7>, 'D') TotalWafers = ScheduleEventSummary<9> Begin Case Case ReactorType _eqc 'ASM+' ; ReactorType = 'ASM+' Case ReactorType _eqc 'EPP' ; ReactorType = 'EpiPro' Case ReactorType _eqc 'EPS' ; ReactorType = 'ASM' Case ReactorType _eqc 'HTR' ; ReactorType = 'HTR' Case ReactorType _eqc 'GAN' ; ReactorType = 'GaN' Case ReactorType _eqc '' ; ReactorType = '***' End Case MinutesPerWafer = Epi_Part_Services('GetMinutesPerWaferScheduler', EpiPartNo, ReactorType) WafersPerDay = Epi_Part_Services('GetAdjustedWafersPerDayScheduler', EpiPartNo, ReactorType, MinutesPerWafer) If ScheduleDate LT EndDate then // The end date of this schedule event is still in the future. Therefore, the current event is expected // to run the whole day. Use the calculated wafers per day. WafersExpected = WafersPerDay end else // This is the end of the schedule event. Wafers expected will be the remaining total wafers after // all previous wafers per day have been deducted. TotalPreviousDays = EndDate - StartDate TotalPreviousWafers = TotalPreviousDays * WafersPerDay WafersExpected = TotalWafers - TotalPreviousWafers If WafersExpected GT WafersPerDay then WafersExpected = WafersPerDay ; // Cap to the wafers per day. end If WafersExpected LT 0 then WafersExpected = 0 // Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE} WeekDate = Date_Services('GetISOWeekDate', ScheduleDate) WeekYear = WeekDate[1, '-'] WeekNo = WeekDate[Col2() + 1, '-'] PerfKeyID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) PerfRow<2> = PerfRow<2> + Iconv(WafersExpected, 'MD2') Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$) Locate PerfKeyID in PerfKeyIDs using @FM setting fPos else PerfKeyIDs := PerfKeyID : @FM end Next ScheduleEvent // Pass through each Reactor Performance row. For every part being run on a given reactor, the following // adjustment is required: // // 1. Total expected amount per part should be prorated by the number of parts. This accounts for the fact // that one reactor will be splitting its time for each part. For example, if Part A is normally estimated // to run 200 parts and Part B is normally estimated to run 300 parts, they will each be prorated by .5. // Thus, Part A will now be estimated to run 100 parts and Part B will be estimated to run 150 parts. // // 2. Since each part change requires an average of 6 hours of down time to prepare the reactor, the amount // per part should be prorated by the remaining hours in the day. For example, if there are two parts being // ran on the reactor, this only allows 18 hours (out of 24) to run parts, which is a prorated value of // .75. Using the above example, Part A would then have 100 parts prorated to 75 (100 * .75) and Part would // then have 150 parts prorated to 112.50 (150 * .75). If PerfKeyIDs NE '' then For Each PerfKeyID in PerfKeyIDs using @FM ReactorNo = PerfKeyID[1, '*'] EpiPartNo = PerfKeyID[Col2() + 1, '*'] WeekYear = PerfKeyID[Col2() + 1, '*'] WeekNo = PerfKeyID[Col2() + 1, '*'] ScheduleDate = PerfKeyID[Col2() + 1, '*'] PartCountKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate NumParts = Memory_Services('GetValue', PartCountKeyID) If NumParts GT 1 then // Only prorate if there is more then one part. Prorate1 = 1 / NumParts ; // Adjust for the number of parts. Prorate2 = ((24 - ((NumParts - 1) * 6) ) / 24) ; // Adjust for the number of hours remaining in the day. Prorate = Prorate1 * Prorate2 PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) PerfRow<2> = PerfRow<2> * ProRate Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$) end Next PerfKeyID // Clear out all cached data. Memory_Services('ReleaseHashTable') end end If CreateReports then Reactor_Services('CreateDailyPerformanceReport', ScheduleDate) If Mod(ScheduleDate, 7) EQ 5 then // This is early Friday. Create the weekly performance report for the upcoming week. First, the // CreatePerformanceTrackers must be called for all days in the upcoming week. NextMonday = ScheduleDate + 3 NextSunday = ScheduleDate + 9 For ScheduleDate = NextMonday to NextSunday Reactor_Services('CreatePerformanceTrackers', ScheduleDate, False$) Next ScheduleDate // Create the weekly performance report based on the daily performance tracking data. YearWeekNo = Date_Services('GetISOWeekDate', NextMonday) YearWeekNo = Field(YearWeekNo, '-', 1, 2) Reactor_Services('CreateWeeklyPerformanceReport', YearWeekNo) // Clear the daily performance tracking data for the upcoming week since these will be recreated // automatically on the morning of each date. For ScheduleDate = NextMonday to NextSunday Reactor_Services('ClearWafersExpected', ScheduleDate) Next ScheduleDate end end end service //---------------------------------------------------------------------------------------------------------------------- // UpdatePerformanceTrackers // // Updates the wafers processed column in the performance tracking database rows. //---------------------------------------------------------------------------------------------------------------------- Service UpdatePerformanceTrackers(ScheduleDate, CreateReports) If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() If CreateReports NE False$ then CreateReports = True$ rv = Set_Status(0) Sentence = 'SELECT RDS WITH DATE_OUT EQ ' : Quote(Oconv(ScheduleDate, 'D4/')) RList(Sentence, 5, '', '', '') EOF = False$ Loop Readnext RDSID else EOF = True$ Until EOF RDSRow = Database_Services('ReadDataRow', 'RDS', RDSID) If Error_Services('NoError') then WeekDate = Date_Services('GetISOWeekDate', ScheduleDate) WeekYear = WeekDate[1, '-'] WeekNo = WeekDate[Col2() + 1, '-'] ReactorNo = RDSRow ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 60, False$) ReactorType = ReactorRow If ReactorType EQ 'EPP' then // This is an EpiPro reactor. Check to see if has a second chamber. If so, then this is the primary // reactor. If not, then check the previous reactor to see if it references this current reactor as its // second chamber. If so then use the previous reactor to track the wafers processed. SecondChamber = ReactorRow If SecondChamber EQ '' then CompareReactorNo = ReactorNo - 2 CompareReactorRow = Database_Services('ReadDataRow', 'REACTOR', CompareReactorNo, True$, 60, False$) CompareSecondChamber = CompareReactorRow If CompareSecondChamber EQ ReactorNo then Transfer CompareReactorNo to ReactorNo end end * EpiPartNo = RDSRow EpiPartNo = Xlate('RDS', RDSID, 'EPI_PART_NO', 'X') // Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE} PerfKeyID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) If Error_Services('NoError') then WafersProcessed = RDSRow PerfRow<3> = PerfRow<3> + Iconv(WafersProcessed, 'MD2') Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$) end end Repeat If CreateReports then Reactor_Services('UpdateDailyPerformanceReport', ScheduleDate) If Mod(ScheduleDate, 7) EQ 0 then // This is a Sunday, which means the last day of a work week has been updated. Update the weekly performance // report but set the date to the previous Monday. YearWeekNo = Date_Services('GetISOWeekDate', ScheduleDate - 6) YearWeekNo = Field(YearWeekNo, '-', 1, 2) Reactor_Services('UpdateWeeklyPerformanceReport', ScheduleDate - 6) end end end service //---------------------------------------------------------------------------------------------------------------------- // ClearWafersExpected // // Clears the expected wafers for all database rows the REACTOR_PERFORMANCE table based on the indicated schedule date. //---------------------------------------------------------------------------------------------------------------------- Service ClearWafersExpected(ScheduleDate) If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ ReportData = '' Loop Readnext ReactorNo else Done = True$ Until Done ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0) ReactorType = ReactorRow SecondChamber = ReactorRow @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then * If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then @ID = ReactorNo : '****' : ScheduleDate @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) If Error_Services('NoError') then DetailPerfKeyIDs = {ALL_DETAIL_CHILD_KEY_IDS} If DetailPerfKeyIDs NE '' then For Each PerfKeyID in DetailPerfKeyIDs using @VM PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) PerfRow<2> = '' Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$) Next DetailPerfKeyID end end end Repeat end end end service //---------------------------------------------------------------------------------------------------------------------- // ClearWafersProcessed // // Clears the processed wafers for all database rows the REACTOR_PERFORMANCE table based on the indicated schedule date. //---------------------------------------------------------------------------------------------------------------------- Service ClearWafersProcessed(ScheduleDate) If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ ReportData = '' Loop Readnext ReactorNo else Done = True$ Until Done ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0) ReactorType = ReactorRow SecondChamber = ReactorRow @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then * If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then @ID = ReactorNo : '****' : ScheduleDate @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) If Error_Services('NoError') then DetailPerfKeyIDs = {ALL_DETAIL_CHILD_KEY_IDS} If DetailPerfKeyIDs NE '' then For Each PerfKeyID in DetailPerfKeyIDs using @VM PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) PerfRow<3> = '' Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$) Next DetailPerfKeyID end end end Repeat end end end service //---------------------------------------------------------------------------------------------------------------------- // CreateDailyPerformanceReport // // Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an // Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template. //---------------------------------------------------------------------------------------------------------------------- Service CreateDailyPerformanceReport(ScheduleDate) If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() DisplayDate = Oconv(ScheduleDate, 'D4/') XLSXTemplate = 'Fab Performance Daily Template.xlsx' objDocument = Excel_Services('OpenDocument', TemplatesFolder : XLSXTemplate) If Error_Services('NoError') then hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ ReportData = '' Loop Readnext ReactorNo else Done = True$ Until Done ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0) ReactorType = ReactorRow SecondChamber = ReactorRow @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then * If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then PerfKeyID = ReactorNo : '****' : ScheduleDate PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) DetailPerfKeyIDs = PerfRow<1> If DetailPerfKeyIDs NE '' then For Each @ID in DetailPerfKeyIDs using @VM @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) ReactorName = {REACTOR_NAME} EpiPartNo = {EPI_PART_NO} WafersExpected = Oconv({TOTAL_WAFERS_EXPECTED}, 'MD2') WafersExpectedRounded = Oconv({TOTAL_WAFERS_EXPECTED_ROUNDED}, 'MD2') ReportData := ReactorType : @VM : ReactorName : @VM : DisplayDate : @VM : EpiPartNo : @VM : WafersExpected : @VM : WafersExpectedRounded : @VM : ReactorNo : @FM Next DetailPerfKeyID end else ReportData := ReactorType : @VM : ReactorNo : @VM : DisplayDate : @VM : '' : @VM : '' : @VM : '' : @VM : ReactorNo : @FM end end Repeat ReportData[-1, 1] = '' ; // Strip off the last @FM ReportData = SRP_Array('SortRows', ReportData, 'AR7' : @VM : 'AL4', 'LIST', @FM, @VM) CellRow = 1 ; // Initialize the cell row to start entering data into. If ReportData NE '' then For Each ReportRow in ReportData using @FM ReactorType = ReportRow[1, @VM] ReactorName = ReportRow[Col2() + 1, @VM] DisplayDate = ReportRow[Col2() + 1, @VM] EpiPartNo = ReportRow[Col2() + 1, @VM] WafersExpected = ReportRow[Col2() + 1, @VM] WafersExpectedRounded = ReportRow[Col2() + 1, @VM] CellRow += 1 Excel_Services('SetCellValue', objDocument, 'SSR', 'A', CellRow, ReactorType) Excel_Services('SetCellValue', objDocument, 'SSR', 'B', CellRow, ReactorName) Excel_Services('SetCellValue', objDocument, 'SSR', 'E', CellRow, DisplayDate) Excel_Services('SetCellValue', objDocument, 'SSR', 'F', CellRow, EpiPartNo) Excel_Services('SetCellValue', objDocument, 'SSR', 'G', CellRow, WafersExpected) Excel_Services('SetCellValue', objDocument, 'SSR', 'H', CellRow, WafersExpectedRounded) Next ReportRow end end NewDocument = DisplayDate[7, 4] : '-' : DisplayDate[1, 2] : '-' : DisplayDate[4, 2] : ' Fab Performance.xlsx' Excel_Services('SaveDocument', objDocument, DailyReportsFolder : NewDocument) If Error_Services('NoError') then Call Send_SRP_Mail(DailyReportsFolder : NewDocument) rv = Set_Status(0) OSRead PerformanceReport from DailyReportsFolder : NewDocument then OSWrite PerformanceReport to DailyReportsFolder : NewDocument If Status() then Error_Services('Add', 'Error writing ' : DailyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status()) end end else Error_Services('Add', 'Error reading ' : DailyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status()) end end end end end service //---------------------------------------------------------------------------------------------------------------------- // UpdateDailyPerformanceReport // // Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an // Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template. //---------------------------------------------------------------------------------------------------------------------- Service UpdateDailyPerformanceReport(ScheduleDate) If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D') If ScheduleDate EQ '' then ScheduleDate = Date() DisplayDate = Oconv(ScheduleDate, 'D4/') Document = DisplayDate[7, 4] : '-' : DisplayDate[1, 2] : '-' : DisplayDate[4, 2] : ' Fab Performance.xlsx' If Excel_Services('DocumentExists', DailyReportsFolder : Document) then objDocument = Excel_Services('OpenDocument', DailyReportsFolder : Document) end else Error_Services('Add', 'Unable to find ' : Document : ' in the ' : Service : ' service.') end If Error_Services('NoError') then @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If Error_Services('NoError') then CellRow = 1 ; // Initialize the cell row to start entering data into. Loop CellRow += 1 Date = Excel_Services('GetCellValue', objDocument, 'SSR', 'E', CellRow) Until Date EQ '' ReactorName = Excel_Services('GetCellValue', objDocument, 'SSR', 'B', CellRow) ReactorNo = ReactorName[1, 'F/'] EpiPartNo = Excel_Services('GetCellValue', objDocument, 'SSR', 'F', CellRow) WeekDate = Date_Services('GetISOWeekDate', ScheduleDate) WeekYear = WeekDate[1, '-'] WeekNo = WeekDate[Col2() + 1, '-'] // Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE} @ID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) WafersProcessed = Oconv({TOTAL_WAFERS_PROCESSED}, 'MD2') WafersDelta = Oconv({TOTAL_WAFERS_DELTA}, 'MD2') WafersDeltaRounded = Oconv({TOTAL_WAFERS_DELTA_ROUNDED}, 'MD2') Excel_Services('SetCellValue', objDocument, 'SSR', 'I', CellRow, WafersProcessed) Excel_Services('SetCellValue', objDocument, 'SSR', 'K', CellRow, WafersDelta) Excel_Services('SetCellValue', objDocument, 'SSR', 'L', CellRow, WafersDeltaRounded) //Comment = Excel_Services('GetCellValue', objDocument, 'SSR', 'M', CellRow) //Excel_Services('SetCellValue', objDocument, 'SSR', 'M', CellRow, Comment) Repeat Excel_Services('SaveDocument', objDocument) If Error_Services('NoError') then Call Send_SRP_Mail(DailyReportsFolder : Document) rv = Set_Status(0) OSRead PerformanceReport from DailyReportsFolder : Document then OSWrite PerformanceReport to DailyReportsFolder : Document If Status() then Error_Services('Add', 'Error writing ' : DailyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status()) end end else Error_Services('Add', 'Error reading ' : DailyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status()) end end else ErrorMessage = Error_Services('GetMessage') end end end end service //---------------------------------------------------------------------------------------------------------------------- // CreateWeeklyPerformanceReport // // Creates weekly performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an // Excel spreadsheet using the "Fab Performance Weekly Template.xlsx" file as a template. //---------------------------------------------------------------------------------------------------------------------- Service CreateWeeklyPerformanceReport(YearWeekNo) // YearWeekNo looks like 2017-W44. For testing purposes it might be easier to pass in a date and the YearWeekNo // will be calculated. If (Num(Iconv(YearWeekNo, 'D')) AND (Iconv(YearWeekNo, 'D') NE '')) OR Num(YearWeekNo) then // A internal or external formatted date was passed in. YearWeekNo = Date_Services('GetISOWeekDate', YearWeekNo) YearWeekNo = Field(YearWeekNo, '-', 1, 2) end WeekYear = YearWeekNo[1, '-'] WeekNo = YearWeekNo[Col2() + 1, '-'] XLSXTemplate = 'Fab Performance Weekly Template.xlsx' objDocument = Excel_Services('OpenDocument', TemplatesFolder : XLSXTemplate) If Error_Services('NoError') then hReactors = Database_Services('GetTableHandle', 'REACTOR') If Error_Services('NoError') then If Error_Services('NoError') then rv = Set_Status(0) RList('SELECT REACTOR BY REACT_NO', 5, '', '', '') Done = False$ ReportData = '' Loop Readnext ReactorNo else Done = True$ Until Done ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0) ReactorType = ReactorRow SecondChamber = ReactorRow @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then * If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then PerfKeyID = ReactorNo : '**' : WeekYear : '*' : WeekNo : '*' PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0) DetailPerfKeyIDs = PerfRow<1> If DetailPerfKeyIDs NE '' then DetailPerfKeyIDs = SRP_Array('SortRows', DetailPerfKeyIDs, 'AL2', 'LIST', @VM, '*') PrevEpiPartNo = '' TotalWafersExpected = 0 TotalWafersExpectedRounded = 0 For Each @ID in DetailPerfKeyIDs using @VM @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) ReactorName = {REACTOR_NAME} EpiPartNo = {EPI_PART_NO} If (EpiPartNo NE PrevEpiPartNo) AND (PrevepiPartNo NE '') then // Epi Part No has changed. Add the current totals for the previous Epi Part No to // the report and reset the variables. ReportData := ReactorType : @VM : ReactorName : @VM : YearWeekNo : @VM : PrevEpiPartNo : @VM : TotalWafersExpected : @VM : TotalWafersExpectedRounded : @VM : ReactorNo : @FM TotalWafersExpected = 0 TotalWafersExpectedRounded = 0 end PrevEpiPartNo = EpiPartNo TotalWafersExpected += Oconv({TOTAL_WAFERS_EXPECTED}, 'MD2') TotalWafersExpectedRounded += Oconv({TOTAL_WAFERS_EXPECTED_ROUNDED}, 'MD2') Next DetailPerfKeyID // Add the final total values to the report. ReportData := ReactorType : @VM : ReactorName : @VM : YearWeekNo : @VM : PrevEpiPartNo : @VM : TotalWafersExpected : @VM : TotalWafersExpectedRounded : @VM : ReactorNo : @FM end else ReportData := ReactorType : @VM : ReactorNo : @VM : YearWeekNo : @VM : '' : @VM : '' : @VM : '' : @VM : ReactorNo : @FM end end Repeat ReportData[-1, 1] = '' ; // Strip off the last @FM ReportData = SRP_Array('SortRows', ReportData, 'AR7' : @VM : 'AL4', 'LIST', @FM, @VM) CellRow = 1 ; // Initialize the cell row to start entering data into. If ReportData NE '' then For Each ReportRow in ReportData using @FM ReactorType = ReportRow[1, @VM] ReactorName = ReportRow[Col2() + 1, @VM] YearWeekNo = ReportRow[Col2() + 1, @VM] EpiPartNo = ReportRow[Col2() + 1, @VM] WafersExpected = ReportRow[Col2() + 1, @VM] WafersExpectedRounded = ReportRow[Col2() + 1, @VM] CellRow += 1 Excel_Services('SetCellValue', objDocument, 'SSR', 'A', CellRow, ReactorType) Excel_Services('SetCellValue', objDocument, 'SSR', 'B', CellRow, ReactorName) Excel_Services('SetCellValue', objDocument, 'SSR', 'E', CellRow, YearWeekNo) Excel_Services('SetCellValue', objDocument, 'SSR', 'F', CellRow, EpiPartNo) Excel_Services('SetCellValue', objDocument, 'SSR', 'G', CellRow, WafersExpected) Excel_Services('SetCellValue', objDocument, 'SSR', 'H', CellRow, WafersExpectedRounded) Next ReportRow end end NewDocument = YearWeekNo : ' Fab Performance.xlsx' Excel_Services('SaveDocument', objDocument, WeeklyReportsFolder : NewDocument) If Error_Services('NoError') then Call Send_SRP_Mail(WeeklyReportsFolder : NewDocument) rv = Set_Status(0) OSRead PerformanceReport from WeeklyReportsFolder : NewDocument then OSWrite PerformanceReport to WeeklyReportsFolder : NewDocument If Status() then Error_Services('Add', 'Error writing ' : WeeklyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status()) end end else Error_Services('Add', 'Error reading ' : WeeklyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status()) end end end end end service //---------------------------------------------------------------------------------------------------------------------- // UpdateWeeklyPerformanceReport // // Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an // Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template. //---------------------------------------------------------------------------------------------------------------------- Service UpdateWeeklyPerformanceReport(YearWeekNo) // YearWeekNo looks like 2017-W44. For testing purposes it might be easier to pass in a date and the YearWeekNo // will be calculated. If (Num(Iconv(YearWeekNo, 'D')) AND (Iconv(YearWeekNo, 'D') NE '')) OR Num(YearWeekNo) then // A internal or external formatted date was passed in. YearWeekNo = Date_Services('GetISOWeekDate', YearWeekNo) YearWeekNo = Field(YearWeekNo, '-', 1, 2) end WeekYear = YearWeekNo[1, '-'] WeekNo = YearWeekNo[Col2() + 1, '-'] Document = YearWeekNo : ' Fab Performance.xlsx' If Excel_Services('DocumentExists', WeeklyReportsFolder : Document) then objDocument = Excel_Services('OpenDocument', WeeklyReportsFolder : Document) end else Error_Services('Add', 'Unable to find ' : Document : ' in the ' : Service : ' service.') end If Error_Services('NoError') then @DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE') If Error_Services('NoError') then CellRow = 1 ; // Initialize the cell row to start entering data into. Loop CellRow += 1 Date = Excel_Services('GetCellValue', objDocument, 'SSR', 'E', CellRow) Until Date EQ '' ReactorName = Excel_Services('GetCellValue', objDocument, 'SSR', 'B', CellRow) ReactorNo = ReactorName[1, 'F/'] EpiPartNo = Excel_Services('GetCellValue', objDocument, 'SSR', 'F', CellRow) // Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE} @ID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' @RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0) WafersProcessed = Oconv({TOTAL_WAFERS_PROCESSED}, 'MD2') WafersDelta = Oconv({TOTAL_WAFERS_DELTA}, 'MD2') WafersDeltaRounded = Oconv({TOTAL_WAFERS_DELTA_ROUNDED}, 'MD2') Excel_Services('SetCellValue', objDocument, 'SSR', 'J', CellRow, WafersProcessed) Excel_Services('SetCellValue', objDocument, 'SSR', 'K', CellRow, WafersDelta) Excel_Services('SetCellValue', objDocument, 'SSR', 'L', CellRow, WafersDeltaRounded) Repeat Excel_Services('SaveDocument', objDocument) If Error_Services('NoError') then Call Send_SRP_Mail(WeeklyReportsFolder : Document) rv = Set_Status(0) OSRead PerformanceReport from WeeklyReportsFolder : Document then OSWrite PerformanceReport to WeeklyReportsFolder : Document If Status() then Error_Services('Add', 'Error writing ' : WeeklyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status()) end end else Error_Services('Add', 'Error reading ' : WeeklyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status()) end end end end end service Service GetReactorCurrLoad(ReactNo) Response = '' ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo) LoadedCassettes = ReactStatusRec Response = LoadedCassettes end service Service GetReactorCurrLoadRDS(ReactNo) Response = '' ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo) LoadedCassettes = ReactStatusRec Response = LoadedCassettes Response = '' ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo) LoadedCassettes = ReactStatusRec Response = LoadedCassettes end service Service GetReactCurrModeRec(ReactNo) Response = '' ReactModeRecKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X') ReactModeRec = Database_Services('ReadDataRow', 'REACT_MODE_NG', ReactModeRecKey) Response = ReactModeRec end service Service GetReactCurrModeId(ReactNo) Response = '' ReactModeRecKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X') Response = ReactModeRecKey end service Service GetReactCurrModeName(ReactNo) Response = '' ReactModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo) Response = ReactModeRec end service Service GetReactModeHistory(ReactNo, DaysToReport) StartDt = Date() - DaysToReport Response = '' LegacyDate = 19749 If ( (ReactNo NE '') and (DaysToReport NE '') ) then If Date() - DaysToReport LE LegacyDate then modeArray = '' // New Modes SelectSent = 'SELECT REACT_MODE_NG WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM ' Set_Status(0) RList(SelectSent, TARGET_ACTIVELIST$, "", "", "") IF Get_Status(errCode) THEN ErrMsg(errCode) RETURN END IF @RecCount then EoF = 0 NumKeys = @RecCount Cnt = 0 Loop ReadNext Mode Else EoF = 1 until EoF RowToAdd = '' ServiceCategories = XLATE('REACT_MODE_NG', Mode, 'PROB_CAT_DESC', 'X') swap @VM with @svm in ServiceCategories ServiceDescs = XLATE('REACT_MODE_NG', Mode, 'SERV_DESC', 'X') ReactorLogID = XLATE('REACT_MODE_NG', Mode, 'START_RL_ID', 'X') StartDTM = OCONV(XLATE('REACT_MODE_NG', Mode, 'START_DTM', 'X'),'DT2/^HS') ServiceNotes = XLATE('REACTOR_LOG',ReactorLogID, REACTOR_LOG_NOTES$, 'X') swap @VM with @svm in ServiceDescs RowToAdd <1,1> = StartDTM RowToAdd <1,2> = OCONV(XLATE('REACT_MODE_NG', Mode,'ELAP_HRS','X'),'MD2,') RowToAdd <1,3> = OCONV(XLATE('REACT_MODE_NG', Mode, 'MODE', 'X' ),'[REACT_MODE_CONV]') RowToAdd <1,4> = XLATE('REACT_MODE_NG', Mode, 'START_NOTES', 'X') RowToAdd <1,5> = ServiceCategories RowToAdd <1,6> = XLATE('REACT_MODE_NG', Mode, 'START_USER', 'X') RowToAdd <1,7> = ReactorLogID RowToAdd <1,8> = ServiceDescs ServiceNotesDtms = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_DTMS$, 'X') ServiceNotesUsers = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_USERS$, 'X') ServiceNotesFormatted = '' For each ServiceNote in ServiceNotes using @VM setting vPos ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote Next ServiceNote NumNotes = DCount(ServiceNotesFormatted, @VM) // Wrap text using CRLF$ For NoteIndex = 1 to NumNotes Note = ServiceNotesFormatted<0, NoteIndex> NoteLen = Len(Note) If NoteLen GT 100 then NumLoops = Int(NoteLen/100) For LoopIndex = 1 to NumLoops Dummy = Note[LoopIndex * 100, 'F '] Loc = Col2() Note[Loc, 0] = CRLF$ Next LoopIndex ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$ end Next NoteIndex ServiceNotes = ServiceNotesFormatted Swap @VM with CRLF$ in ServiceNotes RowToAdd <1,9> = ServiceNotes modeArray := RowToAdd : @FM Repeat end GoSub ClearCursors ClearSelect TARGET_ACTIVELIST$ // Old Modes SelectSent = 'SELECT REACT_MODE WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM ' Set_Status(0) RList(SelectSent, TARGET_ACTIVELIST$, "", "", "") IF Get_Status(errCode) THEN ErrMsg(errCode) RETURN END IF @RecCount then EoF = 0 NumKeys = @RecCount Cnt = 0 Loop ReadNext Mode Else EoF = 1 until EoF RowToAdd = '' ServiceCategories = XLATE('REACT_MODE', Mode, 'PROB_CAT_DESC', 'X') swap @VM with @svm in ServiceCategories ServiceDescs = XLATE('REACT_MODE', Mode, 'SERV_DESC', 'X') ReactorLogID = XLATE('REACT_MODE', Mode, 'START_RL_ID', 'X') StartDTM = OCONV(XLATE('REACT_MODE', Mode, 'START_DTM', 'X'),'DT2/^HS') ServiceNotes = XLATE('REACTOR_LOG',ReactorLogID, REACTOR_LOG_NOTES$, 'X') swap @VM with @svm in ServiceDescs RowToAdd <1,1> = StartDTM RowToAdd <1,2> = OCONV(XLATE('REACT_MODE', Mode,'ELAP_HRS','X'),'MD2,') RowToAdd <1,3> = OCONV(XLATE('REACT_MODE', Mode, 'MODE', 'X' ),'[REACT_MODE_CONV]') RowToAdd <1,4> = XLATE('REACT_MODE', Mode, 'START_NOTES', 'X') RowToAdd <1,5> = ServiceCategories RowToAdd <1,6> = XLATE('REACT_MODE', Mode, 'START_USER', 'X') RowToAdd <1,7> = ReactorLogID RowToAdd <1,8> = ServiceDescs ServiceNotesDtms = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_DTMS$, 'X') ServiceNotesUsers = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_USERS$, 'X') ServiceNotesFormatted = '' For each ServiceNote in ServiceNotes using @VM setting vPos ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote Next ServiceNote NumNotes = DCount(ServiceNotesFormatted, @VM) // Wrap text using CRLF$ For NoteIndex = 1 to NumNotes Note = ServiceNotesFormatted<0, NoteIndex> NoteLen = Len(Note) If NoteLen GT 100 then NumLoops = Int(NoteLen/100) For LoopIndex = 1 to NumLoops Dummy = Note[LoopIndex * 100, 'F '] Loc = Col2() Note[Loc, 0] = CRLF$ Next LoopIndex ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$ end Next NoteIndex ServiceNotes = ServiceNotesFormatted Swap @VM with @SVM in ServiceNotes RowToAdd <1,9> = ServiceNotes modeArray := RowToAdd : @FM Repeat response = modeArray end end else Open 'REACT_MODE_NG' to ReactModeTable then OPEN 'DICT.REACT_MODE_NG' TO @DICT then //StartDt = OCONV(StartDt,'D4/') SelectSent = 'SELECT REACT_MODE_NG WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM ' Set_Status(0) errCode = '' RList(SelectSent, TARGET_ACTIVELIST$, "", "", "") If Not(Get_Status(errCode)) then @RecCount = 0 EOF = False$ Loop Readnext @ID else EOF = True$ While EOF EQ False$ READO @RECORD FROM ReactModeTable,@ID then @RecCount += 1 StartDTM = OCONV({START_DTM},'DT2/^HS') StopDTM = OCONV({STOP_DTM},'DT2/^HS') ElapsedHrs = OCONV({ELAP_HRS},'MD2,') Mode = OCONV({MODE},'[REACT_MODE_CONV]') StartRLID = {START_RL_ID} ProbCatIDs = {PROB_CAT_ID} ProbCatDescs = {PROB_CAT_DESC} ServIDs = {SERV_ID} ServDescs = {SERV_DESC} StartUser = {START_USER} StopUser = {STOP_USER} Notes = {START_NOTES} ServiceNotes = XLATE('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES$, 'X') ServiceNotesDtms = Xlate('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES_DTMS$, 'X') ServiceNotesUsers = Xlate('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES_USERS$, 'X') ServiceNotesFormatted = '' For each ServiceNote in ServiceNotes using @VM setting vPos ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote Next ServiceNote NumNotes = DCount(ServiceNotesFormatted, @VM) // Wrap text using CRLF$ For NoteIndex = 1 to NumNotes Note = ServiceNotesFormatted<0, NoteIndex> NoteLen = Len(Note) If NoteLen GT 100 then NumLoops = Int(NoteLen/100) For LoopIndex = 1 to NumLoops Dummy = Note[LoopIndex * 100, 'F '] Loc = Col2() Note[Loc, 0] = CRLF$ Next LoopIndex ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$ end Next NoteIndex ServiceNotes = ServiceNotesFormatted FOR I = 1 TO COUNT(ProbCatIDs,@VM) + (ProbCatIDs NE '') ProbCatDescs<1,I> = ProbCatIDs<1,I>:' - ':ProbCatDescs<1,I> NEXT I FOR I = 1 TO COUNT(ServIDs,@VM) + (ServIDs NE '') ServDescs<1,I> = ServIDs<1,I>:' - ':ServDescs<1,I> NEXT I SWAP @VM WITH CRLF$ IN ProbCatDescs SWAP @VM WITH CRLF$ IN ServDescs Swap @VM with CRLF$ in ServiceNotes Response<@RecCount, 1> = StartDTM Response<@RecCount, 2> = ElapsedHrs Response<@RecCount, 3> = Mode Response<@RecCount, 4> = Notes Response<@RecCount, 5> = ProbCatDescs Response<@RecCount, 6> = StartUser Response<@RecCount, 7> = StartRLID Response<@RecCount, 8> = ServDescs Response<@RecCount, 9> = ServiceNotes end Repeat end else ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "DICT.REACT_MODE_NG" table!' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "REACT_MODE_NG" table!' Error_Services('Add', ErrorMsg) end end end end service Service GetReactorCassLoadHistory(ReactNo, DaysToReport) Response = '' If ( (ReactNo NE '') and (DaysToReport NE '') ) then Open 'RDS' to RDSTable then OPEN 'DICT.RDS' TO @DICT then StartDt = Date() - DaysToReport SelectSent = 'SELECT RDS WITH REACTOR = ':QUOTE(ReactNo):' AND WITH DATE_IN > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND DATETIME_IN ' Set_Status(0) errCode = '' RList(SelectSent, TARGET_ACTIVELIST$, "", "", "") If Not(Get_Status(errCode)) then @RecCount = 0 EOF = False$ Loop Readnext @ID else EOF = True$ While EOF EQ False$ READO @RECORD FROM RDSTable,@ID then @RecCount += 1 RDSNo = {SEQ} DateIn = OCONV({DATETIME_IN},'DT2/^HS') DateOut = OCONV({DATETIME_OUT},'DT2/^HS') LoadOperator = {OPERATOR_IN} UnLoadOperator = {OPERATOR_OUT} Response<@RecCount, 1> = RDSNo Response<@RecCount, 2> = DateIn Response<@RecCount, 3> = DateOut Response<@RecCount, 4> = LoadOperator Response<@RecCount, 5> = UnLoadOperator end Repeat end else ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "DICT.RDS" table!' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "RDS" table!' Error_Services('Add', ErrorMsg) end end end service Service GetReactorCassLoadHistoryRange(ReactNo, StartDTM, StopDTM) Response = '' If ( (ReactNo NE '') and (StartDTM NE '') and (StopDTM NE '')) then Open 'RDS' to RDSTable then OPEN 'DICT.RDS' TO @DICT then SelectSent = 'SELECT RDS WITH REACTOR EQ ':ReactNo:' AND WITH DATETIME_IN GE ':StartDTM:' AND WITH DATETIME_IN LE ':StopDTM:' BY-DSND DATETIME_IN ' Set_Status(0) errCode = '' RList(SelectSent, TARGET_ACTIVELIST$, "", "", "") If Not(Get_Status(errCode)) then @RecCount = 0 EOF = False$ Loop Readnext @ID else EOF = True$ While EOF EQ False$ READO @RECORD FROM RDSTable,@ID then @RecCount += 1 RDSNo = {SEQ} DateIn = OCONV({DATETIME_IN},'DT2/^HS') DateOut = OCONV({DATETIME_OUT},'DT2/^HS') LoadOperator = {OPERATOR_IN} UnLoadOperator = {OPERATOR_OUT} Response<@RecCount, 1> = RDSNo Response<@RecCount, 2> = DateIn Response<@RecCount, 3> = DateOut Response<@RecCount, 4> = LoadOperator Response<@RecCount, 5> = UnLoadOperator end Repeat end else ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "DICT.RDS" table!' Error_Services('Add', ErrorMsg) end end else ErrorMsg = 'Unable to Open "RDS" table!' Error_Services('Add', ErrorMsg) end end end service Service IncrementCycleCount(ToolID) If ToolID NE '' then // A reactor number may be passed in. Convert it to the corresponding tool ID if necessary. If Num(ToolID) then ToolID = 'R':ToolID ToolRec = Database_Services('ReadDataRow', 'TOOL', ToolID) If Error_Services('NoError') then CycleCnt = ToolRec CycleCnt += 1 ToolRec = CycleCnt Database_Services('WriteDataRow', 'TOOL', ToolID, ToolRec, True$, False$, True$) end end end service Service CreateReactModeChange(UserID, ReactNo, Mode, ModeSubCat, ModeText, ForceModeChange) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ReactorModeChg' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Mode Change Log.csv' Headers = 'Logging DTM' : @FM : 'Notes' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, '', False$, False$, True$) LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM ErrorMsg = '' IF ForceModeChange NE True$ then ForceModeChange = False$ If ( (UserID NE '') and (ReactNo NE '') and (Mode NE '') and (ModeSubCat NE '')) then CurTime = Time() CurDate = Date() NGPrevModeKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X')<1, 1> PrevModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo) SelectedModeRec = Database_Services('ReadDataRow', 'REACTOR_MODES', Mode) SelE10State = SelectedModeRec CommentException = False$ Begin Case Case PrevModeRec EQ 'WAITING_FOR_MAINTENANCE_UNSCHEDULED' AND Mode EQ 'MAINTENANCE_UNSCHEDULED' CommentException = True$ Case PrevModeRec EQ 'WAITING_FOR_MAINTENANCE_SCHEDULED' AND Mode EQ 'MAINTENANCE_SCHEDULED' CommentException = True$ Case PrevModeRec EQ 'WAITING_FOR_ENGINEER_UNSCHEDULED' AND Mode EQ 'ENGINEERING_INVESTIGATION' CommentException = True$ Case PrevModeRec EQ 'WAITING_FOR_ENGINEER_SCHEDULED' AND Mode EQ 'ENGINEERING_DEVELOPMENT' CommentException = True$ Case PrevModeRec EQ 'WAITING_FOR_ENGTECH_UNSCHEDULED' AND (Mode EQ 'TROUBLESHOOT_ENGTECH' OR Mode EQ 'ENGINEERING_INVESTIGATION') CommentException = True$ Case PrevModeRec EQ 'WAITING_FOR_ENGTECH_SCHEDULED' AND Mode EQ 'ENGINEERING_DEVELOPMENT' CommentException = True$ End Case If ((ModeText NE '') and (Len(ModeText) GE 4)) OR CommentException then NewModeCategory = SelectedModeRec OldRlRecordKey = PrevModeRec If Reactor_Log_Services('IsMaint', OldRlRecordKey) AND ForceModeChange EQ False$ then If (NOT(Reactor_Log_Services('IsSigned', OldRlRecordKey))) then ErrorMsg = 'The current mode cannot be changed until the technician has signed off on the Reactor Log.' end end ModeSubCatID = '' Locate ModeSubCat in SelectedModeRec using @VM setting SvcPos then NewModeSvcList = SelectedModeRec ModeSubCatID = NewModeSvcList<1,SvcPos> end else ErrorMsg = 'Failed to locate ModeSubCat.' end CurrentMode = PrevModeRec ActiveProveInPreventsModeChange = Reactor_Services('ActiveProveInPreventsModeChange', ReactNo, Mode, CurrentMode) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end else If ActiveProveInPreventsModeChange EQ True$ then ErrorMsg = 'A reactor prove in is required before changing the mode. Active prove in types: ' TypeList = '' ProveInTypes = Reactor_Services('GetActiveProveInTypes', ReactNo) for each ProveInType in ProveInTypes using @VM setting Idx If Idx GT 1 then TypeList := ', ' end TypeList := ProveInType Next ProveInType ErrorMsg := TypeList end end IdleStartupRequired = Reactor_Services('GetIdleStartupRequired', ReactNo) If ErrorMsg EQ '' and IdleStartupRequired and Mode[1, 2] EQ 'UP' then ProveInTypes = Reactor_Services('GetActiveProveInTypes', ReactNo) IdleStartupActive = False$ For each ProveInType in ProveInTypes using @VM setting Idx If ProveInType EQ 'IDLE' then IdleStartupActive = True$ end Next ProveInType If IdleStartupActive EQ True$ then ErrorMsg = "You must complete the IDLE_STARTUP prove in checklist before putting the reactor UP." end else ErrorMsg = "An IDLE_STARTUP prove in checklist is required before putting the reactor UP. Change the mode to IDLE_STARTUP, then complete the checklist." end end If ErrorMsg EQ '' then ActiveHgCVChecklists = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, 'IQS_HGCV_ALARM') HgCVChecklistActive = (ActiveHgCVChecklists NE '') If ( HgCVChecklistActive and (SelE10State _EQC 'Productive') ) then ErrorMsg = "An HgCV OCAP Checklist is active for this reactor and must be completed or overridden in order to change to a productive state." end end If ErrorMsg EQ '' then IntrMaintFeatureFlag = Xlate('FEATURE_FLAGS', 'NICA_INTRUSIVE_MAINTENANCE', FEATURE_FLAGS.ENABLED$, 'X') If IntrMaintFeatureFlag EQ True$ then ActiveIntrusiveMaintChecklists = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, 'INTRUSIVE_MAINT') IntrusiveMaintChecklistActive = (ActiveIntrusiveMaintChecklists NE '') If ( IntrusiveMaintChecklistActive and (SelE10State _EQC 'Productive') ) then ErrorMsg = "An Intrusive Maintenance Checklist is active for this reactor and must be completed or overridden in order to change to a productive state." end end end If ErrorMsg EQ '' then If Len(Mode) GT 10 and Mode[1, 10] EQ 'CHANGEOVER' then Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'CHANGEOVER') end If Mode EQ 'INITIATE_IDLE' then Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'INITIATE_IDLE') end If Mode EQ 'IDLE_STARTUP' then Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'IDLE') end end If ErrorMsg EQ '' then //Log the current Mode Change LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM LogData<2> = 'Reactor No: ' : ReactNo : ' - Requested Mode Change: ' : Mode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) OldReactUtilID = PrevModeRec if OldReactUtilID NE '' then OldReactUtilRec = Database_Services('ReadDataRow', 'REACT_UTIL', OldReactUtilID) OldReactUtilRec = CurDate OldReactUtilRec = CurTime OldReactUtilRec = UserId Database_Services('WriteDataRow', 'REACT_UTIL', OldReactUtilID, OldReactUtilRec) end If Error_Services('NoError') then ********************************************************************************** * WRITE OUT NEW MODE INFORMATION //Create new React_Util record NewRUKey = NextKey('REACT_UTIL') If Error_Services('NoError') then NewRLKey = NextKey('REACTOR_LOG') If Error_Services('NoError') then RUtilRec = '' RUtilRec = ReactNo RUtilRec = ModeText RMode = '' RUtilRec = Mode RUtilRec = CurDate RUtilRec = CurTime RUtilRec = UserID RUtilRec = NewRLKey // Get current work order from the CONFIG table DailySchedName = 'WO_DAILY_SCHED':ReactNo DSR = XLATE('CONFIG', DailySchedName, '', 'X') WOCust = DSR WorkOrder = Field(WOCust, ' ', 1) RUtilRec = WorkOrder RUtilRec = xlate( 'WO_LOG', WorkOrder, wo_log_cust_no$, 'X' ) ; ******************************************************************************************************** //Create a new Reactor_Log Entry EntryId = UserID RLRec = '' RLRec = CurDate RLRec = CurTime RLRec = ReactNo if NewModeCategory EQ 'MAINTENANCE' then RLRec = 'M' ;* for maintenance end RLRec = UserID RLRec = CurDate RLRec = NewRUKey RLRec = ModeSubCatID Database_Services('WriteDataRow', 'REACTOR_LOG', NewRLKey, RLRec) If Error_Services('NoError') then Database_Services('WriteDataRow', 'REACT_UTIL', NewRUKey, RUtilRec) If Error_Services('NoError') then Rec = '' Rec = Mode Rec = oconv( UserID, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ) Rec = oconv( CurDate, 'D4/' ) Rec = oconv( CurTime, 'MTH' ) Rec = NewRUKey Rec = NewRLKey Rec = ModeSubCat Rec = ModeText CurrDTM = Rec:" ":Rec NGPrevModeDTM = Field(NGPrevModeKey, '*', 2) PrevModeKey = NGPrevModeKey OldMode = OCONV(XLATE('REACTOR',ReactNo,'CURR_MODE','X'),'[REACT_MODE_CONV]') OpenDTM = FIELD(PrevModeKey,'*',2) OpenDTM = OCONV(OpenDTM,'DT4/^S') Mode = Rec RecName = 'REACT_MODE':ReactNo * * * * * Changes by JCH on 11/5/2007 * * * * * ProdModes = 'Production':@VM ProdModes := 'Production (incr sampling)':@VM ProdModes := 'UP_WITH_RESTRICTIONS':@VM ProdModes := 'UP':@VM ProdModes := 'UP_WITH_INCREASED_SAMPLING':@VM ProdModes := 'UP_WITH_INCREASED_SAMPLING_SAMPLING':@VM ProdModes := 'UP_WITH_INCREASED_SAMPLING_METROLOGY':@VM ProdModes := 'UP_NOT_RUNNING':@VM LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM LogData<2> = 'Reactor No: ' : ReactNo : ' - Current Mode: ' : OldMode : ' - New Mode: ' : Mode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) LOCATE OldMode IN ProdModes USING @VM SETTING DUMMY THEN LOCATE Mode IN ProdModes USING @VM SETTING DUMMY ELSE OutOfProdDTM = Rec:' ':Rec obj_React_Status('SetOutOfProdDTM',ReactNo:@RM:OutOfProdDTM) IF Get_Status(errCode) THEN ErrorMsg = errCode END ;* End of check on New Mode END ;* End of check on Current Mode * * * End of changes * * * * * //Write new mode info to config table. OrigConfigRec = Database_Services('ReadDataRow', 'CONFIG', RecName) Database_Services('WriteDataRow', 'CONFIG', RecName, Rec) If Error_Services('NoError') then IF OldMode NE '' THEN crParms = ReactNo crParms := @RM:OpenDTM crParms := @RM:CurrDTM crParms := @RM:UserID crParms := @RM:Rec crParms := @RM:Rec crParms := @RM:Rec LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM LogData<2> = 'Reactor No: ' : ReactNo : ' - obj_React_Mode("Close") - Key ID: ' : ReactNo : '*' : Iconv(OpenDTM, 'DT') Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) obj_React_Mode('Close',crParms) ;* Close the currently active mode END If Not(Get_Status(errCode)) then crParms = ReactNo crParms := @RM:CurrDTM crParms := @RM:UserID crParms := @RM:Mode crParms := @RM:Rec crParms := @RM:Rec crParms := @RM:Rec crParms := @RM:ModeSubCat LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM LogData<2> = 'Reactor No: ' : ReactNo : ' - obj_React_Mode("Create") - Key ID: ' : ReactNo : '*' : Iconv(CurrDTM, 'DT') Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) obj_React_Mode('Create',crParms) ;* Create new active mode record IF Get_Status(errCode) THEN // Failed to create new react mode ErrorMsg = errCode GoSub RollbackReactUtil // Delete new REACTOR_LOG record Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey) // Delete new REACT_UTIL record Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey) // Rollback CONFIG record Database_Services('WriteDataRow', 'CONFIG', RecName, OrigConfigRec) // Reopen previous react mode Database_Services('WriteDataRow', 'REACT_MODE_NG', NGPrevModeKey, PrevModeRec) end else // Check to see if notifications are active for this mode If SelectedModeRec then //If notifications are active get the classes from the REACTOR_MODE record SendToClasses = SelectedModeRec For each class in SendToClasses using @VM //Send to all the classes notesParms = '' IncludeNextShift = False$ //If we are close to shift change we want to add in the next shift. CurrTime = Time() if SRP_Time('Hour', CurrTime) EQ 17 OR SRP_Time('Hour', CurrTime) EQ 5 then IncludeNextShift = True$ end Recipients = LSL_USERS_SERVICES('GetOnShiftUsersByClass', class, IncludeNextShift); *Get all the on shift recipients SentFrom = 'OI_ADMIN' Subject = 'Reactor Mode Notification - ': ReactNo : ' ' : Mode Message = 'Reactor: ' :ReactNo: ' has been placed into ' : Mode :'.' Message := CRLF$ : 'Sub-Category: ' : ModeSubCat Message := CRLF$ : 'User: ' : UserID Message := CRLF$ : 'Notes: ' Message := CRLF$ : ModeText AttachWindow = '' AttachKey = '' SendToGroup = '' notesParms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup Obj_Notes('Create', notesParms) Next class end // If new mode sub category is an ABORT/ALARM or particular Facilities Failure, then apply abort metrology to the oldest loaded RDS ReactType = Xlate('REACTOR', ReactNo, 'REACT_TYPE', 'X') If ReactType NE 'EPP' then Begin Case Case ModeSubCat _EQC 'ABORT/ALARM - TC Failure' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Contactor Not Sensed On' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Temp Up Failure' ApplyAbortMet = True$ Case ModeSubCat _EQC 'Gas Delivery Issue' ApplyAbortMet = True$ Case ModeSubCat _EQC 'Toxic Gas Alarm' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Facilities Level Failure' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Exhaust System Failure (Scrubber Toxic)' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - TCS' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - Dopant' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - Hydrogen' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Susceptor Faults' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - 24V. Interlock Abort' ApplyAbortMet = True$ Case ModeSubCat _EQC 'ABORT/ALARM - Wafer Handling' ApplyAbortMet = True$ Case Otherwise$ ApplyAbortMet = False$ End Case If ApplyAbortMet then LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ReactorAborts' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Reactor Abort Log.csv' Headers = 'Logging DTM' : @FM : 'ReactorNo' : @FM : 'Notes' objAbortLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, '', False$, False$, True$) LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM LogMsg = 'Intermediate or Major ABORT/ALARM mode sub category, ':ModeSubCat:'. ' LogMsg := 'Attempting to apply abort metrology to loaded RDS.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) // Get the loaded RDS key(s) and apply abort metrology. If two are loaded, select the one loaded first. LoadedRdsKeys = Xlate('REACT_STATUS', ReactNo, 'LOAD_RDS', 'X') If LoadedRdsKeys NE '' then AbortRds = '' Begin Case Case DCount(LoadedRdsKeys, @VM) EQ 2 // Select the oldest one LoadDtms = Xlate('RDS', LoadedRdsKeys, 'DATETIME_IN', 'X') If LoadDtms<0, 2> GT LoadDtms<0, 1> then AbortRds = LoadedRdsKeys<0, 1> end else AbortRds = LoadedRdsKeys<0, 2> end Swap @VM with ' ' in LoadedRdsKeys LogMsg = 'Two loaded RDS keys, ':LoadedRdsKeys:', found in REACT_STATUS record.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) LogMsg = 'Selecting RDS ':AbortRDS:' as it was loaded earlier.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) Case DCount(LoadedRdsKeys, @VM) EQ 1 // Only one loaded, so use that AbortRds = LoadedRdsKeys LogMsg = 'One loaded RDS key, ':AbortRds:', found in REACT_STATUS record.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) Case Otherwise$ // Unexpected condition - log error Swap @VM with ' ' in LoadedRdsKeys LogMsg = 'Error selecting RDS to apply abort metrology to. Loaded RDS keys, ':LoadedRdsKeys:', found in REACT_STATUS record.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) End Case If AbortRds NE '' then LogMsg = 'Attempting to apply abort metrology to RDS ':AbortRds:'.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) Rds_Services('ApplyAbortMetrology', AbortRds) If Error_Services('NoError') then LogMsg = 'Successfully applied abort metrology to RDS ':AbortRds:'.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Error occurred while applying abort metrology to RDS ':AbortRds:'. Error message: ':ErrorMsg LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) end end end else // No loaded RDS runs detected LogMsg = 'No loaded RDS keys found in REACT_STATUS record.' LogData = '' LogData<1> = LoggingDtm LogData<2> = ReactNo LogData<3> = LogMsg Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM) end end end end end else // Failed to close previous react mode ErrorMsg = errCode GoSub RollbackReactUtil // Delete new REACTOR_LOG record Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey) // Delete new REACT_UTIL record Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey) // Rollback CONFIG record Database_Services('WriteDataRow', 'CONFIG', RecName, OrigConfigRec) end END ELSE ErrorMsg = 'Reactor No: ' : ReactNo : 'Unable to write ':RecName:' on CONFIG table...' : ReactNo : '*' : Iconv(CurrDTM, 'DT') LogData = '' LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM LogData<2> = ErrorMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) GoSub RollbackReactUtil // Delete new REACTOR_LOG record Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey) // Delete new REACT_UTIL record Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey) end end else // Failed to write REACT_UTIL record ErrorMsg = Error_Services('GetMessage') GoSub RollbackReactUtil // Delete new REACTOR_LOG record Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey) end end else // Failed to write REACTOR_LOG record ErrorMsg = Error_Services('GetMessage') GoSub RollbackReactUtil end end else // Failed to get new REACTOR_LOG key ErrorMsg = Error_Services('GetMessage') GoSub RollbackReactUtil end end else // Failed to get new REACT_UTIL key ErrorMsg = Error_Services('GetMessage') GoSub RollbackReactUtil end end else ErrorMsg = Error_Services('GetMessage') end end end else Begin Case Case ModeText EQ '' ErrorMsg = 'You must enter a comment.' Case Len(ModeText) LT 5 ErrorMsg = 'Comments must be more than 4 characters...' End Case end end else Begin Case Case UserID EQ '' ErrorMsg = 'Null UserID passed into service.' Case ReactNo EQ '' ErrorMsg = 'You must choose a Reactor.' Case Mode EQ '' ErrorMsg = 'You must choose a VALID Reactor Mode.' Case ModeSubCat EQ '' ErrorMsg = 'You must choose a VALID Reactor Problem Category.' End Case end If ErrorMsg EQ '' then Response = True$ end else Error_Services('Add', 'Error in ':Service:' service. ':ErrorMsg) Response = False$ end end service Service FormatReactStatusSingle(ReactNo) Response = '' CurrModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo) CurrLoadings = Reactor_Services('GetReactorCurrLoad', ReactNo) ReactStatusArray = CurrModeRec ReactStatusArray<12> = CurrLoadings; *Currently loaded cassettes Response = ReactStatusArray end service Service GetSingleReactStatusJson(reactNo) response = '' // Create the root object JSON If SRP_Json(objReactor, "New") then // Create the array of reactors If SRP_Json(objReactorArray, "New", "Array") then ReactStatusArray = Reactor_Services('FormatReactStatusSingle', reactNo) CurrE10State = Xlate('REACTOR_MODES', ReactStatusArray, REACTOR_MODES_E10_STATE$, 'X') ModeIconName = Xlate('REACTOR_MODES', ReactStatusArray, REACTOR_MODES_ICON$, 'X') RunningStatus = false$ CurrLoad = Reactor_Services('GetReactorCurrLoad', ReactNo) CurrSubCat = ReactStatusArray if CurrLoad NE '' then RunningStatus = true$ end objSingleReactor = '' If SRP_Json(objSingleReactor, "New") then SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorNumber', reactNo, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorMode', ReactStatusArray, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'E10State', CurrE10State, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeIconName', ModeIconName, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'IsRunning', RunningStatus, 'BOOLEAN') SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeSubCat', CurrSubCat, 'STRING') SRP_Json(objReactorArray, "Add", objSingleReactor) SRP_Json(objSingleReactor, "Release") end // Now add the array as a member of the root object SRP_Json(objReactor, "Set", "reactors", objReactorArray) // All done with the array object SRP_Json(objReactorArray, "Release") end // Now get the actual JSON resultingJSON = SRP_Json(objReactor, "Stringify", "STYLED") // All done with the root object SRP_Json(objReactor, "Release") end response = resultingJSON end service Service GetAllReactStatusJson() Response = '' AllReactNos = Reactor_Services('GetReactorNumbers') //Create the root objec JSON If SRP_Json(objReactor, "New") then //Create the array of reactors If SRP_Json(objReactorArray, "New", "Array") then //Loop through all reactor nums and add to the array for each reactNo in AllReactNos using @FM if reactNo NE 'Cln' OR reactNo NE '140' then ReactStatusArray = Reactor_Services('FormatReactStatusSingle', reactNo) CurrE10State = Xlate('REACTOR_MODES', ReactStatusArray, REACTOR_MODES_E10_STATE$, 'X') ModeIconName = Xlate('REACTOR_MODES', ReactStatusArray, REACTOR_MODES_ICON$, 'X') RunningStatus = false$ CurrLoad = Reactor_Services('GetReactorCurrLoad', ReactNo) if CurrLoad NE '' then RunningStatus = true$ end If SRP_Json(objSingleReactor, "New") then SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorNumber', reactNo, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorMode', ReactStatusArray, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'E10State', CurrE10State, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeIconName', ModeIconName, 'STRING') SRP_JSON(objSingleReactor, 'SETVALUE', 'IsRunning', RunningStatus, 'BOOLEAN') SRP_Json(objReactorArray, "Add", objSingleReactor) SRP_Json(objSingleReactor, "Release") end end Next reactNo // Now add the array as a member of the root object SRP_Json(objReactor, "Set", "reactors", objReactorArray) // All done with the array object SRP_Json(objReactorArray, "Release") end // Now get the actual JSON resultingJSON = SRP_Json(objReactor, "Stringify", "STYLED") // All done with the root object SRP_Json(objReactor, "Release") end response = resultingJSON end service Service IsReactorLoaded(ReactNo) ErrorMsg = '' Response = False$ If ReactNo NE '' then LoadedRDS = Xlate('REACT_STATUS', ReactNo, 'LOAD_RDS', 'X') If LoadedRDS NE '' then Response = True$ end else ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service GetReactorTimeSinceUnload(ReactNo) ErrorMsg = '' Response = 0 If ReactNo NE '' then LastUnloadTime = Xlate('REACT_STATUS', ReactNo, 'UNLOAD_DTM', 'X') Response = SRP_DateTime("MinuteSpan", LastUnloadTime, Datetime(), 0) end else ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service ConvertRecordToJSON(ReactorNo, ItemURL, CurrUser, FullObject=BOOLEAN) If FullObject EQ '' then FullObject = True$ ErrorMsg = '' JSON = '' If ReactorNo then objJSON = '' If SRP_JSON(objJSON, 'New', 'Object') then // Add in reactor current mode, available modes, and available sub categories. CurrModeKey = Reactor_Services('GetReactCurrModeId', ReactorNo) CurrMode = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_MODE$, 'X') ServiceDesc = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_SERVICE_DESC$, 'X') If (CurrUser NE '') then AvailModes = Reactor_Modes_Services('AvailableModes', CurrMode, CurrUser) CurrRLKey = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_START_RL_ID$ , 'X') ReactorType = Xlate('REACTOR', ReactorNo, 'REACT_TYPE', 'X') ReactAssign = Xlate('REACTOR', ReactorNo, 'REACT_ASSIGNMENT', 'X') React_Assign_Conv('OCONV', ReactAssign, '', ReactAssign) // Create reactor object If SRP_JSON(objReactor, 'New', 'Object') then SRP_JSON(objReactor, 'SetValue', 'reactorNo', ReactorNo) SRP_JSON(objReactor, 'SetValue', 'reactType', ReactorType) SRP_JSON(objReactor, 'SetValue', 'reactAssignment', ReactAssign) PickPlace = Xlate('REACTOR', ReactorNo, 'PICK_PLACE', 'X') SRP_JSON(objReactor, 'SetValue', 'pickPlace', PickPlace, 'Boolean') LLDisabledKey = Xlate('REACTOR', ReactorNo, 'ACTIVE_LL_DISABLED', 'X') LoadLockDisabled = Xlate('REACT_LL', LLDisabledKey, 'DISABLED', 'X') SRP_JSON(objReactor, 'SetValue', 'loadLockDown', LoadLockDisabled) SRP_JSON(objReactor, 'SetValue', '0311Active', Xlate('REACTOR', ReactorNo, '0311_ACTIVE', 'X'), 'Boolean') SRP_JSON(objReactor, 'SetValue', 'active0311Checklist', Xlate('REACTOR', ReactorNo, '0311_ACTIVE', 'X'), 'Boolean') SRP_JSON(objReactor, 'SetValue', 'TubeBellJarCnt', Xlate('REACTOR', ReactorNo, REACTOR_TUBE_BELL_JAR_THK$, 'X')) SRP_JSON(objReactor, 'SetValue', 'TubeBellJarThk', Xlate('REACTOR', ReactorNo, REACTOR_TUBE_BELL_JAR_WFR_CNT$, 'X')) SRP_JSON(objReactor, 'SetValue', 'SusceptorCnt', Xlate('REACTOR', ReactorNo, REACTOR_SUSC_WFR_CNT$, 'X')) SRP_JSON(objReactor, 'SetValue', 'SusceptorThk', Xlate('REACTOR', ReactorNo, REACTOR_SUSC_THK$, 'X')) SRP_JSON(objReactor, 'SetValue', 'LowerQuartzCnt', Xlate('REACTOR', ReactorNo, REACTOR_LOWER_QUARTZ_WFR$, 'X')) SRP_JSON(objReactor, 'SetValue', 'LowerQuartzThk', Xlate('REACTOR', ReactorNo, REACTOR_LOWER_QUARTZ_THK$, 'X')) SRP_JSON(objReactor, 'SetValue', 'ArmsCnt', Xlate('REACTOR', ReactorNo, REACTOR_ARMS_WFR_CNT$, 'X')) // Add Current Run Status (Current Loaded Cassettes) LoadedRDS = Xlate('REACT_STATUS', ReactorNo, 'LOAD_RDS', 'X') If LoadedRDS NE '' then objLoadedRDS = '' If SRP_JSON(objLoadedRDS, 'New', 'Array') then For each RDS in LoadedRDS using @VM setting vPos SRP_JSON(objLoadedRDS, 'AddValue', RDS) Next RDS SRP_JSON(objReactor, 'Set', 'loadedRDS', objLoadedRDS) SRP_JSON(objLoadedRDS, 'Release') end end else SRP_JSON(objReactor, 'SetValue', 'loadedRDS', '') end // Add new reactor items here InstItems = Xlate('REACTOR', ReactorNo, REACTOR_CURR_INST_ITEMS$, 'X') If InstItems NE '' then objInstItems = '' If SRP_JSON(objInstItems, 'New', 'Array') then For each Item in InstItems using @VM setting vPos swap '*' with @VM in Item SRP_JSON(objInstItems, 'AddValue', Item<1, 2>) Next Item SRP_JSON(objReactor, 'Set', 'installedReactItems', objInstItems) SRP_JSON(objInstItems, 'Release') end end else SRP_JSON(objReactor, 'SetValue', 'installedReactItems', '') end // Add Current Run Status (Is running) ReactorRunning = (LoadedRDS NE '') SRP_JSON(objReactor, 'SetValue', 'isRunning', ReactorRunning, 'Boolean') // Add Out of prod time OutofProdDTM = Xlate('REACT_STATUS', ReactorNo, 'OUT_OF_PROD_DTM', 'X') SRP_JSON(objReactor, 'SetValue', 'outOfProdDTM', OConv(OutofProdDTM, 'DT2/^H')) If FullObject then // Add Last Unload Time LastUnloadDTM = Xlate('REACT_STATUS', ReactorNo, 'UNLOAD_RDS_DTM', 'X') SRP_JSON(objReactor, 'SetValue', 'unloadDTM', OConv(LastUnloadDTM, 'DT2/^H')) // Add Last Load Time LastLoadDTM = Xlate('REACT_STATUS', ReactorNo, 'LOAD_RDS_DTM', 'X') LastLoadDTM = LastLoadDTM[-1, 'B':@VM] SRP_JSON(objReactor, 'SetValue', 'loadDTM', OConv(LastLoadDTM, 'DT2/^H')) // Add Last Reactor Readings LastReadWfrsDTM = Xlate('REACTOR', ReactorNo, 'LAST_READ_WFRS_DTM', 'X') LastReadWfrs = Xlate('REACT_READS', ReactorNo:'*':LastReadWfrsDTM, 'WAFER_CNT', 'X') SRP_JSON(objReactor, 'SetValue', 'lastReadWafersDTM', OConv(LastReadWfrsDTM, 'DT2/^H')) SRP_JSON(objReactor, 'SetValue', 'lastReadWafers', LastReadWfrs) end // Add work order object SchedConfigRec = Database_Services('ReadDataRow', 'CONFIG', 'WO_DAILY_SCHED':ReactorNo) WorkOrderCust = SchedConfigRec CurrWorkOrder = Field(WorkOrderCust, ' ', 1) SRP_JSON(objReactor, 'SetValue', 'workOrder', CurrWorkOrder) WOHotStatus = Xlate('WO_LOG', CurrWorkOrder, 'HOT_FLAG', 'X') SRP_JSON(objReactor, 'SetValue', 'workOrderHotStatus', WOHotStatus) WOCustomer = Field(WorkOrderCust, ' ', 2) SRP_JSON(objReactor, 'SetValue', 'workOrderCustomer', WOCustomer) If FullObject then JSONWorkOrder = Work_Order_Services('ConvertRecordToJSON', CurrWorkOrder) objWorkOrder = '' If SRP_JSON(objWorkOrder, 'Parse', JSONWorkOrder) EQ '' then objTemp = SRP_JSON(objWorkOrder, 'Get', 'workOrder') SRP_JSON(objReactor, 'Set', 'workOrder', objTemp) SRP_JSON(objTemp, 'Release') SRP_JSON(objWorkOrder, 'Release') end end // Reactor Mode object/properties If FullObject then // Add reactor mode object JSONReactorMode = React_Mode_NG_Services('ConvertRecordToJSON', CurrModeKey, '', CurrUser) objReactorMode = '' If SRP_JSON(objReactorMode, 'Parse', JSONReactorMode) EQ '' then objTemp = SRP_JSON(objReactorMode, 'Get', 'reactorMode') SRP_JSON(objReactor, 'Set', 'reactorMode', objTemp) SRP_JSON(objTemp, 'Release') SRP_JSON(objReactorMode, 'Release') end end else CurrMode = Xlate('REACT_MODE_NG', CurrModeKey, 'MODE', 'X') SubCat = Xlate('REACT_MODE_NG', CurrModeKey, 'SERVICE_DESC', 'X') E10State = Xlate('REACTOR_MODES', CurrMode, 'E10_STATE', 'X') SRP_JSON(objReactor, 'SetValue', 'currMode', CurrMode) SRP_JSON(objReactor, 'SetValue', 'serviceDesc', SubCat) SRP_JSON(objReactor, 'SetValue', 'e10State', E10State) end If Not(FullObject) then // Add reactor log properties CurrRlKey = Xlate('REACTOR', ReactorNo, 'CURR_MODE_RL_ID', 'X') If CurrRLKey NE '' then RlChecklistActive = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_ACTIVE', 'X') SRP_JSON(objReactor, 'SetValue', 'reactorLogChecklistActive', RlChecklistActive, 'Boolean') If RlChecklistActive then RlChecklistTypes = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_TYPE', 'X') RlChecklistOrderIds = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_ORDER_ID', 'X') objRlChecklistArray = '' If SRP_JSON(objRlChecklistArray, 'New', 'Array') then objChecklist = '' For each RlChecklistType in RlChecklistTypes using @VM setting vPos If SRP_JSON(objChecklist, 'New', 'Object') then SRP_JSON(objChecklist, 'SetValue', 'reactorLogChecklistType', RlChecklistType) RlChecklistOrderId = RlChecklistOrderIds<0, vPos> SRP_JSON(objChecklist, 'SetValue', 'reactorLogChecklistOrderId', RlChecklistOrderId) SRP_JSON(objRlChecklistArray, 'Add', objChecklist) SRP_JSON(objChecklist, 'Release') end Next RlChecklistType SRP_JSON(objReactor, 'Set', 'reactorLogChecklists', objRlChecklistArray) SRP_JSON(objRlChecklistArray, 'Release') end end end // Add prove in checklist properties PiChecklistActive = Xlate('REACTOR', ReactorNo, 'PROVE_IN_ACTIVE', 'X') SRP_JSON(objReactor, 'SetValue', 'proveInChecklistActive', PiChecklistActive, 'Boolean') If PiChecklistActive then PiTypes = Xlate('REACTOR', ReactorNo, 'PROVE_IN_TYPE', 'X') PiChecklistOrderIds = Xlate('REACTOR', ReactorNo, 'PROVE_IN_ORDER_ID', 'X') objPiChecklistArray = '' If SRP_JSON(objPiChecklistArray, 'New', 'Array') then objProveIn = '' For each PiType in PiTypes using @VM setting vPos If SRP_JSON(objProveIn, 'New', 'Object') then SRP_JSON(objProveIn, 'SetValue', 'proveInType', PiType) PiChecklistOrderId = PiCheckListOrderIds<0, vPos> SRP_JSON(objProveIn, 'SetValue', 'proveInOrderId', PiChecklistOrderId) SRP_JSON(objPiChecklistArray, 'Add', objProveIn) SRP_JSON(objProveIn, 'Release') end Next PiType SRP_JSON(objReactor, 'Set', 'proveInChecklists', objPiChecklistArray) SRP_JSON(objPiChecklistArray) end end end If itemURL NE '' then // The itemURL was passed in so add HAL+JSON properties. objLinks = '' // Create the _links property and then all link objects needed for this resource. If SRP_JSON(objLinks, 'New', 'Object') then // Create a self link. objLink = '' If SRP_JSON(objLink, 'New', 'Object') then SRP_JSON(objLink, 'SetValue', 'href', ItemURL, 'String') SRP_JSON(objLink, 'SetValue', 'title', 'Self', 'String') SRP_JSON(objLinks, 'Set', 'self', objLink) SRP_JSON(objLink, 'Release') end SRP_JSON(objReactor, 'Set', '_links', objLinks) SRP_JSON(objLinks, 'Release') end // Create the _class property for this resource. SRP_JSON(objReactor, 'SetValue', '_class', 'resource') end SRP_JSON(objJSON, 'Set', 'reactor', objReactor) SRP_JSON(objReactor, 'Release') end JSON = SRP_JSON(objJSON, 'Stringify', 'Styled') SRP_JSON(objJSON, 'Release') end else ErrorMsg = 'Error in ':Service:' service. Error creating JSON object.' end end else ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.' end If ErrorMsg EQ '' then Response = JSON end else Error_Services('Add', ErrorMsg) end end service Service ConvertJSONToRecord(KeyID, JSON) Record = '' If JSON NE '' then If SRP_JSON(objJSON, 'Parse', JSON) EQ '' then objReactor = SRP_JSON(objJSON, 'Get', 'reactor') Record = Database_Services('ReadDataRow', 'REACTOR', KeyID) If Error_Services('NoError') then // Add code to update additional columns as needed. // If property is "" then clear the field. // If property is null then do not update it. NewVal = SRP_JSON(objReactor, 'GetValue', '0311Active') If NewVal NE 'null' then Record = NewVal end end SRP_JSON(objReactor, 'Release') SRP_JSON(objJSON, 'Release') end else Error_Services('Add', 'Error in ':Service:' service. Unable to parse JSON payload.') end end else Error_Services('Add', 'Error in ':Service:' service. Null JSON passed in.') end Response = Record end service Service CleanReactStatus() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then ReactNos = Reactor_Services('GetReactorNumbers') For each ReactNo in ReactNos using @FM HaveLock = Database_Services('GetKeyIDLock', 'REACT_STATUS', ReactNo) If HaveLock then OrigReactStatRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo) ReactStatRec = OrigReactStatRec If Error_Services('NoError') then For Col = 1 to 9 OrigList = OrigReactStatRec If OrigList NE '' then CleanList = '' For each Val in OrigList using @VM If Val NE 1 then CleanList<0, -1> = Val Next Val ReactStatRec = CleanList end Next Col If OrigReactStatRec NE ReactStatRec then Database_Services('WriteDataRow', 'REACT_STATUS', ReactNo, ReactStatRec, True$, False$, False$) end else Database_Services('ReleaseKeyIDLock', 'REACT_STATUS', ReactNo) end end end Next ReactNo Unlock hSysLists, ServiceKeyID else Null end end service Service GetReactModeKeysByTimeSpan(ReactorNo, StartDtm, StopDtm) Begin Case Case ReactorNo Eq '' Error_Services('Add', 'Error in ' : Service : ' service. ReactorNo not supplied.') Case StartDtm Eq '' Error_Services('Add', 'Error in ' : Service : ' service. StartDtm not supplied.') Case StopDtm Eq '' Error_Services('Add', 'Error in ' : Service : ' service. StopDtm not supplied.') End Case If Error_Services('NoError') then //Get all modes within the StartDtm and StopDtm StartDt = FIELD(StartDtm, '.', 1) StopDt = Field(StopDtm, '.', 1) keys = '' OPEN 'DICT.REACT_MODE_NG' TO @DICT then SearchString = '' SearchString := "START_DTM" :@VM: StartDtm : '~' : StopDtm: @FM SearchString := "STOP_DTM" :@VM: ';' : StartDtm : '~' : StopDtm : @FM SearchString := "REACT_NO" :@VM: ReactorNo : @FM keylist = "" option = "" flag = "" Btree.Extract(SearchString, 'REACT_MODE_NG', @DICT, keylist, option, flag) for each key in keylist keys<-1> = key Next key end if keys<1> EQ '' then //Get Current Mode because it started before report date and has yet to finish //Is the report time for the current mode? CurrReactorModeKey = Reactor_Services('GetReactCurrModeId', ReactorNo) CurrReactorModeStartDtm = Field(CurrReactorModeKey, '*', 2) IF StopDtm GT CurrReactorModeStartDtm then keys<-1> = CurrReactorModeKey end else // SearchString = '' SearchString := "START_DTM" :@VM: '<=' : StartDtm: @FM SearchString := "STOP_DTM" :@VM: '>=' : StopDtm : @FM SearchString := "REACT_NO" :@VM: ReactorNo : @FM SubKeyList = "" option = "" flag = "" Btree.Extract(SearchString, 'REACT_MODE_NG', @DICT, SubKeyList, option, flag) for each SubKey in SubKeyList keys<-1> = SubKey Next SubKey end //Is the report time outside of the current mode end Response = keys end else Response = Error_Services('GetMessage') end end service Service GetReactorUptimeMetricsByTimeSpan(ReactorNo, StartDtm, StopDtm) ToolData = '' TotalProductiveMinutes = 0 TotalUnscheduledDownMinutes = 0 TotalScheduledDownMinutes = 0 TotalNonSchedMinutes = 0 TotalEngMinutes = 0 Begin Case Case ReactorNo Eq '' Error_Services('Add', 'Error in ' : Service : ' service. ReactorNo not supplied.') Case StartDtm Eq '' Error_Services('Add', 'Error in ' : Service : ' service. StartDtm not supplied.') Case StopDtm Eq '' Error_Services('Add', 'Error in ' : Service : ' service. StopDtm not supplied.') End Case //If StopDtm is in future then set it to current time. If StopDtm GT Datetime() then StopDtm = Datetime() end If Error_Services('NoError') then //Get Keys for the supplied time span ReactModeNGKeys = Reactor_Services('GetReactModeKeysByTimeSpan', ReactorNo, StartDtm, StopDtm) If Error_Services('NoError') then //Get total minutes of timespan. TotalReportMinutes = SRP_Datetime('MinuteSpan', StartDtm, StopDtm) //Loop Through each mode key returned for each key in ReactModeNGKeys using @VM ReactModeNGRec = Database_Services('ReadDataRow', 'REACT_MODE_NG', key) ModeStartDtm = Field(key, '*', 2) ModeStopDtm = ReactModeNGRec ReactModeName = ReactModeNGRec E10State = Xlate('REACTOR_MODES', ReactModeName, REACTOR_MODES_E10_STATE$, 'X') MinutesInMode = 0 Begin Case CASE E10State EQ 'Productive' //Begin Production if ModeStartDtm LT StartDtm then //Mode Started Earlier than report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan If ModeStopDtm NE '' then MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm) end else //Mode is not closed If ModeStartDtm LT StartDtm then //if ModeStartDtm is before StartDtm and is not close used the total report timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end else //Use the ModeStartDtm and the StopDtm MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end end else //Mode started after report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan OR isn't yet closed If ModeStopDtm NE '' then //Mode is closed. Started and finished within the report time so use the Mode's start and stop MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm) end else //Mode is not closed. Started within the report time but has yet to stop. MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end TotalProductiveMinutes += MinutesInMode Case E10State EQ 'Unscheduled Down' //Begin Production if ModeStartDtm LT StartDtm then //Mode Started Earlier than report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan If ModeStopDtm NE '' then MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm) end else //Mode is not closed If ModeStartDtm LT StartDtm then //if ModeStartDtm is before StartDtm and is not close used the total report timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end else //Use the ModeStartDtm and the StopDtm MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end end else //Mode started after report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan OR isn't yet closed If ModeStopDtm NE '' then //Mode is closed. Started and finished within the report time so use the Mode's start and stop MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm) end else //Mode is not closed. Started within the report time but has yet to stop. MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end TotalUnscheduledDownMinutes += MinutesInMode Case E10State EQ 'Scheduled Down' //Begin Production if ModeStartDtm LT StartDtm then //Mode Started Earlier than report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan If ModeStopDtm NE '' then MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm) end else //Mode is not closed If ModeStartDtm LT StartDtm then //if ModeStartDtm is before StartDtm and is not close used the total report timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end else //Use the ModeStartDtm and the StopDtm MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end end else //Mode started after report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan OR isn't yet closed If ModeStopDtm NE '' then //Mode is closed. Started and finished within the report time so use the Mode's start and stop MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm) end else //Mode is not closed. Started within the report time but has yet to stop. MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end TotalScheduledDownMinutes += MinutesInMode Case E10State EQ 'Non-Scheduled' OR E10State EQ 'Standby' if ModeStartDtm LT StartDtm then //Mode Started Earlier than report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan If ModeStopDtm NE '' then MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm) end else //Mode is not closed If ModeStartDtm LT StartDtm then //if ModeStartDtm is before StartDtm and is not close used the total report timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end else //Use the ModeStartDtm and the StopDtm MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end end else //Mode started after report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan OR isn't yet closed If ModeStopDtm NE '' then //Mode is closed. Started and finished within the report time so use the Mode's start and stop MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm) end else //Mode is not closed. Started within the report time but has yet to stop. MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end TotalNonSchedMinutes += MinutesInMode Case E10State EQ 'Engineering' if ModeStartDtm LT StartDtm then //Mode Started Earlier than report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan If ModeStopDtm NE '' then MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm) end else //Mode is not closed If ModeStartDtm LT StartDtm then //if ModeStartDtm is before StartDtm and is not close used the total report timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end else //Use the ModeStartDtm and the StopDtm MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm) end end else //Mode started after report time If ModeStopDtm LT StopDtm then //Mode finished within the timespan OR isn't yet closed If ModeStopDtm NE '' then //Mode is closed. Started and finished within the report time so use the Mode's start and stop MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm) end else //Mode is not closed. Started within the report time but has yet to stop. MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end else //Mode finished after the timespan MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm) end end TotalEngMinutes += MinutesInMode End Case Next key ProdPercentage = (TotalProductiveMinutes / TotalReportMinutes) * 100 UnschedDownPercentage = (TotalUnscheduledDownMinutes / TotalReportMinutes) * 100 SchedDownPercentage = (TotalScheduledDownMinutes / TotalReportMinutes) * 100 NonSchedPercentage = (TotalNonSchedMinutes / TotalReportMinutes) * 100 EngPercentage = (TotalEngMinutes / TotalReportMinutes) * 100 //Percentages ToolData<1, PRODUCTIVE$> = ProdPercentage ToolData<1, UNSCHED$> = UnschedDownPercentage ToolData<1, SCHED$> = SchedDownPercentage ToolData<1, NONSCHED$> = NonSchedPercentage ToolData<1, ENG$> = EngPercentage //Total Minutes ToolData<2, PRODUCTIVE$> = TotalProductiveMinutes ToolData<2, UNSCHED$> = TotalUnscheduledDownMinutes ToolData<2, SCHED$> = TotalScheduledDownMinutes ToolData<2, NONSCHED$> = TotalNonSchedMinutes ToolData<2, ENG$> = TotalEngMinutes Response = ToolData end else Response = Error_Services('GetMessage') end end else Response = Error_Services('GetMessage') end end service Service GetReactorUptimeMetricsByTypeAndTimeSpan(startDtm, endDtm, reactType) Begin Case Case startDtm EQ '' Error_Services('Add', 'Error getting reactor uptime metrics -> Report start date not supplied') Case endDtm EQ '' Error_Services('Add', 'Error getting reactor uptime metrics -> Report end date not supplied') End Case If reactType EQ '' then reactType = 'ALL' If Error_Services('NoError') then If endDtm GT Date() then //This sets the current report end time to the current time. endDtm = Datetime() end reportMinutes = SRP_Datetime('MinuteSpan', startDtm, endDtm) if num(reportMinutes) then Begin Case Case reactType EQ 'ASM' or reactType EQ 'ASM+' Reactors = Reactor_Services('GetReactorNumbers', 'ASM') : @FM : Reactor_Services('GetReactorNumbers', 'ASM+') Case reactType EQ 'HTR' Reactors = Reactor_Services('GetReactorNumbers', 'HTR') Case reactType EQ 'EPP' Reactors = Reactor_Services('GetReactorNumbers', 'EPP') Case reactType EQ 'ALL' Reactors = Reactor_Services('GetReactorNumbers', 'ASM') : @FM : Reactor_Services('GetReactorNumbers', 'ASM+') : @FM : Reactor_Services('GetReactorNumbers', 'HTR') : @FM : Reactor_Services('GetReactorNumbers', 'EPP') End Case AllReactorsScheduledMinutes = 0 AllReactorsUptimeMinutes = 0 AllReactorsProdMinutes = 0 AllReactorsUnschedDownMinutes = 0 AllReactorsSchedDownMinutes = 0 AllReactorsEngMinutes = 0 AllReactorsIdleMinutes = 0 AllReactorsSingleLL= 0 TotalMinutesUp = 0 ReactorsData = '' ReactorsExcluded = '' for each Reactor in Reactors using @FM ReactorStateTimes = Reactor_Services('GetReactorUptimeMetricsByTimeSpan', Reactor, startDtm, endDtm) PercentProd = ReactorStateTimes<1,PRODUCTIVE$> MinuteProd = ReactorStateTimes<2,PRODUCTIVE$> PercentUnSchedDown = ReactorStateTimes<1,UNSCHED$> MinuteUnschedDown = ReactorStateTimes<2,UNSCHED$> PercentSchedDown = ReactorStateTimes<1,SCHED$> MinuteSchedDown = ReactorStateTimes<2,SCHED$> PercentNonSched = ReactorStateTimes<1,NONSCHED$> MinutesNonSched = ReactorStateTimes<2,NONSCHED$> PercentEng = ReactorStateTimes<1, ENG$> MinutesEng = ReactorStateTimes<2, ENG$> if MinutesNonSched LT reportMinutes then thisReactorExpectedAvailMinutes = reportMinutes - MinutesNonSched; * This is the amount of minutes the single reactor was scheduled to run work. AllReactorsScheduledMinutes += thisReactorExpectedAvailMinutes; * Add it to the collective of reactors thisReactorUptimeMinutes = MinuteProd + MinutesEng AllReactorsUptimeMinutes = thisReactorUptimeMinutes + AllReactorsUptimeMinutes AllReactorsProdMinutes += MinuteProd AllReactorsUnschedDownMinutes += MinuteUnschedDown AllReactorsSchedDownMinutes += MinuteSchedDown AllReactorsEngMinutes += MinutesEng AllReactorsIdleMinutes += MinutesNonSched if reactType NE 'EPP' then thisReactorDisabledLoadLock = Reactor_Services('GetReactorDownLL', Reactor) NE '' AllReactorsSingleLL += thisReactorDisabledLoadLock end else thisReactorDisabledLoadLock = 0 end ReactorsData = Reactor ReactorsData = PercentProd ReactorsData = MinuteProd ReactorsData = PercentEng ReactorsData = MinutesEng ReactorsData = PercentUnSchedDown ReactorsData = MinuteUnschedDown ReactorsData = PercentSchedDown ReactorsData = MinuteSchedDown ReactorsData = PercentNonSched ReactorsData = MinutesNonSched ReactorsData = thisReactorDisabledLoadLock end else ReactorsData = Reactor end Next Reactor if AllReactorsScheduledMinutes GT 0 then TotalUptimePercent = SRP_Math('ROUND', AllReactorsUptimeMinutes / AllReactorsScheduledMinutes, 5) TotalUptimeMinutes = SRP_Math('ROUND', AllReactorsUptimeMinutes, 5) TotalAvailMinutes = SRP_Math('ROUND', AllReactorsScheduledMinutes, 5) TotalProdPercent = SRP_Math('ROUND', AllReactorsProdMinutes / AllReactorsScheduledMinutes, 5) TotalUnschedDownPercent = SRP_Math('ROUND', AllReactorsUnschedDownMinutes / AllReactorsScheduledMinutes, 5) TotalSchedDownPercent = SRP_Math('ROUND', AllReactorsSchedDownMinutes / AllReactorsScheduledMinutes, 5) TotalEngPercent = SRP_Math('ROUND', AllReactorsEngMinutes / AllReactorsScheduledMinutes, 5) TotalIdlePercent = SRP_Math('ROUND', AllReactorsIdleMinutes / AllReactorsScheduledMinutes, 5) end else TotalUptimePercent = 0 TotalUptimeMinutes = 0 TotalAvailMinutes = 0 TotalProdPercent = 0 TotalUnschedDownPercent = 0 TotalSchedDownPercent = 0 TotalEngPercent = 0 TotalIdlePercent = 0 end ReactorsData = TotalUptimePercent ReactorsData = TotalProdPercent ReactorsData = AllReactorsProdMinutes ReactorsData = TotalEngPercent ReactorsData = AllReactorsEngMinutes ReactorsData = TotalUnschedDownPercent ReactorsData = AllReactorsUnschedDownMinutes ReactorsData = TotalSchedDownPercent ReactorsData = AllReactorsSchedDownMinutes ReactorsData = TotalIdlePercent ReactorsData = AllReactorsIdleMinutes ReactorsData = TotalUptimeMinutes ReactorsData = TotalAvailMinutes ReactorsData = AllReactorsSingleLL Response = ReactorsData end else Error_Services('Add', 'Error getting reactor uptime metrics -> Unable to get total report duration.') end end end service Service GetLoadedRds(ReactNo) StopRDS = Xlate('REACT_STATE', ReactNo, 'LAST_RDS_NO', 'X') // Get list of RDS on current reactor that are not FQA ReactorConfigKey = 'WO_DAILY_SCHED':ReactNo WoNo = Field(Xlate('CONFIG', ReactorConfigKey, WOCust$, 'X'), ' ', 1) RDSColumns = '' RDSColumns<0, 1> = 'SEQ' RDSList = RDS_Services('GetRDSData', WoNo, RDSColumns, False$, '') // Find the index of StopRDS RDSList = SRP_Sort_Array(RDSList, "AN1") RDSFastArray = SRP_Fastarray("Create", RDSList) StopRDSIdx = 0 SRP_Fastarray("Match", RDSFastArray, StopRDS, StopRDSIdx) RDSList = SRP_Fastarray("GetVariable", RDSFastArray) RdsKeys = '':@FM:'' RdsKeysPosition = 1 RdsIdx = StopRDSIdx + 1 DateIn = '' DateOut = '' Loop DateIn = Xlate('RDS', RDSList, RDS_DATE_IN$, 'X') DateOut = Xlate('RDS', RDSList, RDS_DATE_OUT$, 'X') While (DateIn NE '') and (DateOut EQ '') RdsKeys = RDSList If (RdsKeysPosition EQ 1) then RdsKeysPosition = 2 end else RdsKeysPosition = 1 end RdsIdx += 1 Repeat Response = RdsKeys end service Service ActiveProveInPreventsModeChange(ReactNo, NewMode, CurrentMode) If (ReactNo NE '') then If (NewMode NE '') then ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo) ActiveProveIn = Reactor_Services('GetProveInActive', ReactNo) If ActiveProveIn EQ True$ then Nica_Orders_Services('GetOrderUpdates') ActiveProveIn = Reactor_Services('GetProveInActive', ReactNo) If ActiveProveIn EQ True$ then Begin Case Case CurrentMode EQ 'INITIATE_IDLE' IdleStartupActive = Reactor_Services('GetIdleStartupRequired', ReactNo) If IdleStartupActive EQ True$ then Response = True$ end else Response = False$ end Case Len(NewMode) GE 2 and NewMode[1, 2] EQ 'UP' Response = True$ Case Otherwise$ Response = False$ End Case end else Response = False$ end end else Response = False$ end end else Error_Services('Add', 'Error in ' : Service : ' service. NewMode was empty') end end else Error_Services('Add', 'Error in ' : Service : ' service. ReactNo was empty') end end service Service GetReactorDownLL(ReactNo) Response = '' If RowExists('REACTOR', ReactNo) then LLDisabledID = Database_Services('ReadDataColumn', 'REACTOR', ReactNo, REACTOR_ACTIVE_LL_DISABLED$, True$, 0) If LLDisabledID NE '' then If RowExists('REACT_LL', LLDisabledID) then DownLoadLock = Database_Services('ReadDataColumn', 'REACT_LL', LLDisabledID, REACT_LL_DISABLED$, True$, 0) Response = DownLoadLock end end end end service Service GetReactorLoadCountLimit(ReactNo) ErrMsg = 'Error in ReactorServices -> GetReactorLoadCountLimit: ' MaxLoadCount = 999 If ReactNo NE '' then If RowExists('REACTOR', ReactNo) then ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo) If Error_Services('NoError') then ReactType = ReactorRec PickPlace = ReactorRec DisabledLoadLockCnt = DCount(ReactorRec, @VM) Begin Case Case ReactType EQ 'ASM' If PickPlace then MaxLoadCount = 2 - DisabledLoadLockCnt end else MaxLoadCount = 1 end Case ReactType EQ 'ASM+' If PickPlace then MaxLoadCount = 2 - DisabledLoadLockCnt end else MaxLoadCount = 1 end Case ReactType EQ 'HTR' If PickPlace then MaxLoadCount = 2 - DisabledLoadLockCnt end else MaxLoadCount = 1 end Case ReactType EQ 'EPP' MaxLoadCount = 2;*EPP needs to have an additional load capability. End Case end else ErrMsg := Error_Services('GetMessage') Error_Services('Add', ErrMsg) end end else ErrMsg := 'Reactor ' : ReactNo : ' does not exist.' Error_Services('Add', ErrMsg) end end else ErrMsg := 'Reactor Number was null.' Error_Services('Add', ErrMsg) end Response = MaxLoadCount end service Service GetReactorAvailChamberCount(ReactNo) ErrMsg = 'Error in ReactorServices -> GetReactorAvailChamberCount: ' AvailableChamberCount = 0 If ReactNo NE '' then If RowExists('REACTOR', ReactNo) then LoadedRDS = Reactor_Services('GetReactorCurrLoadRDS', ReactNo) ReactorCurrLoadCnt = DCount(LoadedRDS, @VM) ReactorCurrCapacity = Reactor_Services('GetReactorLoadCountLimit', ReactNo) AvailableChamberCount = ReactorCurrCapacity - ReactorCurrLoadCnt end else ErrMsg := 'Reactor ' : ReactNo : ' does not exist.' Error_Services('Add', ErrMsg) end end else ErrMsg := 'Reactor Number was null.' Error_Services('Add', ErrMsg) end Response = AvailableChamberCount end service Service RemoveRDSFromReactorLoad(RDSNo, ReactorNo, User) Response = 0 If User NE '' then If RDSNo NE '' then If ReactorNo NE '' then ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactorNo) If Error_Services('NoError') then Locate RDSNo in ReactStatusRec setting RDSPos then ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_RDS$, RDSPos, 0) ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_RDS_DTM$, RDSPos, 0) ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_CASS_ID$, RDSPos, 0) ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_DTM$, RDSPos, 0) Database_Services('WriteDataRow', 'REACT_STATUS', ReactorNo, ReactStatusRec, 1, 0, 1) If Error_Services('NoError') then Response = 1 end else ErrMsg = Error_Services('GetMessage') Error_Services('Add', ErrMsg) end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: RDS was not found as a loaded lot.') end end else ErrMsg = Error_Services('GetMessage') Error_Services('Add', ErrMsg) end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Reactor No was supplied.') end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No RDS No was supplied.') end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Username was supplied.') end end service Service AddRDSToReactorLoad(RDSNo, ReactorNo) Response = 0 If RDSNo NE '' then If ReactorNo NE '' then ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactorNo) If Error_Services('NoError') then Locate RDSNo in ReactStatusRec using @VM setting iPos else WONo = Xlate('RDS', RDSNo, 'WO_NO', 'X') CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X') WOMatKey = WONo : '*' : CassNo ThisDTM = SRP_Datetime('Now') ReactStatusRec = RDSNo ReactStatusRec = ThisDTM ReactStatusRec = WOMatKey ReactStatusRec = ThisDTM Database_Services('WriteDataRow', 'REACT_STATUS', ReactorNo, ReactStatusRec, 1, 0, 1) end end else ErrMsg = Error_Services('GetMessage') Error_Services('Add', ErrMsg) end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Reactor No was supplied.') end end else Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No RDS No was supplied.') end end service Service UpdateReactorIQSViolations() ReactNos = Reactor_Services('GetReactorNumbers') If Error_Services('NoError') then CurrViols = Database_Services('ReadDataRow', 'CONFIG', 'IQS_VIOL_DATA') If Error_Services('NoError') then ViolatingReactors = CurrViols ViolationDtms = CurrViols ViolationTests = CurrViols Swap ' AM' with 'AM' in ViolationDtms Swap ' PM' with 'PM' in ViolationDtms ViolationDtms = IConv(ViolationDtms, 'DT') For each ReactNo in ReactNos ActiveAlarm = False$ For each ViolReactor in ViolatingReactors using @VM setting vPos If ViolReactor EQ ReactNo then ActiveAlarm = True$ ThisAlarmDtm = ViolationDtms<0, vPos> ThisAlarmTest = ViolationTests<0, vPos> // Check if a new alarm and update if necessary LastAlarmDtm = Xlate('REACTOR', ReactNo, REACTOR_IQS_ALARM_DTM$, 'X') If LastAlarmDtm LT ThisAlarmDtm then // New alarm HaveLock = Database_Services('GetKeyIDLock', 'REACTOR', ReactNo, True$) If HaveLock then ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo) If Error_Services('NoError') then ReactorRec = ThisAlarmDtm ReactorRec = ThisAlarmTest // WriteDataRow will clear the lock as long as "IgnoreAllLocks" is false // REACTOR_ACTIONS will be triggered, which will generate a NICA order if a new HgCV alarm is detected Database_Services('WriteDataRow', 'REACTOR', ReactNo, ReactorRec, True$, False$, False$) end end end end Next ViolReactor If Not(ActiveAlarm) then // Clear last active alarm HaveLock = Database_Services('GetKeyIDLock', 'REACTOR', ReactNo, True$) If HaveLock then ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo) If Error_Services('NoError') then ReactorRec = '' ReactorRec = '' // WriteDataRow will clear the lock as long as "IgnoreAllLocks" is false Database_Services('WriteDataRow', 'REACTOR', ReactNo, ReactorRec, True$, False$, False$) end end end Next ReactNo end end end service Service GetProveInActive(ReactNo) If ReactNo NE '' then OrderTypes = 'CHANGEOVER' : @VM : 'INITIATE_IDLE' : @VM : 'IDLE' ActiveProveInIds = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, OrderTypes) Response = (ActiveProveInIds NE '') end else Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.') end end service Service GetActiveProveInTypes(ReactNo) If ReactNo NE '' then ActiveProveInOrderIds = Reactor_Services('GetActiveProveInOrderIds', ReactNo) If ActiveProveInOrderIds NE '' then Response = Xlate('NICA_ORDERS', ActiveProveInOrderIds, 'ORDER_TYPE', 'X') end end else Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.') end end service Service GetActiveProveInProgresses(ReactNo) Response = '' If ReactNo NE '' then ActiveProveInOrderIds = Reactor_Services('GetActiveProveInOrderIds', ReactNo) If ActiveProveInOrderIds NE '' then OrderTypes = Xlate('NICA_ORDERS', ActiveProveInOrderIds, 'ORDER_TYPE', 'X') OrderCount = Dcount(OrderTypes, @VM) For I = 1 to OrderCount OrderType = OrderTypes ProgressPercentage = Xlate('NICA_ORDERS', ActiveProveInOrderIds, 'PROGRESS_PERCENTAGE', 'X') Response<-1> = OrderType : '- ' : ProgressPercentage :'% Complete.' Next I end end else Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.') end end service Service GetActiveProveInOrderIds(ReactNo) If ReactNo NE '' then OrderTypes = 'CHANGEOVER' : @VM : 'INITIATE_IDLE' : @VM : 'IDLE' Response = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, OrderTypes) end else Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.') end end service Service GetIdleStartupRequired(ReactNo) If ReactNo NE '' then Response = Xlate('REACTOR', ReactNo, REACTOR_IDLE_STARTUP_REQUIRED$, 'X') end else Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.') end end service //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RollbackReactUtil: // Reopen previous REACT_UTIL record If OldReactUtilID NE '' then OldReactUtilRec = Database_Services('ReadDataRow', 'REACT_UTIL', OldReactUtilID) OldReactUtilRec = '' OldReactUtilRec = '' OldReactUtilRec = '' Database_Services('WriteDataRow', 'REACT_UTIL', OldReactUtilID, OldReactUtilRec) end return ClearCursors: For counter = 0 to 8 ClearSelect counter Next counter return