Function Scheduler_Actions_Dev_Events(CtrlEntId, Event, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15) /*********************************************************************************************************************** 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 Infineon. Name : Scheduler_Actions_Dev_Events Description : This function acts as a commuter module for all events related to this window. Notes : Commuter Modules are automatically called from the Promoted_Events function which is called by the application-specific promoted event handler. This makes it possible to add QuickEvents that need to execute Basic+ logic without having use the Form Designer to make the association, although this is limited to the events which are currently promoted. If the form needs to call the commuter module directly then the QuickEvent parameters should be formatted like this: '@SELF','@EVENT',['@PARAM1','@PARAMx'] Parameters : CtrlEntId [in] -- The fully qualified name of the control calling the promoted event Event [in] -- The event being executed. See the Notes section regarding "PRE" events Param1-15 [in] -- Additional event parameter holders EventFlow [out] -- Set to 1 or 0 so the calling event knows whether or not to chain forward. See comments in EVENT_SETUP insert History : (Date, Initials, Notes) 06/12/17 dmb Created initial commuter module. 01/08/21 djs Began work on version 2.0. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler #Window SCHEDULER_ACTIONS_DEV $insert APP_INSERTS $insert EVENT_SETUP $insert MSG_EQUATES $insert SCHED_DET_NG_EQUATES $insert WO_LOG_EQUATES $insert WO_SCHEDULE_NG_EQUATES $insert REACTOR_EQUATES Equ OI_DISABLED_GREY$ TO 239 + (239*256) + (239*65536) WorkOrderCtrls = 'OLE_DIV_WORK_ORDER_DETAILS,WO_NO_LABEL,WO_NO,EPI_PART_LABEL,EPI_PART,DESCRIPTION_LABEL,DESCRIPTION,CUSTOMER_NAME_LABEL,CUSTOMER_NAME,' WorkOrderCtrls := 'TOTAL_WAFERS_LABEL,TOTAL_WAFERS,TOTAL_REMAINING_LABEL,TOTAL_REMAINING,PERCENT_COMPLETE_LABEL,PERCENT_COMPLETE' DateRangeCtrls = 'SCHEDULE_START_DTM_LABEL,SCHEDULE_START_DTM,SCHEDULE_END_DTM_LABEL,SCHEDULE_END_DTM,DAYS_LABEL,DAYS' Declare function SRP_Array, Schedule_Services_Dev, Database_Services, Work_Order_Services, SRP_Math Declare function Epi_Part_Services, Datetime Declare subroutine obj_Appwindow, Center_Window, Schedule_Services_Dev, Form_Services, SRP_Show_Window Declare subroutine Form_Services, ErrMsg SubclassInfo = Form_Services('FindSubclassControl') Subclass = SubclassInfo<1> // Update the arguments so that the OpenInsight OLE event will treate the ActiveX event as a native event handler. If Event EQ 'OLE' then Transfer Event to OIEvent Transfer Param1 to Event Transfer Param2 to Param1 Transfer Param3 to Param2 Transfer Param4 to Param3 Transfer Param5 to Param4 Transfer Param6 to Param5 Transfer Param7 to Param6 Transfer Param8 to Param7 end Type = Get_Property(CtrlEntId, 'TYPE') If Type EQ 'RADIOBUTTON' then Convert ' ' to '_' in CtrlEntID end GoToEvent Event for CtrlEntID Return EventFlow else EVENT_CONTINUE$ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Events //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Event WINDOW.CREATE(CreateParam) ReactorNo = CreateParam<1> SchedStartDTM = CreateParam<2> Set_Property(@Window, '@SCHED_START_DTM', SchedStartDTM) NextStartDTM = '' ReactSchedEvents = Xlate('REACTOR', ReactorNo, 'SCHED_EVENTS', 'X') If ReactSchedEvents NE '' then LastEventKey = ReactSchedEvents[-1, 'B':@VM] LastSchedDetRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', LastEventKey) NextStartDTM = LastSchedDetRec end Set_Property(@Window, '@NEXT_START_DTM', NextStartDTM) If NextStartDTM NE '' then StartDTM = NextStartDTM end else StartDTM = SchedStartDTM end Set_Property(@Window : '.REACTOR_NO', 'TEXT', ReactorNo) Set_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE', StartDTM) GoSub Setup_OLE_Controls GoSub PopulateControls Set_Property(@Window : '.CLOSE_BUTTON', 'NEXT', @Window : '.REACTOR_NO') SRP_Show_Window(@Window, '', 'C', 'C', 1, '', False$, False$) end event Event WINDOW.CLOSE(CancelFlag) end event Event SCHEDULE_OPTIONS_DATETIME.NEXT_AVAILABLE.CLICK() StartDTM = Get_Property(@Window, '@NEXT_START_DTM') Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM) Set_Property(@Window:'.SCHEDULE_START_DTM', 'ENABLED', False$) Set_Property(@Window:'.SCHEDULE_START_DTM', 'BACKCOLOR', OI_DISABLED_GREY$) GoSub UpdateWorkOrderDetails end event Event SCHEDULE_OPTIONS_DATETIME.SPECIFIC_DATE_AND_TIME.CLICK() StartDTM = Get_Property(@Window, '@SCHED_START_DTM') Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM) Set_Property(@Window:'.SCHEDULE_START_DTM', 'ENABLED', True$) Set_Property(@Window:'.SCHEDULE_START_DTM', 'BACKCOLOR', WHITE$) GoSub UpdateWorkOrderDetails end event Event SCHEDULE_END_DTM.LOSTFOCUS(Flag, FocusID) StartDTM = Get_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE') EndDTM = Get_Property(CtrlEntId, 'INVALUE') If StartDTM NE '' AND EndDTM NE '' then Days = EndDTM - StartDTM + 1 Set_Property(@Window : '.DAYS', 'DEFPROP', Days) end end event Event SCHEDULE_START_DTM.LOSTFOCUS(Flag, FocusID) WorkOrder = Get_Property(@Window : '.WO_NO', 'TEXT') If WorkOrder NE '' then GoSub UpdateWorkOrderDetails end else Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', '') end end event Event WO_NO.LOSTFOCUS(Flag, FocusID) WONo = Get_Property(CtrlEntID, 'TEXT') OrigWONo = Get_Property(@Window, '@WO_NO') If WONo NE OrigWONo then Set_Property(@Window, '@WO_NO', WONo) // User changed the value in this control. Update related controls. GoSub UpdateCustomerName GoSub InitializeProperties GoSub UpdateWorkOrderDetails end end event Event SAVE_BUTTON.CLICK() ResponseData = '' ReactorNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') WorkOrder = Get_Property(@Window : '.WO_NO', 'TEXT') StartDTM = Get_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE') EndDTM = Get_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE') Description = Get_Property(@Window : '.DESCRIPTION', 'INVALUE') EventQty = Get_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT') ResponseData = ReactorNo : @FM : WorkOrder : @FM : StartDTM : @FM : EndDTM : @FM : Description : @FM : EventQty End_Dialog(@Window, ResponseData) end event Event CLOSE_BUTTON.CLICK() Post_Event(@Window, 'CLOSE') end event Event OLE_SUBCLASS.OnOptionClick(CtrlId) Send_Event(CtrlId, 'OPTIONS') end event Event OLE_SUBCLASS.OnComboClick(CtrlId) Send_Event(CtrlId, 'LOSTFOCUS') end event Event SCHEDULE_WAFERS.CHANGED(NewData) SchedQty = NewData AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT') If SchedQty NE '' then If (SchedQty GT AvailQty) then Set_Property(CtrlEntID, 'FOCUS', True$) Set_Property(CtrlEntID, 'SELECTION', 1 : @FM : 999) Message = 'Schedule quantity must be less than or equal to the avialable quantity.' Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEndID, 'VALIDATION', 'RGB(229,20,0)') end else GoSub UpdateWorkOrderDetails end end GoSub EnableSaveButton end event Event SCHEDULE_WAFERS.CHAR(VirtCode, ScanCode, CtrlKey, ShiftKey, AltKey) Form_Services('CloseControlMessage', CtrlEntId) * SchedQty = Get_Property(CtrlEntID, 'TEXT') * AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT') * If SchedQty GT AvailQty then * Set_Property(CtrlEntID, 'FOCUS', True$) * Set_Property(CtrlEntID, 'SELECTION', 1 : @FM : 999) * Message = 'Schedule quantity must be less than or equal to the avialable quantity.' * Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEndID, 'VALIDATION', 'RGB(229,20,0)') * end else * GoSub UpdateWorkOrderDetails * end * GoSub EnableSaveButton end event Event SCHEDULE_WAFERS.LOSTFOCUS(Flag, FocusID) * SchedQty = Get_Property(CtrlEntID, 'TEXT') * AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT') * If SchedQty GT AvailQty then * Set_Property(CtrlEntID, 'FOCUS', True$) * Set_Property(CtrlEntID, 'SELECTION', 1 : @FM : 999) * Message = 'Schedule quantity must be less than or equal to the avialable quantity.' * Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEndID, 'VALIDATION', 'RGB(229,20,0)') * end else * GoSub UpdateWorkOrderDetails * end * GoSub EnableSaveButton end event //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Setup_OLE_Controls: Ctrl = @Window : '.OLE_SUBCLASS' // Get the current reactor type and size so the GetReactor and GetUnscheduledWorkOrders service results can be filtered // down to only those items that match the same type and size. ReactorNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) ReactorType = ReactorRec SusceptorSize = ReactorRec EditLine = @Window : '.WO_NO' Handle = Get_Property(EditLine, 'HANDLE') Send_Message(Ctrl, 'OLE.Subclass', Handle, EditLine) Combo = '' Combo<1> = 1 Combo<2, 1> = 'Work Order' : @TM : 'Epi Part' : @TM : 'Customer' : @TM : 'Reactor Type' : @TM : 'PSN Block' Combo<2, 2> = 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'L' : @STM : 'DYN' : @TM : 'C' : @STM : 'DYN' Combo<2, 3> = '' Combo<2, 4> = 1 Combo<2, 5> = 1 Combo<2, 6> = 0 Combo<2, 7> = 40 Combo<2, 9> = 1 Combo<2,10> = 0 Combo<2,11> = 0 Combo<2,12> = 1 Combo<2,24> = 0 EditLine = @Window : ';WO_NO' Set_Property(@Window : '.OLE_SUBCLASS', 'OLE.Combo[' : EditLine : ']', Combo) Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnOptionClick', 1) Send_Message(Ctrl, 'QUALIFY_EVENT', 'OLE.OnComboClick', 1) return SelectAll: Set_Property(CtrlEntId, 'SELECTION', 1 : @FM : 999) return UpdateScheduleDetails: ScheduleDetail = Schedule_Services_Dev('GetScheduleDetail', ScheduleKeyID) Set_Property(@Window, '@ORIG_SCHEDULEDETAIL', ScheduleDetail) WorkOrder = Get_Property(@Window : '.WO_NO', 'TEXT') If WorkOrder NE '' then Set_Property(@Window : '.DESCRIPTION', 'TEXT', ScheduleDetail) end else Set_Property(@Window : '.DESCRIPTION', 'TEXT', '') end return UpdateCustomerName: WoNo = Get_Property(@Window : '.WO_NO', 'TEXT') If WoNo NE '' then WorkOrderDetail = Work_Order_Services('GetWorkOrderLogDetail', WONo) CustNo = WorkOrderDetail CompanyRow = Database_Services('ReadDataRow', 'COMPANY', CustNo) CustName = CompanyRow<42> end else CustName = '' end Set_Property(@Window : '.CUSTOMER_NAME', 'TEXT', CustName) return UpdateReactorDetails: ReactorNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') If Index(ReactorNo, '/', 1) then // EpiPro reactors formatted as such, "40/42". We must truncate the reactor number to the first reactor. ReactorNo = Field(ReactorNo, '/', 1, 1) Set_Property(@Window : '.REACTOR_NO', 'TEXT', ReactorNo) end ReactorDetails = Schedule_Services_Dev('GetReactorDetails', ReactorNo) ReactorType = ReactorDetails Begin Case Case ReactorType _EQC 'EPP' ; ReactorType = 'EpiPro' Case ReactorType _EQC 'GAN' ; ReactorType = 'GaN' End Case Set_Property(@Window : '.REACTOR_TYPE', 'TEXT', ReactorType) Set_Property(@Window : '.REACTOR_SIZE', 'TEXT', ReactorDetails) FutureEvents = Schedule_Services_Dev('GetScheduleEvents', Date() + 1, '', ReactorNo, '', False$) Set_Property(@Window, '@FUTURE_EVENTS', FutureEvents) return InitializeProperties: WorkOrder = Get_Property(@Window : '.WO_NO', 'TEXT') ReactNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') ReactorType = Get_Property(@Window : '.REACTOR_TYPE', 'TEXT') WorkOrderDetail = Work_Order_Services('GetWorkOrderLogDetail', WorkOrder) RemainingToProcess = Work_Order_Services('GetUnprocessedWafers', WorkOrder) RemainingToSchedule = Schedule_Services_Dev('GetUnscheduledWfrQty', WorkOrder) EpiPart = WorkOrderDetail MinutesPerWaferAdjusted = Epi_Part_Services('GetAdjustedWafersPerDayScheduler', EpiPart, ReactorType) ScheduledWfrQty = Schedule_Services_Dev('GetScheduledWfrQty', WorkOrder) WOSchedCass = Schedule_Services_Dev('GetScheduledCassettes', WorkOrder) Set_Property(@Window, '@WORK_ORDER_DETAIL', WorkOrderDetail) Set_Property(@Window, '@REMAINING_TO_PROCESS', RemainingToProcess) Set_Property(@Window, '@REMAINING_TO_SCHEDULE', RemainingToSchedule) Set_Property(@Window, '@MINUTES_PER_WAFER_ADJUSTED', MinutesPerWaferAdjusted) Set_Property(@Window, '@SCHEDULED_WFR_QTY', ScheduledWfrQty) Set_Property(@Window, '@WO_SCHED_CASS', WOSchedCass) return UpdateWorkOrderDetails: MinutesPerWaferAdjusted = '' WorkOrder = Get_Property(@Window : '.WO_NO', 'TEXT') ReactNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') CurrDTM = Datetime() If WorkOrder NE '' then PSNBlocked = False$ WorkOrdersArray = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS') Convert @TM to @FM in WorkOrdersArray Convert @STM to @VM in WorkOrdersArray WorkOrderList = WorkOrdersArray<1> PSNBlockedList = WorkOrdersArray<5> Locate WorkOrder in WorkOrderList using @VM setting vPos then PSNBlocked = PSNBlockedList<0, vPos> If PSNBlocked EQ '' then Set_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE', False$) WorkOrderDetail = Get_Property(@Window, '@WORK_ORDER_DETAIL') EpiPart = WorkOrderDetail TotalWafers = WorkOrderDetail RemainingToProcess = Get_Property(@Window, '@REMAINING_TO_PROCESS') RemainingToSchedule = Get_Property(@Window, '@REMAINING_TO_SCHEDULE') If TotalWafers GT 0 then Complete = ( (TotalWafers - RemainingToProcess) / TotalWafers) * 100 end else Complete = 0 end ReactorType = Get_Property(@Window : '.REACTOR_TYPE', 'TEXT') MinutesPerWaferAdjusted = Get_Property(@Window, '@MINUTES_PER_WAFER_ADJUSTED') ScheduledWfrQty = Get_Property(@Window, '@SCHEDULED_WFR_QTY') AvailableWfrQty = RemainingToSchedule EventWafers = Get_Property(@Window:'.SCHEDULE_WAFERS', 'TEXT') If ( (EventWafers EQ '') and (MinutesPerWaferAdjusted NE '') ) then EventWafers = AvailableWfrQty Set_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT', AvailableWfrQty) end // Are any cassettes already engaged? WOSchedCass = Get_Property(@Window, '@WO_SCHED_CASS') WOLastCass = WOSchedCass[-1, 'B':@VM] CassNo = WOLastCass + 1 EpiPro = (Xlate('WO_LOG', WorkOrder, 'REACT_TYPE', 'X') EQ 'EPP') EventEngaged = False$ RDSNo = '' * If @User4 EQ 'DANIEL_ST' then ! New Code - UAT began 11/10/2021 TotalCass = SRP_Math('CEILING', (TotalWafers / 25)) If WOSchedCass NE '' then WOLastCass = WOSchedCass[-1, 'B':@VM] end else WOLastCass = 0 end UnprocessedCassettes = '' ProcessedCassettes = '' For CassIndex = 0 to TotalCass CurrStatus = '' Skip = False$ CassProcessed = False$ CassNo = WOLastCass + CassIndex If CassNo GT 0 then RDSNo = '' // Is this cassette processed? If EpiPro then // EpiPro --- Get WM_IN record and see if it has any wafers remaining. WMIKey = WorkOrder:'*1*':CassNo RemWfrs = Xlate('WM_IN', WMIKey, 'REM_WFRS', 'X') If RemWfrs EQ 0 then CassProcessed = True$ end else // Non-EpiPro --- Get RDS number and check if DATE_OUT is populated WOMatKey = WorkOrder:'*':CassNo RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') If CassIndex EQ 0 then // This is necessary as we had to set CassIndex = 0 for EpiPro. // EpiPro can cassettes can be in two different work order events. Skip = True$ end CurrStatus = Xlate('WO_MAT', WOMatKey, 'CURR_STATUS', 'X') end If ( (RDSNo NE '') and (CurrStatus NE '') ) then DateOut = Xlate('RDS', RDSNo, 'DATE_OUT', 'X') If ( (DateOut NE '') or (CurrStatus EQ 'REJ') or (CurrStatus EQ 'MT') ) then CassProcessed = True$ end If Skip EQ False$ then If CassProcessed then ProcessedCassettes<0, -1> = CassNo end else UnProcessedCassettes<0, -1> = CassNo end end end Next CassIndex CassToSched = SRP_Array('Join', UnprocessedCassettes, ProcessedCassettes, 'OR', @VM) CassToSched = SRP_Array('SortSimpleList', CassToSched, 'AscendingNumbers', @VM) WOMatKeys = '' For each SchedCassNo in CassToSched using @VM setting vPos WOMatKeys<0, vPos> = WorkOrder:'*':SchedCassNo Next SchedCassNo * SchedRDSNos = Xlate('WO_MAT', WOMatKeys, 'RDS_NO', 'X') If EpiPro then FirstCass = CassToSched<0, 1> If FirstCass NE '' then WMIKey = WorkOrder:'*1*':FirstCass SchedRDSNos = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X') // Look at the next slot to be scheduled! SchedSlot = Mod(ScheduledWfrQty, 25) + 1 SchedRDSNos = Field(SchedRDSNos, @VM, SchedSlot, (25 - SchedSlot)) end end else SchedRDSNos = Xlate('WO_MAT', WOMatKeys, 'RDS_NO', 'X') end SchedDateIns = Xlate('RDS', SchedRDSNos, 'DATE_IN', 'X') If SchedDateIns NE '' then FirstLoad = '' For each SchedDateIn in SchedDateIns using @VM setting vPos If SchedDateIn NE '' then RDSNo = SchedRDSNos<0, vPos> EventEngaged = True$ end Until EventEngaged EQ True$ Next SchedDateIn end * end else * ! Old code * // Is this cassette processed? * If EpiPro then * // EpiPro --- Get WM_IN record and see if RDS in slot 1 has DATE_IN field populated * WMIKey = WorkOrder:'*1*':CassNo * RDSNos = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X') * RDSNo = RDSNos<0, 1> * end else * // Non-EpiPro --- Get RDS number and check if DATE_IN is populated * WOMatKey = WorkOrder:'*':CassNo * RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') * end * If RDSNo NE '' then * DateIn = Xlate('RDS', RDSNo, 'DATE_IN', 'X') * If DateIn NE '' then EventEngaged = True$ * end * end If EventEngaged EQ True$ then // Set the start DTM of this event to the DATETIME_IN of the first cassette that was loaded. StartDTM = Xlate('RDS', RDSNo, 'DATETIME_IN', 'X') ! This needs to be updated to support EpiPro logic. We need to look at the datetime_in ! of the first remaining wafer (RDS), not the first wafer (RDS) in the WM_IN cassette as ! it may have already been processed. // Disable Start Date Options Group Set_Property(@Window:'.OPTIONS_GRP_START_DTM', 'ENABLED', False$) // Calculate the end DTM based on the number of wafers remaining to process. // Round up in case the number of wafers is not a multiple of 25. EventCassettes = SRP_Math('CEILING', (EventWafers / 25)) ProcessedCassettes = '' UnprocessedCassettes = '' For CassIndex = 1 to EventCassettes CassProcessed = False$ CassNo = WOLastCass + CassIndex RDSNo = '' // Is this cassette processed? If EpiPro then // EpiPro --- Get WM_IN record and see if RDS in slot 25 has DATE_OUT field populated WMIKey = WorkOrder:'*1*':CassNo RDSNos = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X') RDSNo = RDSNos<0, 25> end else // Non-EpiPro --- Get RDS number and check if DATE_OUT is populated WOMatKey = WorkOrder:'*':CassNo RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') CurrStatus = CurrStatus = Xlate('WO_MAT', WOMatKey, 'CURR_STATUS', 'X') end If RDSNo NE '' then DateOut = Xlate('RDS', RDSNo, 'DATE_OUT', 'X') If ( (DateOut NE '') or (CurrStatus EQ 'REJ') or (CurrStatus EQ 'MT') ) then CassProcessed = True$ end If CassProcessed then ProcessedCassettes<0, -1> = CassNo end else UnprocessedCassettes<0, -1> = CassNo end Next CassIndex UnprocessedWfrQty = 0 For each UnprocCassNo in UnprocessedCassettes using @VM setting vPos WOMatKey = WorkOrder:'*':UnprocCassNo If RowExists('WO_MAT', WOMatKey) then CassQty = Xlate('WO_MAT', WOMatKey, 'WAFER_QTY', 'X') UnprocessedWfrQty += CassQty end else // Material for this cassette has not yet been released. Assume quantity of 25 wafers. UnprocessedWfrQty += 25 end Next UnprocCassNo DurationEstimate = Schedule_Services_Dev('GetEventDuration', WorkOrder, UnprocessedWfrQty) If Error_Services('NoError') then EndDTM = CurrDTM + DurationEstimate end end else // Event not engaged yet. Use previous event's end DTM unless it is in the past. // In that event use the current DTM. Set_Property(@Window:'.OPTIONS_GRP_START_DTM', 'ENABLED', True$) NextStartDTM = Get_Property(@Window, '@NEXT_START_DTM') CurrDTM = Datetime() If NextStartDTM GT CurrDTM then StartDTM = NextStartDTM end else StartDTM = CurrDTM end // Calculate End DTM based on the start DTM in the form and duration estimate DurationEstimate = Schedule_Services_Dev('GetEventDuration', WorkOrder, EventWafers) Set_Property(@Window:'.SCHEDULE_START_DTM', 'INVALUE', StartDTM) EndDTM = StartDTM + DurationEstimate end If MinutesPerWaferAdjusted EQ '' then Msg(@Window, 'Warning: ' : EpiPart : ' appears to be missing minutes per wafer values for ' : ReactorType) Set_Property(@Window:'.CLOSE_BUTTON', 'FOCUS', True$) end end else // PSN Blocked Set_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE', True$) end end If ( (WorkOrder NE '') and (MinutesPerWaferAdjusted NE '') ) then Set_Property(@Window : '.EPI_PART', 'TEXT', EpiPart) Set_Property(@Window : '.TOTAL_WAFERS', 'TEXT', TotalWafers) Set_Property(@Window : '.TOTAL_REMAINING', 'TEXT', RemainingToProcess) Set_Property(@Window : '.PERCENT_COMPLETE', 'TEXT', Oconv(Complete, 'MD0[ %]S')) Set_Property(@Window : '.SCHEDULE_START_DTM', 'INVALUE', StartDTM) Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', EndDTM) DurationDaysRounded = SRP_Math('ROUND', DurationEstimate, 1) Set_Property(@Window : '.DAYS', 'DEFPROP', DurationDaysRounded) Set_Property(@Window : '.AVAILABLE_QTY', 'TEXT', AvailableWfrQty) end else Error_Services('DisplayError') Set_Property(@Window : '.EPI_PART', 'TEXT', '') Set_Property(@Window : '.TOTAL_WAFERS', 'TEXT', '') Set_Property(@Window : '.TOTAL_REMAINING', 'TEXT', '') Set_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT', '') Set_Property(@Window : '.PERCENT_COMPLETE', 'TEXT', '') Set_Property(@Window : '.SCHEDULE_END_DTM', 'INVALUE', '') Set_Property(@Window : '.DAYS', 'DEFPROP', '') end GoSub EnableSaveButton return UpdateWorkOrderList: WorkOrders = '' // Adding work order. WorkOrders = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS') If WorkOrders EQ '' then // Get the current reactor type and size so the GetReactor and GetUnscheduledWorkOrders service results // can be filtered down to only those items that match the same type and size. ReactorNo = Get_Property(@Window : '.REACTOR_NO', 'TEXT') ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo) ReactorType = ReactorRec SusceptorSize = ReactorRec WorkOrders = Schedule_Services_Dev('GetAvailableWorkOrders', ReactorType, '', ReactorNo) WorkOrders = SRP_Array('Rotate', WorkOrders) Convert @FM to @TM in WorkOrders Convert @VM to @STM in WorkOrders Set_Property(@Window, '@UNSCHEDULED_WORK_ORDERS', WorkOrders) end EditLine = @Window : ';WO_NO' Set_Property(@Window : '.OLE_SUBCLASS', 'OLE.ComboData[' : EditLine : ']', WorkOrders) return PopulateControls: Set_Property(@Window, 'TEXT', 'Scheduler Actions - Add Work Order Event') Set_Property(@Window : '.REACTOR_NO', 'NEXT', @Window : '.SCHEDULE_START_DTM') Set_Property(@Window : '.DESCRIPTION', 'NEXT', @Window : '.REACTOR_NO') WorkOrders = Get_Property(@Window, '@UNSCHEDULED_WORK_ORDERS') WONo = '' ScheduleKeyID = '' GoSub UpdateWorkOrderList GoSub UpdateScheduleDetails GoSub UpdateReactorDetails GoSub UpdateCustomerName GoSub EnableSaveButton Set_Property(@Window : '.REACTOR_NO', 'FOCUS', True$) return EnableSaveButton: PSNBlocked = Get_Property(@Window:'.LBL_PSN_BLOCK', 'VISIBLE') SchedQty = Get_Property(@Window : '.SCHEDULE_WAFERS', 'TEXT') AvailQty = Get_Property(@Window : '.AVAILABLE_QTY', 'TEXT') ButtonEnabled = ( (SchedQty NE '') and (SchedQty NE 0) and (AvailQty NE 0) and (SchedQty LE AvailQty) and (PSNBlocked EQ False$) ) Set_Property(@Window : '.SAVE_BUTTON', 'ENABLED', ButtonEnabled) return