Function Material_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 : Material_Services Description : Handler program for all module related services. Notes : Service module to support environmental state issues. Environmental refers to the state of the operating system, which includes version, client vs. server, and path to critical systems. 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) 04/16/18 dmb Original programmer. 04/24/18 dmb Modify GetAvailableMakeupWafers to avoid returning cassette with 0 wafers. 10/25/18 dmb Modify GetAvailableMakeupWafers to better support EpiPro. 09/07/23 djm Add GetLotHistory Service. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert LOGICAL $insert SERVICE_SETUP $insert WO_LOG_EQUATES $insert WO_MAT_EQUATES $insert WO_STEP_EQUATES $insert PROD_SPEC_EQUATES $insert RDS_EQUATES $insert RLIST_EQUATES $insert WO_MAT_QUEUE_EQUATES $insert WM_OUT_QUEUE_EQUATES $insert WO_STEP_QUEUE_EQUATES $insert WM_OUT_EQUATES $insert RDS_QUEUE_EQUATES $insert REACT_RUN_EQUATES $insert NOTIFICATION_EQUATES $insert PROD_VER_EQUATES $insert NCR_EQUATES $insert CLEAN_INSP_EQUATES $insert RDS_LAYER_EQUATES $insert RDS_TEST_EQUATES $insert TW_USE_EQUATES $insert MAKEUP_WAFERS_EQUATES Equ Tab$ to Char(9) Equ Esc$ to \1B\ Equ CRLF$ to \0D0A\ Equ COMMA$ to ',' Common /EnvironmentServices/ Unused1@, Unused2@, Unused3@, Unused4@, Unused5@, Unused6@, Unused7@, Unused8@, Unused9@, Unused10@ Declare function Material_Services, Memory_Services, Database_Services, SRP_Array, obj_WO_Mat, obj_WM_Out Declare function Logging_Services, Environment_Services, Datetime, obj_WO_Step, Database_Services, SQL_Services Declare function SRP_Rotate_Array, SRP_DateTime, obj_WO_Log, obj_Shipment, SRP_Date, Rds_Services Declare subroutine Material_Services, Memory_Services, Database_Services, SRP_Array, Btree.Extract, Logging_Services Declare subroutine SRP_Stopwatch, Set_Status, RList, Work_Order_Services, SQL_Services, obj_WO_Mat, obj_Notes Declare subroutine SRP_Rotate_Array, SRP_DateTime, obj_WO_Log, Hold_Services LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\MUBox' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Makeup Auto Hold Log.csv' Headers = 'Logging DTM' : @FM : 'WONo' : @FM : 'Notes' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_Mat' LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Erase Attempt.csv' Headers = 'Logging DTM' : @FM : 'User' : @FM : 'RDSNo' : @FM : 'WOMatKeyID' : @FM : 'Call Stack' : @FM : 'Error' objLog3 = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_Mat' LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Curr Status Change.csv' Headers = 'Logging DTM' : @FM : 'User' : @FM : 'WOMatKeyID' : @FM : 'Old Status' : @FM : 'New Status' objStatusLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) GoToService else Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.') end Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options BOOLEAN = True$, False$ Options IDType = 'RDS', 'WO_MAT' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // GetLotHistory // // IDType - [Required] Either 'RDS' or 'WO_MAT'. Default is RDS // LotID - [Required] RDS ID or WO_MAT ID, corresponding to IDType // StartDate - (Optional) // EndDate - (Optional) // // Returns a delimited array of Lot History Events and comments. // //---------------------------------------------------------------------------------------------------------------------- Service GetLotHistory(IDType=IDType, LotID, StartDate, EndDate) LotList = '' LotArray = '' CommentList = '' CommentArray = '' ActionList = '' ActionArray = '' FinalLotArray = '' // No Start/EndDate entered If IDType = 'WO_MAT' then // Open RDS and WO_MAT records WOMatRow = Database_Services('ReadDataRow', 'WO_MAT', LotID) RDSNo = WOMatRow RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo) // Get RDS Comments CommentDates = RDSRow CommentUsers = RDSRow Comments = RDSRow CommentList = CommentDates :@FM: CommentUsers :@FM:@FM: Comments CommentArray = SRP_Rotate_Array(CommentList) CommentCount = DCount(CommentArray, @FM) For I = 1 to CommentCount ThisComment = CommentArray Begin Case Case IndexC(ThisComment, 'Material Taken off Hold', 1) CommentArray = 'HOLD_OFF' Case IndexC(ThisComment, 'Material Placed on Hold', 1) CommentArray = 'HOLD_ON' Case IndexC(ThisComment, 'Packaging completed for', 1) CommentArray = 'PACK' End Case Next I // WO_MAT Actions INVDTMs = WOMatRow INVUsers = WOMatRow INVActions = WOMatRow ActionList = INVDTMs :@FM: INVUsers :@FM: INVActions :@FM:@FM ActionArray = SRP_Rotate_Array(ActionList) // Remove Hold Inventory actions from array because they are populated from RDS commments. HoldOffCount = Count(INVActions, 'HOLD_OFF') HoldOnCount = Count(INVActions, 'HOLD_ON') PackCount = Count(INVActions, 'PACK') Locate 'HOLD_OFF' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end Locate 'HOLD_ON' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end For K = 1 to PackCount Locate 'PACK' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end Next K end else // RDS is default IDType // Open RDS and WO_MAT records RDSRow = Database_Services('ReadDataRow', 'RDS', LotID) WOMatKey = Xlate('RDS', LotID, 'WO_MAT_KEY', 'X') WOMatRow = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) // Get RDS Comments CommentDates = RDSRow CommentUsers = RDSRow Comments = RDSRow CommentList = CommentDates :@FM: CommentUsers :@FM:@FM: Comments CommentArray = SRP_Rotate_Array(CommentList) CommentCount = DCount(CommentArray, @FM) For I = 1 to CommentCount ThisComment = CommentArray Begin Case Case IndexC(ThisComment, 'Material Taken off Hold', 1) CommentArray = 'HOLD_OFF' Case IndexC(ThisComment, 'Material Placed on Hold', 1) CommentArray = 'HOLD_ON' Case IndexC(ThisComment, 'Packaging completed for', 1) CommentArray = 'PACK' End Case Next I // WO_MAT Actions INVDTMs = WOMatRow INVUsers = WOMatRow INVActions = WOMatRow ActionList = INVDTMs :@FM: INVUsers :@FM: INVActions :@FM:@FM ActionArray = SRP_Rotate_Array(ActionList) HoldOffCount = Count(INVActions, 'HOLD_OFF') HoldOnCount = Count(INVActions, 'HOLD_ON') PackCount = Count(INVActions, 'PACK') // Remove Hold Inventory actions from array because they are populated from RDS commments. Locate 'HOLD_OFF' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end Locate 'HOLD_ON' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end For K = 1 to PackCount Locate 'PACK' in InvActions Using @VM Setting POS then ActionArray = Delete(ActionArray, POS, 0, 0) end Next K end // Add Comments if present If CommentArray NE '' then LotArray = CommentArray :@FM: ActionArray end else LotArray = ActionArray end // Sort by Date SortedLotArray = SRP_Array('SortRows', LotArray, 'D1', 'LIST') // Convert DateTimes to External RowCount = Dcount(SortedLotArray, @FM) If StartDate NE '' AND EndDate NE '' then For index = 1 to RowCount If SortedLotArray LE EndDate and SortedLotArray GE StartDate then FinalLotArray<-1> = Oconv(SortedLotArray, 'DT') :@vm: SortedLotArray :@vm: SortedLotArray :@vm: SortedLotArray end Next Index end else For index = 1 to RowCount FinalLotArray<-1> = Oconv(SortedLotArray, 'DT') :@vm: SortedLotArray :@vm: SortedLotArray :@vm: SortedLotArray Next Index end Response = FinalLotArray End Service //---------------------------------------------------------------------------------------------------------------------- // ProcessAutoHold // // looks for MakeUp wafers older than 3 years old and then puts them on hold and sends notification. //---------------------------------------------------------------------------------------------------------------------- Service ProcessAutoHold() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Begin ':Service Logging_Services('AppendLog', objLog, LogData, @RM, @FM) HoldList = '' FailedHoldList = '' HoldEntityIds = '' CuttoffDtm = SRP_Datetime('AddYears', Datetime(), -3) Query = 'SELECT MAKEUP_WAFERS WITH UNLOAD_DTM LT ':Quote(OConv(CuttoffDtm, 'DT2/^H')): ' AND WITH EXPIRED NE ':True$ Flag = '' RList(Query, TARGET_ACTIVELIST$, '', '', Flag) LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'RList Flag = ':Flag:'. @RecCount = ':@RecCount Logging_Services('AppendLog', objLog, LogData, @RM, @FM) EOF = False$ Loop Readnext WOMatKey else EOF = True$ Until EOF ErrorMsg = '' ; // Local loop error message tracking ExpiredFlag = '' HoldFlag = '' LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Identified lot "':WOMatKey:'" as older than three years. Checking hold state...' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) WONo = Field(WOMatKey, '*', 1) ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X') If ReactType EQ 'EPP' then CassNo = Field(WOMatKey, '*', 2) HoldEntity = 'WM_OUT' HoldEntityID = WONo:'*1*':CassNo end else HoldEntity = 'RDS' HoldEntityID = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') end WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) If Error_Services('NoError') then HoldFlag = WOMatRec If HoldFlag EQ True$ then LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Lot "':WOMatKey:'" already on hold. Hold flag = ':HoldFlag:'.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Lot "':WOMatKey:'" not on hold. Hold flag = ':HoldFlag:'. Attempting to place lot on hold...' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) // Toggle hold state Hold_Services('ToggleHold', WOMatKey, HoldEntity, HoldEntityID, '', 'H', '', 'SYSTEM') If Error_Services('NoError') then // Verify hold state // Re-read record to verify hold state WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) If Error_Services('NoError') then NewHoldFlag = WOMatRec LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Lot "':WOMatKey:'" new hold flag = ':NewHoldFlag:'.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) If NewHoldFlag EQ HoldFlag then // Something went wrong somewhere ErrorMsg = 'New hold state, ':NewHoldFlag:', of lot "':WOMatKey:'" equals previous hold state, ':HoldFlag:'.' LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = ErrorMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to verify lot "':WOMatKey:'" was placed on hold.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to toggle hold state of lot "':WOMatKey:'".' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end If ErrorMsg EQ '' then // Now mark cassette as expired MWRec = Database_Services('ReadDataRow', 'MAKEUP_WAFERS', WOMatKey) ExpiredFlag = MWRec LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Checking expiry state of "':WOMatKey:'". Expired flag = ':ExpiredFlag:'.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) If ExpiredFlag NE True$ then LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Lot "':WOMatKey:'" not marked as expired. Attempting to mark lot "':WOMatKey:'" as expired.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) Material_Services('MarkMUCassExpired', WOMatKey) If Error_Services('NoError') then MWRec = Database_Services('ReadDataRow', 'MAKEUP_WAFERS', WOMatKey) If Error_Services('NoError') then ExpiredFlag = MWRec LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Successfully marked lot "':WOMatKey:'" as expired. Expired flag = ':ExpiredFlag:'.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to verify lot "':WOMatKey:'" was marked as expired.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to mark lot "':WOMatKey:'" as expired.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Lot "':WOMatKey:'" already marked as expired. Expired flag = ':ExpiredFlag:'.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to toggle hold state of lot "':WOMatKey:'".' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to place lot "':WOMatKey:'" on hold. Error reading WO_MAT record to get hold state.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end If (ErrorMsg EQ '') then HoldList<-1> = ReactType:TAB$:HoldEntityID HoldEntityIds<-1> = WOMatKey end else FailedHoldList<-1> = ReactType:TAB$:HoldEntityID end Repeat NotifyDtm = Datetime() // Send initial notification of successful lots and failed lots If (HoldEntityIds NE '') then Recipients = '' SentFrom = 'SYSTEM' Subject = 'Makeup Wafer Auto-Hold Report' AttachWindow = '' AttachKey = '' SendToGroup = 'AUTO_HOLD' Message = 'The following makeup cassettes are older than three years and have been automatically ' Message := 'placed on hold.':CRLF$:'Reminder: EpiPro lots can contain multiple RDS lots.':CRLF$:CRLF$ Swap @FM with CRLF$ in HoldList Message := HoldList Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup obj_Notes('Create',Parms) For each HoldEntityId in HoldEntityIds using @FM WOMatKey = HoldEntityId MUWfrRec = Database_Services('ReadDataRow', 'MAKEUP_WAFERS', WOMatKey) If Error_Services('NoError') then HaveLock = Database_Services('GetKeyIDLock', 'MAKEUP_WAFERS', WOMatKey, True$) If HaveLock then MUWfrRec = NotifyDtm Database_Services('WriteDataRow', 'MAKEUP_WAFERS', WOMatKey, MUWfrRec, True$, False$, False$) If Error_Services('NoError') then LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Updated expiry notify dtm for expired lot "':WOMatKey:'".' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to update expiry notify dtm for expired lot "':WOMatKey:'". Error updating MAKEUP_WAFERS record.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) SelfLocked = Database_Services('IsKeyIDSelfLocked', 'MAKEUP_WAFERS', WOMatKey) If SelfLocked then Database_Services('ReleaseKeyIDLock', 'MAKEUP_WAFERS', WOMatKey) end end else LogMsg = 'MAKEUP_WAFERS record for expired lot "':WOMatKey:'" is locked. Service will attempt again on next service call.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to send notification for expired lot "':WOMatKey:'". Error reading MAKEUP_WAFERS record.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end Next HoldEntityId end If (FailedHoldList NE '') then Recipients = '' SentFrom = 'SYSTEM' Subject = 'Makeup Wafer Auto-Hold Report' AttachWindow = '' AttachKey = '' SendToGroup = 'AUTO_HOLD' Message = 'The following makeup cassettes are older than three years and failed to be placed on hold by ' Message := 'the system.':CRLF$:'Reminder: EpiPro lots can contain multiple RDS lots.':CRLF$:CRLF$ Swap @FM with CRLF$ in FailedHoldList Message := FailedHoldList Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup obj_Notes('Create',Parms) end // Send reminders of expired lots not yet NCR'd, which should trigger deletion of MAKEUP_WAFERS record when quantity reaches zero. NotifyList = '' ThresholdDtm = SRP_Datetime('AddHours', Datetime(), -12) ThresholdDtm = OConv(ThresholdDtm, 'DT2/^H') Query = 'SELECT MAKEUP_WAFERS WITH EXPIRED EQ ':True$:' AND WITH EXPIRY_LAST_NOTIFY_DTM LT ':Quote(ThresholdDtm) Flag = '' RList(Query, TARGET_ACTIVELIST$, '', '', Flag) LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Notification RList Flag = ':Flag:'. @RecCount = ':@RecCount Logging_Services('AppendLog', objLog, LogData, @RM, @FM) EOF = False$ Loop Readnext WOMatKey else EOF = True$ Until EOF WONo = Field(WOMatKey, '*', 1) ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X') If ReactType EQ 'EPP' then CassNo = Field(WOMatKey, '*', 2) HoldEntityID = WONo:'*1*':CassNo end else HoldEntityID = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') end MUWfrRec = Database_Services('ReadDataRow', 'MAKEUP_WAFERS', WOMatKey) If Error_Services('NoError') then HaveLock = Database_Services('GetKeyIDLock', 'MAKEUP_WAFERS', WOMatKey, True$) If HaveLock then MUWfrRec = NotifyDtm Database_Services('WriteDataRow', 'MAKEUP_WAFERS', WOMatKey, MUWfrRec, True$, False$, False$) If Error_Services('NoError') then NotifyList<-1> = ReactType:TAB$:HoldEntityID LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'Updated expiry notify dtm for expired lot "':WOMatKey:'".' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to send notification for expired lot "':WOMatKey:'". Error updating MAKEUP_WAFERS record.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) SelfLocked = Database_Services('IsKeyIDSelfLocked', 'MAKEUP_WAFERS', WOMatKey) If SelfLocked then Database_Services('ReleaseKeyIDLock', 'MAKEUP_WAFERS', WOMatKey) end end else LogMsg = 'MAKEUP_WAFERS record for expired lot "':WOMatKey:'" is locked. Service will attempt again on next service call.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end end else ErrorMsg = Error_Services('GetMessage') LogMsg = 'Failed to send notification for expired lot "':WOMatKey:'". Error reading MAKEUP_WAFERS record.' LogMsg := 'Error message: ':ErrorMsg LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = LogMsg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end Repeat If (NotifyList NE '') then Recipients = '' SentFrom = 'SYSTEM' Subject = 'Makeup Wafer Auto-Hold Report' AttachWindow = '' AttachKey = '' SendToGroup = 'AUTO_HOLD' Message = 'The following makeup cassettes are older than three years and have been automatically ' Message := 'placed on hold.':CRLF$:'Reminder: EpiPro lots can contain multiple RDS lots.':CRLF$:CRLF$ Swap @FM with CRLF$ in NotifyList Message := NotifyList Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup obj_Notes('Create',Parms) end LogData = '' LogData<1> = OConv(Datetime(), 'DT2/^H') LogData<2> = 'End ':Service Logging_Services('AppendLog', objLog, LogData, @RM, @FM) Unlock hSysLists, ServiceKeyID else Null end end service //---------------------------------------------------------------------------------------------------------------------- // GetAvailableMakeupWafers // // Returns an array of available makeup wafers for the indicated work order. // // <1> = Cassettes with final RDS signature (i.e., available to use). // <2> = Cassettes still missing final RDS signature. // // Data within each field mark will be @VM row and @SVM column limited. //---------------------------------------------------------------------------------------------------------------------- Service GetAvailableMakeupWafers(WorkOrderNo, KeysOnly=BOOLEAN) AvailableMakeupWafers = '' If WorkOrderNo NE '' then WorkOrderNo = WorkOrderNo[1, '*'] ; // This might be formatted as a WO_MAT Key ID, so strip off the Cassette No. WOLogRow = Database_Services('ReadDataRow', 'WO_LOG', WorkOrderNo) If Error_Services('NoError') then WOStepKeys = WOLogRow WOMatKeys = WOLogRow FirstWOMatKey = WOMatKeys<0, 1> WOMatRow = Database_Services('ReadDataRow', 'WO_MAT', FirstWOMatKey) If Error_Services('NoError') then PartNo = WOMatRow LastWOStepKey = WOStepKeys[-1, 'B' : @VM] WOStepRow = Database_Services('ReadDataRow', 'WO_STEP', LastWOStepKey) If Error_Services('NoError') then WOStepPSN = WOStepRow WOStepRDSNos = WOStepRow WOStepWMOutNos = WOStepRow ProdSpecRow = Database_Services('ReadDataRow', 'PROD_SPEC', WOStepPSN) If Error_Services('NoError') then ReactorType = ProdSpecRow SearchString = '' SearchTable = 'MAKEUP_WAFERS' If ReactorType EQ 'EPP' then SearchString := 'EPI_PART_NO' : @VM : PartNo : @FM : 'REACT_TYPE' : @VM : 'EPP' : @FM end else SearchString := 'EPI_PART_NO' : @VM : PartNo : @FM : 'REACT_TYPE' : @VM : '#EPP' : @FM end hDictSearchTable = Database_Services('GetTableHandle', 'DICT.' : SearchTable) If Error_Services('NoError') then rv = Set_Status(0) MakeupBoxes = '' Flag = '' StatusCode = '' Btree.Extract(SearchString, SearchTable, hDictSearchTable, MakeupBoxes, '', Flag) If Get_Status(StatusCode) then Error_Services('Add', 'Error calling Btree.Extract in the ' : Service : ' service. StatusCode: ' : StatusCode) end else If MakeupBoxes NE '' then // One or more makeup was found that matches the customer's part and has the status of 'Ready to Use'. // Now loop through to find out which ones have the RDS final signature or not. NumMakeupBoxes = DCount(MakeupBoxes, @VM) For Each MakeupBoxID in MakeupBoxes using @VM WOMatKeyID = MakeupBoxID CurrStatus = Xlate('MAKEUP_WAFERS', MakeupBoxID, 'CURR_STATUS_STATIC', 'X') // DPC 7/21/20 added HOLD as excluded status type Locate CurrStatus in 'MT,VOID,SHIP,REJ,HOLD' using ',' setting cPos else If (ReactorType EQ 'EPP') OR (ReactorType EQ 'P') then CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID:@RM:'':@RM:True$) end else CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID) end If CurrWaferCount GT 0 then WOMatRow = Database_Services('ReadDataRow', 'WO_MAT', WOMatKeyID) RDSKeyIDs = WOMatRow SAPBatchNo = WOMatRow FirstRDSKeyID = RDSKeyIDs[1, @VM] RDSRow = Database_Services('ReadDataRow', 'RDS', FirstRDSKeyID) WMOKey = WOMatRow If WMOKey NE '' then WMOFQASig = Xlate('WM_OUT', WMOKey, 'SUP_VER_SIG', 'X') end else WMOFQASig = '' end ThisWorkOrderNo = WOMatKeyID[1, '*'] ThisCassetteNo = WOMatKeyID[Col2() + 1, '*'] ThisWOLogRow = Database_Services('ReadDataRow', 'WO_LOG', ThisWorkOrderNo) ThisWOStepKeyID = ThisWOLogRow[-1, 'B' : @VM] ThisWOStepRow = Database_Services('ReadDataRow', 'WO_STEP', ThisWOStepKeyID) WOStepRDSNos = ThisWoStepRow MakeupBoxDet = ThisWorkOrderNo : @SVM MakeupBoxDet := ThisCassetteNo : @SVM MakeupBoxDet := WOMatRow : @SVM MakeupBoxDet := ThisWOStepRow : @SVM MakeupBoxDet := PartNo : @SVM MakeupBoxDet := CurrWaferCount : @SVM MakeupBoxDet := FirstRDSKeyID // JRO Added PROD_SPEC PARAMETERS 5/8/2020 If (ReactorType EQ 'EPP') OR (ReactorType EQ 'P') then ProdSpecID = Xlate('RDS', WOStepRDSNos<1, 1>, RDS_PROD_SPEC_ID$, 'X') end else ProdSpecID = Xlate('RDS', RDSKeyIDs, RDS_PROD_SPEC_ID$, 'X') end ActiveStatus = XLATE('PROD_SPEC', ProdSpecID, PROD_SPEC_STATUS$, 'X') LabelCheck = Count(WOMatRow, 'LBLCHK') // JRO Added the extra condition for Active Status 5/8/2020 If ActiveStatus EQ 'A' then Begin Case Case SAPBatchNo EQ '' // Cassette has not received a batch number from SAP, so it is not yet eligible to be used. FieldPos = 3 Case ( (ReactorType NE 'EPP') and (RDSRow NE '') and (LabelCheck NE FALSE$) ) OR ( (ReactorType EQ 'EPP') and (WMOFQASig NE '') and (LabelCheck NE FALSE$) ) // Cassette has a final signature, so it is eligible to be used. FieldPos = 1 Case ( (ReactorType NE 'EPP') and (RDSRow EQ '') ) OR ( (ReactorType EQ 'EPP') and (WMOFQASig EQ '') ) // Cassette does not yet have a final signature, so it is not yet eligible to be used. FieldPos = 2 Case ( (ReactorType NE 'EPP') and (RDSRow NE '') and (LabelCheck EQ False$)) OR ( (ReactorType EQ 'EPP') and (WMOFQASig NE '') and (LabelCheck EQ False$)) // Cassette does not yet have a packing label check, so it is not yet eligible to be used. FieldPos = 4 Case Otherwise$ // Log these cassettes as we should never end up here. Null End Case If KeysOnly EQ True$ then If (ReactorType EQ 'EPP') OR (ReactorType EQ 'P') then WMOFormat = Field(MakeupBoxID, '*', 1):'*1*':Field(MakeupBoxID, '*', 2) AvailableMakeupWafers = Insert(AvailableMakeupWafers, FieldPos, -1, 0, WMOFormat) end else AvailableMakeupWafers = Insert(AvailableMakeupWafers, FieldPos, -1, 0, WOMatKeyID) end end else AvailableMakeupWafers = Insert(AvailableMakeupWafers, FieldPos, -1, 0, MakeupBoxDet) end end end end Next MakeupBoxID end end end end end end end end else Error_Services('Add', 'WorkOrderNo argument was missing from the ' : Service : ' service.') end Response = AvailableMakeupWafers end service Service UpdateWOMatStatus(WOMatKey) If WOMatKey NE '' then WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) WOMatCurrStatus = obj_WO_Mat('CurrStatus', WOMatKey:@RM:WOMatRec) WOMatCurrStatus = WOMatCurrStatus[-1, 'B':@VM] // Get a fresh copy of the record. WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) WOMatCurrStatusStatic = WOMatRec If WOMatCurrStatus NE WOMatCurrStatusStatic then WOMatRec = WOMatCurrStatus Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$) LogData = '' LogData<1> = LoggingDTM LogData<2> = @User4 LogData<3> = WOMatKey LogData<4> = WOMatCurrStatusStatic LogData<5> = WOMatCurrStatus Logging_Services('AppendLog', objStatusLog, LogData, @RM, @FM) end Database_Services('ReleaseKeyIDLock', 'WO_MAT', WOMatKey) end end service Service PostWOMatUpdateRequest(WOMatKey) If WOMatKey NE '' then // Look for a pre-existing request in the queue If (RowExists('WO_MAT_QUEUE', WOMatKey) EQ False$) then // This is a new request RequestKeyID = WOMatKey RequestRow = '' RequestRow = Datetime() Database_Services('WriteDataRow', 'WO_MAT_QUEUE', RequestKeyID, RequestRow, False$, False$, False$) end else // Duplicate request Null end end else Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') end end service Service ProcessWOMatUpdateRequests() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then Open 'WO_MAT_QUEUE' to hTable then Select hTable EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF EQ True$ WOMatKey = RequestKeyID Material_Services('UpdateWOMatStatus', WOMatKey) If Error_Services('NoError') then // Successfully updated the current status, so delete the request from the queue. Database_Services('DeleteDataRow', 'WO_MAT_QUEUE', RequestKeyID, True$, True$) end Repeat end else ErrorMsg = 'Error opening WO_MAT_QUEUE in ':Service:' service.' end Unlock hSysLists, ServiceKeyID else Null end end service Service UpdateWMOutStatus(WMOKey) If WMOKey NE '' then WMOutRec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey) WMOutCurrStatus = obj_WM_Out('CurrStatus', WMOKey:@RM:WMOutRec) // Get a fresh copy of the record WMOutRec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey) WMOutCurrStatusStatic = WMOutRec If WMOutCurrStatus NE WMOutCurrStatusStatic then WMOutRec = WMOutCurrStatus Database_Services('WriteDataRow', 'WM_OUT', WMOKey, WMOutRec, True$, False$, True$) end Database_Services('ReleaseKeyIDLock', 'WM_OUT', WMOKey) end end service Service UpdateRDSStatus(RDSNo) If RDSNo NE '' then RDSCombStatus = Xlate('RDS', RDSNo, 'COMB_STATUS', 'X') // Get a fresh copy of the record RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo) RDSCombStatusStatic = RDSRec If RDSCombStatus NE RDSCombStatusStatic then RDSRec = RDSCombStatus Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, True$, True$) end end end service Service PostRDSUpdateRequest(RDSNo) If RDSNo NE '' then // Look for a pre-existing request in the queue If (RowExists('WM_OUT_QUEUE', RDSNo) EQ False$) then // This is a new request RequestKeyID = RDSNo RequestRow = '' RequestRow = Datetime() Database_Services('WriteDataRow', 'RDS_QUEUE', RequestKeyID, RequestRow, False$, False$, False$) end else // Duplicate request - ignore it. Null end end else Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') end end service Service ProcessRDSUpdateRequests() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then Open 'RDS_QUEUE' to hTable then Select hTable EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF EQ True$ RDSNo = RequestKeyID Material_Services('UpdateRDSStatus', RDSNo) If Error_Services('NoError') then // Successfully updated the current status, so delete the request from the queue. Database_Services('DeleteDataRow', 'RDS_QUEUE', RequestKeyID, True$, True$) end Repeat end else ErrorMsg = 'Error opening RDS_QUEUE in ':Service:' service.' end Unlock hSysLists, ServiceKeyID else Null end end service Service PostWMOutUpdateRequest(WMOKey) If WMOKey NE '' then // Look for a pre-existing request in the queue If (RowExists('WM_OUT_QUEUE', WMOKey) EQ False$) then // This is a new request RequestKeyID = WMOKey RequestRow = '' RequestRow = Datetime() Database_Services('WriteDataRow', 'WM_OUT_QUEUE', RequestKeyID, RequestRow, False$, False$, False$) end else // Duplicate request - ignore it. Null end end else Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') end end service Service ProcessWMOutUpdateRequests() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then Open 'WM_OUT_QUEUE' to hTable then Select hTable EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF EQ True$ WMOKey = RequestKeyID Material_Services('UpdateWMOutStatus', WMOKey) If Error_Services('NoError') then // Successfully updated the current status, so delete the request from the queue. Database_Services('DeleteDataRow', 'WM_OUT_QUEUE', RequestKeyID, True$, True$) end Repeat end else ErrorMsg = 'Error opening WM_OUT_QUEUE in ':Service:' service.' end Unlock hSysLists, ServiceKeyID else Null end end service Service PostWfrLocUpdate(WMOKey) Swap '.' with '*' in WMOKey WONo = Field(WMOKey, '*', 1) CassNo = Field(WMOKey, '*', 2) WOMatKey = WONo:'*':CassNo If RowExists('WO_MAT', WOMatKey) then WfrList = Xlate('WO_MAT_WFR', WOMatKey, 'OUT_WFR_ID', 'X') GaNWfrIDs = Xlate('WO_WFR', WfrList, 'GAN_WFR_ID', 'X') WfrLocs = Xlate('WO_WFR', WfrList, 'CUST_NAME', 'X') For each Wfr in GaNWfrIDs using @VM setting vPos LocationName = WfrLocs<0, vPos> GaNWfrID = GaNWfrIDs<0, vPos> SQLStatement = 'UPDATE [G4Wafers_01].[dbo].[Wafer Location] ' SQLStatement := "SET Main_Location = '":LocationName:"', Main_Form = 'FULL' " SQLStatement := "WHERE Wafer_ID = '":GaNWfrID:"'" SQL_Services('PostSQLStatement', 'IQSDMS1', SQLStatement) Next Wfr end end service Service UpdateWaferLocation(WMOKey) Swap '.' with '*' in WMOKey WONo = Field(WMOKey, '*', 1) CassNo = Field(WMOKey, '*', 2) WOMatKey = WONo:'*':CassNo If RowExists('WO_MAT', WOMatKey) then WfrList = Xlate('WO_MAT_WFR', WOMatKey, 'OUT_WFR_ID', 'X') GaNWfrIDs = Xlate('WO_WFR', WfrList, 'GAN_WFR_ID', 'X') WfrLocs = Xlate('WO_WFR', WfrList, 'CUST_NAME', 'X') objConn = Sql_Services('GetConnectionObject', 'IQSDMS1') For each Wfr in GaNWfrIDs using @VM setting vPos LocationName = WfrLocs<0, vPos> GaNWfrID = GaNWfrIDs<0, vPos> SQLStatement = 'UPDATE [G4Wafers_01].[dbo].[Wafer Location] ' SQLStatement := "SET Main_Location = '":LocationName:"', Main_Form = 'FULL' " SQLStatement := "WHERE Wafer_ID = '":GaNWfrID:"'" SQL_Services('ExecuteQuery', objConn, SQLStatement, 0, 1) Next Wfr end end service Service VerifyEPPUnload(RDSNo) ErrorMsg = '' If RDSNo NE '' then // Verify RDS and REACT_RUN outbound cassette data matches. RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo) RDSOutCassNos = RDSRec RDSOutSlotNos = RDSRec RRRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) RROutCassNos = RRRec RROutSlotNos = RRRec If ( (RDSOutCassNos NE RROutCassNos) or (RDSOutSlotNos NE RROutSlotNos) ) then ErrorMsg = 'Error in ':Service:' service. RDS and REACT_RUN mismatch for key ':RDSNo:'!' end else WONo = RDSRec // Verify WM_OUT outbound cassette data matches RDSInCassNos = RDSRec RDSInSlotNos = RDSRec If RDSOutCassNos NE '' then For each OutCassNo in RDSOutCassNos using @VM setting vPos // TEST wafers are not placed in outbound cassettes. If OutCassNo NE '' then // Open WM_OUT record, go to the out slot and verify that the IN_CASS_NO and IN_SLOT_NO match. WMOutKey = WONo:'*1*':OutCassNo WMOutRec = Database_Services('ReadDataRow', 'WM_OUT', WMOutKey) OutSlotNo = RDSOutSlotNos<0, vPos> WMOInCassNo = WMOutRec WMOInSlotNo = WMOutRec RDSInCassNo = RDSInCassNos<0, vPos> RDSInSlotNo = RDSInSlotNos<0, vPos> If (WMOInCassNo EQ RDSInCassNo) and (WMOInSlotNo EQ RDSInSlotNo) then // Data matches Null end else // Data mismatch - throw error ErrorMsg = 'Error in ':Service:' service. RDS and WM_OUT mismatch for inbound wafer ':RDSInCassNo:'*':RDSInSlotNo:'!' end end Until ErrorMsg NE '' Next OutCassNo end else ErrorMsg = 'Error in ':Service:' service. RDS out cassettes numbers are null!' end end end else ErrorMsg = 'Error in ':Service:' service. Null RDSNo passed in!' end If ErrorMsg NE '' then Error_Services('Add', 'Error in ':Service:' service. Error message: ':ErrorMsg) Response = False$ end else Response = True$ end end service Service ConvertMaterial(WONo, CassNos, NewPVNo) NewWONo = '' ErrorMsg = '' If RowExists('WO_LOG', WONo) then If CassNos NE '' then Swap @FM with @VM in CassNos WOMatKeys = '' For each CassNo in CassNos using @VM setting vPos WOMatKeys<0, vPos> = WONo:'*':CassNo MakeupFlag = Xlate('WO_MAT', WONo:'*':CassNo, WO_MAT_MAKEUP_BOX$, 'X') If MakeupFlag then ErrorMsg = 'Error in ':Service:' service. Cassette ':WONo:'*':CassNo:' is a makeup box and cannot be converted to a different part number.' end If ( (ErrorMsg EQ '') and (Not(RowExists('WO_MAT', WONo:'*':CassNo) ) ) ) then ErrorMsg = 'Error in ':Service:' service. Cassette ':WONo:'*':CassNo:' does not exist.' end Until ErrorMsg NE '' Next CassNo If ErrorMsg EQ '' then If RowExists('PROD_VER', NewPVNo) then * 1. Create new WO with coresponding Part no, PSN, EpiPartNo, Cust Epi Part, Sub Part No, Revised Quantity(Peeled off amount coming back) * -Subtract MU wafer quantity(original amount that is apart of a MU lot, 1 MU lot = 25 wafers) // Generate new internal production order number to associate with the new work order. NumAttempts = 0 HaveLock = False$ Loop NumAttempts += 1 HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', 'CURR_INT_PROD_ORD_NO') Until HaveLock or NumAttempts EQ 10 Repeat If HaveLock then CurrIntProdOrdNo = Database_Services('ReadDataRow', 'APP_INFO', 'CURR_INT_PROD_ORD_NO') NextIntProdOrdNo = CurrIntProdOrdNo + 1 NewIntProdOrdNo = 'IFX' : Fmt(NextIntProdOrdNo, 'R(0)#4') : '.1' NewEpiPartNo = Xlate('PROD_VER', NewPVNo, PROD_VER_EPI_PART_NO$, 'X') SubPartNo = Xlate('PROD_VER', NewPVNo, PROD_VER_SUB_PART_NO$, 'X') SubPartRev = Xlate('WO_LOG', WONo, WO_LOG_ORD_SUB_PART_REV$, 'X') NewWOQty = Sum(Xlate('WO_MAT', WOMatKeys, WO_MAT_WAFER_QTY$, 'X')) VendCd = Xlate('WO_LOG', WONo, WO_LOG_EXP_VEND_CD$, 'X') NewCustNo = Xlate('PROD_VER', NewPVNo, PROD_VER_CUST_NO$, 'X') NewPSNo = Xlate('PROD_VER', NewPVNo, PROD_VER_PROC_STEP_PSN$, 'X') If ( (NewIntProdOrdNo NE '') and (NewEpiPartNo NE '') and (SubPartNo NE '') and (NewWOQty NE '') and (VendCd NE '') and (NewCustNo NE '') and (NewPSNo NE '') ) then MockSAPFile = '' MockSAPFile<0, 1> = NewIntProdOrdNo ; // Prod Ord No - Must match "'M'6N'.1'" OR "7X'.1'" and not conflict with SAP MockSAPFile<0, 2> = 'NA' ; // CustPONo - Not Applicable MockSAPFile<0, 3> = Date() + 365 ; // Promise Ship Date - Hard coded to a year from today MockSAPFile<0, 4> = NewEpiPartNo ; // EpiPartNo - Changing from original work order MockSAPFile<0, 5> = SubPartNo ; // SubPartNo - Not changing from original work order MockSAPFile<0, 6> = SubPartRev ; // SubRevNo - Not changing from original work order MockSAPFile<0, 7> = NewWOQty ; // WOQty - Quantity of material moving to new work order MockSAPFile<0, 8> = VendCd ; // VendCd - Not changing from original work order Success = obj_WO_Log('SAPCreate', MockSAPFile) If Success then // obj_WO_Log('SAPCreate') does not return new work order number, so look it up instead. SearchString = 'PROD_ORD_NO':@VM:NewIntProdOrdNo:@FM Open 'DICT.WO_LOG' to hDict then Flag = '' Btree.Extract(SearchString, 'WO_LOG', hDict, NewWONo, 'E', Flag) // Check for successful query If Flag EQ 0 then // There should only be one work order associated with our unique internal production order number. If (DCount(NewWONo, @VM) EQ 1) then // Associate new work order with the part number passed in. obj_WO_Log('Route', NewWONo:@RM:NewPVNo) ErrCode = '' If Not(Get_Status(ErrCode)) then // Start "migrating" WO_MAT, RDS, etc. entities from previous work order to new work order. NewWOStepKey = NewWONo:'*1' NewCassNo = 0 NewWOMatKeys = '' RDSKeys = Xlate('WO_MAT', WOMatKeys, 'RDS_NO', 'X') For each WOMatKey in WOMatKeys using @VM setting vPos NewCassNo += 1 RDSKey = RDSKeys<0, vPos> CassNo = Field(WOMatKey, '*', 2) WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) If Error_Services('NoError') then NewWOMatKey = NewWONo:'*':NewCassNo NewWOMatKeys<0, -1> = NewWOMatKey NewWOMatRec = WOMatRec // Modify WO_MAT fields INV_... (6-10, 31, 103, 142), Cust Part No(3), Part No(22) // Clear material log starting at 1QA InvActions = WOMatRec Locate '1QA' in InvActions using @VM setting aPos then NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) NewWOMatRec = Field(WOMatRec, @VM, 1, aPos - 1) end NewWOMatRec = NewEpiPartNo NewWOMatRec = NewPVNo NewWOMatRec = '' ; // Clear ship number to prevent status of "Shipped" and to allow for re-ship. NewWOMatRec = True$ ; // This flag is used to override INSP_REQ calculated column in CLEAN_INSP. Database_Services('WriteDataRow', 'WO_MAT', NewWOMatKey, NewWOMatRec) If Error_Services('NoError') then NCRKeys = WOMatRec If NCRKeys NE '' then For each NCRKey in NCRKeys using @VM setting nPos NCRRec = Database_Services('ReadDataRow', 'NCR', NCRKey) If Error_Services('NoError') then // Modify NCR fields WO_NO(62), WO_MAT_CASS_NO(64), REJ_WAFER_ID(Change first two fields, third will stay the same(Probably MV))(67) NewNCRRec = NCRRec NewNCRRec = NewWONo NewNCRRec = NewCassNo WfrIDs = NCRRec If WfrIDs NE '' then For each WfrID in WfrIDs using @VM setting wPos NewNCRRec<0, wPos> = NewWONo:'.':NewCassNo:'.':Field(WfrID, '.', 3) Next WfrID end Database_Services('WriteDataRow', 'NCR', NCRKey, NewNCRRec, True$, False$, True$) end else ErrorMsg = Error_Services('GetMessage') end Until ErrorMsg NE '' Next NCRKey end If ErrorMsg EQ '' then RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKey) If Error_Services('NoError') then // Modify RDS fields Epi Part No(10), WO(6), Cust No(9), Prod_Spec_Id(114), WO_STEP_KEY(256), CASS_NO(260) NewRDSRec = RDSRec NewRDSRec = NewWONo NewRDSRec = NewCustNo NewRDSRec = NewEpiPartNo NewRDSRec = NewPSNo NewRDSRec = NewWOStepKey NewRDSRec = NewCassNo NewRDSRec = '' ; // Clear FQA signature to prevent MFS from blocking write and to re-require FQA NewRDSRec = '' NewRDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSKey, NewRDSRec, True$, False$, True$) If Error_Services('NoError') then // Copy WO_MAT_QA record (no changes necessary) WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey) Database_Services('WriteDataRow', 'WO_MAT_QA', NewWOMatKey, WOMatQARec) If Error_Services('NoError') then // Modify REACT_RUN fields WO_NO(1), CASS_NO(3), CI_NO(Dont remove, but capture value, may be MV. Field 6) ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKey) If Error_Services('NoError') then NewReactRunRec = ReactRunRec NewReactRunRec = NewWONo NewReactRunRec = NewCassNo Database_Services('WriteDataRow', 'REACT_RUN', RDSKey, NewReactRunRec, True$, False$, True$) If Error_Services('NoError') then CINos = ReactRunRec If CINos NE '' then For each CINo in CINos using @VM setting cPos // Modify CLEAN_INSP fields WO_NO(1), CASS_NO(3) CIRec = Database_Services('ReadDataRow', 'CLEAN_INSP', CINo) If Error_Services('NoError') then NewCIRec = CIRec NewCIRec = NewWONo NewCIRec = NewCassNo Database_Services('WriteDataRow', 'CLEAN_INSP', CINo, NewCIRec, True$, False$, True$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end Until ErrorMsg NE '' Next CINo end RDSLayerKeys = ReactRunRec If RDSLayerKeys NE '' then For each RDSLayerKey in RDSLayerKeys using @VM RDSTestKeys = Xlate('RDS_LAYER', RDSLayerKey, RDS_LAYER_RDS_TEST_KEYS$, 'X') If RDSTestKeys NE '' then For each RDSTestKey in RDSTestKeys using @VM TWUseKeys = Xlate('RDS_TEST', RDSTestKey, RDS_TEST_TW_USE_ID$, 'X') If TWUseKeys NE '' then For each TWUseKey in TWUseKeys using @VM TWUseRec = Database_Services('ReadDataRow', 'TW_USE', TWUseKey) If Error_Services('NoError') then // Modify TW_USE fields WAFER_ID(19)(Can be multivalue) Change first two fields(WO)(CASS_NO) Third will stay the same. NewTWUseRec = TWUseRec TWUseWfrIDs = TWUseRec If TWUseWfrIDs NE '' then For each TWUseWfrID in TWUseWfrIDs using @VM setting tPos NewTWUseRec = NewWONo:'*':NewCassNo:'*':Field(TWUseWfrID, '*', 3) Next TWUseWfrID end Database_Services('WriteDataRow', 'TW_USE', TWUseKey, NewTWUseRec, True$, False$, True$) end else ErrorMsg = Error_Services('GetMessage') end Until ErrorMsg NE '' Next TWUseKey end Until ErrorMsg NE '' Next RDSTestKey end Until ErrorMsg NE '' Next RDSLayerKey end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end Until ErrorMsg NE '' // Delete old records Database_Services('DeleteDataRow', 'WO_MAT', WOMatKey, True$, False$) Database_Services('DeleteDataRow', 'WO_MAT_QA', WOMatKey, True$, False$) Next WOMatKey If ErrorMsg EQ '' then // Update new work order record to contain list of new WO_MAT keys. NewWORec = Database_Services('ReadDataRow', 'WO_LOG', NewWONo) If Error_Services('NoError') then NewWORec = NewWOMatKeys Database_Services('WriteDataRow', 'WO_LOG', NewWONo, NewWORec, True$, False$, True$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end If ErrorMsg EQ '' then // Reduce source work order quantity by new work order quantity WORec = Database_Services('ReadDataRow', 'WO_LOG', WONo) WORec = WORec - NewWOQty Database_Services('WriteDataRow', 'WO_LOG', WONo, WORec, True$, False$, True$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end end end end else ErrorMsg = 'Error in ':Service:' service. Error routing work order ':NewWONo:'. Error message: ':ErrCode:'.' end end else ErrorMsg = 'Error in ':Service:' service. Error retrieving new work order number. Btree.Extract result: "':NewWONo:'".' end end else ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.' end end else ErrorMsg = 'Error in ':Service:' service. Failed to open DICT.WO_LOG table.' end end else ErrorMsg = 'Error in ':Service:' service. obj_WO_Log("SAPCreate") failed. Check SAP_LOG table for details.' end If ErrorMsg EQ '' then // Increment internal production order number Database_Services('WriteDataRow', 'APP_INFO', 'CURR_INT_PROD_ORD_NO', NextIntProdOrdNo, True$, False$, False$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end else Locked = Database_Services('IsKeyIDLocked', 'APP_INFO', 'CURR_INT_PROD_ORD_NO') If Locked then Database_Services('ReleaseKeyIDLock', 'APP_INFO', 'CURR_INT_PROD_ORD_NO') end end else ErrorMsg = 'Error in ':Service:' service. Failed to determine SAP parameters for new work order.' end end else ErrorMsg = 'Error in ':Service:' service. Failed to get new internal prod order number.' end end else ErrorMsg = 'Error in ':Service:' service. PROD_VER "':NewPVNo:'" does not exist.' end end end else ErrorMsg = 'Error in ':Service:' service. Null CassNos passed into service.' end end else ErrorMsg = 'Error in ':Service:' service. WO_LOG "':WONo:'" does not exist.' end If ErrorMsg EQ '' then Response = NewWONo end else Error_Services('Add', ErrorMsg) Response = '' end end service Service ShipConvertedMaterial(ProdOrdNo, CassNos) ErrorMsg = '' NewShipmentNo = '' If ProdOrdNo NE '' then If CassNos NE '' then SearchString = 'PROD_ORD_NO':@VM:ProdOrdNo:@FM Open 'DICT.WO_LOG' to hDict then Flag = '' WONo = '' Btree.Extract(SearchString, 'WO_LOG', hDict, WONo, 'E', Flag) // Check for successful query If Flag EQ 0 then // There should only be one work order associated with our unique internal production order number. If (DCount(WONo, @VM) EQ 1) then MockShipData = '' For each CassNo in CassNos using @VM setting vPos WOMatKey = WONo:'*':CassNo If RowExists('WO_MAT', WOMatKey) then SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X') If SAPBatchNo NE '' then MockShipData = ProdOrdNo ; // SAP Delivery Number - Just use internal IFX generated SAP production order number. MockShipData = ProdOrdNo ; // Internal IFX generated SAP production order number. MockShipData = SAPBatchNo ; // Original SAP batch number associated with cassette. end else ErrorMsg = 'Error in ':Service:' service. No SAP batch number found for WO_MAT record ':WOMatKey:'.' end end else ErrorMsg = 'Error in ':Service:' service. WO_MAT record ':WOMatKey:' does not exist.' end Until ErrorMsg NE '' Next CassNo If ErrorMsg EQ '' then If MockShipData NE '' then Success = obj_Shipment('SAPCreate', MockShipData) If Not(Success) then ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Error in ':Service:' service. Failed to generate mock ship data file for obj_Shipment("SAPCreate").' end end end else ErrorMsg = 'Error in ':Service:' service. Error retrieving work order number. Btree.Extract result: "':WONo:'".' end end else ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.' end end else ErrorMsg = 'Error in ':Service:' service. Failed to open DICT.WO_LOG table.' end end else ErrorMsg = 'Error in ':Service:' service. Null CassNos passed into service.' end end else ErrorMsg = 'Error in ':Service:' service. Null ProdOrdNo passed into service.' end If ErrorMsg EQ '' then Response = NewShipmentNo end else Error_Services('Add', ErrorMsg) Response = '' end end service Service MarkMUCassExpired(WoMatKey) ErrorMsg = '' If WoMatKey NE '' then If RowExists('MAKEUP_WAFERS', WoMatKey) then Open 'MAKEUP_WAFERS' to hMuTable then WriteV True$ to hMuTable, WoMatKey, MAKEUP_WAFERS.EXPIRED$ else ErrorMsg = 'Error in ':Service:' service. Error writing MAKEUP_WAFERS record "':WoMatKey:'".' end end else ErrorMsg = 'Error in ':Service:' service. Failed to open MAKEUP_WAFERS table.' end end else ErrorMsg = 'Error in ':Service:' service. MAKEUP_WAFERS record "':WoMatKey:'" does not exist!' end end else ErrorMsg = 'Error in ':Service:' service. Null WoMatKey passed in.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) Response = False$ end else Response = True$ end end service //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ClearCursors: For counter = 0 to 8 ClearSelect counter Next counter return