Function NDW_Scheduler_Add_WO_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 : NDW_Scheduler_Add_WO_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 NDW_SCHEDULER_ADD_WO $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) Declare function SRP_Array, Schedule_Services, Database_Services, Work_Order_Services, SRP_Math Declare function Epi_Part_Services, Datetime Declare subroutine obj_Appwindow, Center_Window, Schedule_Services, 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) If LastSchedDetRec GT SchedStartDTM then // The datetime passed in by the user (via where they right-clicked on the schedule) // is before the next available time slot. NextStartDTM = LastSchedDetRec end end If NextStartDTM NE '' then StartDTM = NextStartDTM end else StartDTM = SchedStartDTM end Set_Property(@Window, '@NEXT_START_DTM', StartDTM) 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 available quantity.' Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEntID, '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) 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 available quantity.' Form_Services('DisplayControlMessage', Message, 'Invalid Quantity', CtrlEntID, '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('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('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('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('GetRemainingWafers', WorkOrder) RemainingToSchedule = Schedule_Services('GetUnscheduledWfrQty', WorkOrder) EpiPart = WorkOrderDetail MinutesPerWaferAdjusted = Epi_Part_Services('GetAdjustedWafersPerDayScheduler', EpiPart, ReactorType) ScheduledWfrQty = Schedule_Services('GetScheduledWfrQty', WorkOrder) WOSchedCass = Schedule_Services('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 UnprocessedCassettes = '' ProcessedCassettes = '' // Look at the next slot to be scheduled! // Get the number of wafers scheduled up to this event. // This should give us the correct starting wafer slot. StartCassNo = SRP_Math('CEILING', ( (ScheduledWfrQty + 1) / 25)) If StartCassNo EQ 0 then StartCassNo = 1 EventNumCass = SRP_Math('CEILING', (EventWafers / 25)) FirstRDS = '' EventEngaged = False$ If ReactorType _EQC 'EpiPro' then // Example: Event starts on WM_IN cassette 6 (i.e. 172125*1*6), slot 13. StartSlotNo = Mod(ScheduledWfrQty, 25) + 1 StopCassNo = StartCassNo + EventNumCass - 1 StopSlotNo = Mod((ScheduledWfrQty + EventWafers), 25) If StopSlotNo EQ 0 then StopSlotNo = 25 For CassIndex = 1 to EventNumCass CassNo = (StartCassNo + CassIndex - 1) WMIKey = WorkOrder:'*1*':CassNo WMIRdsKeys = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X') EventCassRDSKeys = '' Begin Case Case CassNo EQ StartCassNo StartIndex = StartSlotNo StopIndex = 25 Case CassNo EQ StopCassNo StartIndex = 1 StopIndex = StopSlotNo Case ( (CassNo EQ StartCassNo) and (CassNo EQ StopCassNo) ) StartIndex = StartSlotNo StopIndex = StopSlotNo Case Otherwise$ StartIndex = 1 StopIndex = 25 End Case For SlotIndex = StartIndex to StopIndex If FirstRDS EQ '' then FirstRDS = WMIRdsKeys<0, SlotIndex> FirstLoad = Xlate('RDS', FirstRDS, 'DATE_IN', 'X') EventEngaged = (FirstLoad NE '') end EventCassRDSKeys<0, -1> = WMIRdsKeys<0, SlotIndex> Next SlotIndex EventCassRDSKeys = SRP_Array('Clean', EventCassRDSKeys, 'TrimAndMakeUnique', @VM) // Now we have a list of RDS keys that only pertain to this event. If EventCassRDSKeys NE '' then // Are all of the RDS runs unloaded? NumUnloadedRDS = 0 UnloadDtms = Xlate('RDS', EventCassRDSKeys, 'DATETIME_OUT', 'X') If UnloadDtms NE '' then For each UnloadDtm in UnloadDtms using @VM If UnloadDtm NE '' then NumUnloadedRds += 1 Next UnloadDtm end NumRDS = DCount(EventCassRDSKeys, @VM) CassProcessed = (NumRds EQ NumUnloadedRds) end else CassProcessed = False$ end If CassProcessed then ProcessedCassettes<0, -1> = CassNo end else UnprocessedCassettes<0, -1> = CassNo end Next CassIndex ProcessedCassettes = SRP_Array('Join', ProcessedCassettes, UnprocessedCassettes, 'NOT', @VM) // Estimate event unprocessed wafer quantity for duration estimate NumUnprocCass = DCount(UnprocessedCassettes, @VM) UnprocessedWfrQty = ( (NumUnprocCass - 1) * 25 ) + StopSlotNo end else // Example: Event starts on WO_MAT cassette 7. We don't need to schedule down to the // wafer levels with non-epipro work order events. For CassIndex = 1 to EventNumCass CassNo = (StartCassNo + CassIndex) WOMatKey = WorkOrder:'*':CassNo RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') If FirstRDS EQ '' then FirstRDS = RDSNo FirstLoad = Xlate('RDS', FirstRDS, 'DATE_IN', 'X') EventEngaged = (FirstLoad NE '') end UnloadDtm = Xlate('RDS', RDSNo, 'DATETIME_OUT', 'X') CassProcessed = (UnloadDtm NE '') If CassProcessed then ProcessedCassettes<0, -1> = CassNo end else UnprocessedCassettes<0, -1> = CassNo end Next CassIndex NumUnprocCass = DCount(UnprocessedCassettes, @VM) UnprocessedWfrQty = NumUnprocCass * 25 end // Need to check if user is scheduling part of the work order on another reactor. PrevSchedEvents = Schedule_Services('GetScheduledEvents', WorkOrder) If EventEngaged and (PrevSchedEvents EQ '') then // Event already engaged // Set start DTM to first load dtm unless the work order is switching reactors or split Set_Property(@Window:'.OPTIONS_GRP_START_DTM', 'ENABLED', False$) StartDtm = Xlate('RDS', FirstRDS, 'DATETIME_IN', 'X') If StartDtm EQ '' then StartDtm = Get_Property(@Window, '@NEXT_START_DTM') DurationEstimate = Schedule_Services('GetEventDuration', WorkOrder, UnprocessedWfrQty) EndDTM = StartDtm + DurationEstimate 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('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('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