Modified UpdateQAMet service to support reactor scheduled metrology tests
This commit is contained in:
committed by
Stieber Daniel (CSC FI SPS MESLEO)
parent
f07e4476a7
commit
245f832445
@ -59,11 +59,11 @@ If Event EQ 'OLE' then
|
|||||||
Transfer Param1 to Event
|
Transfer Param1 to Event
|
||||||
Transfer Param2 to Param1
|
Transfer Param2 to Param1
|
||||||
Transfer Param3 to Param2
|
Transfer Param3 to Param2
|
||||||
* Transfer Param4 to Param3
|
Transfer Param4 to Param3
|
||||||
* Transfer Param5 to Param4
|
Transfer Param5 to Param4
|
||||||
* Transfer Param6 to Param5
|
Transfer Param6 to Param5
|
||||||
* Transfer Param7 to Param6
|
Transfer Param7 to Param6
|
||||||
* Transfer Param8 to Param7
|
Transfer Param8 to Param7
|
||||||
end
|
end
|
||||||
|
|
||||||
GoToEvent Event for CtrlEntID
|
GoToEvent Event for CtrlEntID
|
||||||
@ -226,14 +226,17 @@ Event PUB_ENG_OPTIONS.CLICK()
|
|||||||
End Case
|
End Case
|
||||||
|
|
||||||
If ServiceModules NE '' then
|
If ServiceModules NE '' then
|
||||||
Def = ""
|
ErrorMsg = ''
|
||||||
|
Def = ''
|
||||||
Def<MCAPTION$> = Caption
|
Def<MCAPTION$> = Caption
|
||||||
Def<MTYPE$> = "GC"
|
Def<MTYPE$> = "GC"
|
||||||
Def<MEXTENT$> = NumRows
|
Def<MEXTENT$> = NumRows
|
||||||
Def<MTEXTWIDTH$> = 600
|
Def<MTEXTWIDTH$> = 600
|
||||||
MsgUp = Msg(@WINDOW, Def) ;* Start gas guage message
|
Def<MCOL$> = -2
|
||||||
|
Def<MROW$> = -2
|
||||||
|
MsgUp = Msg(@Window, Def) ;* Start gas guage message
|
||||||
For each WOMatKey in WOMatKeys using @VM setting vPos
|
For each WOMatKey in WOMatKeys using @VM setting vPos
|
||||||
Running = Msg(@WINDOW, MsgUp, vPos, MSGINSTUPDATE$) ;* Update gas guage
|
Running = Msg(@Window, MsgUp, vPos, MSGINSTUPDATE$) ;* Update gas guage
|
||||||
For each ServiceModule in ServiceModules using @VM setting sPos
|
For each ServiceModule in ServiceModules using @VM setting sPos
|
||||||
Service = Services<0, sPos>
|
Service = Services<0, sPos>
|
||||||
If Service = 'UpdateRDSLayerSpecs' then
|
If Service = 'UpdateRDSLayerSpecs' then
|
||||||
@ -243,21 +246,33 @@ Event PUB_ENG_OPTIONS.CLICK()
|
|||||||
Ans = Function(@ServiceModule(Service, WOMatKey))
|
Ans = Function(@ServiceModule(Service, WOMatKey))
|
||||||
end
|
end
|
||||||
If Error_Services('HasError') then
|
If Error_Services('HasError') then
|
||||||
Error_Services('DisplayError')
|
ErrorMsg = Error_Services('GetMessage')
|
||||||
end
|
end
|
||||||
|
Until (ErrorMsg NE '')
|
||||||
Next ServiceModule
|
Next ServiceModule
|
||||||
|
Until (ErrorMsg NE '')
|
||||||
Next WOMatKey
|
Next WOMatKey
|
||||||
Msg(@WINDOW,MsgUp) ;* Take gas guage down
|
|
||||||
|
Msg(@Window,MsgUp) ;* Take gas guage down
|
||||||
|
If (ErrorMsg NE '') then
|
||||||
|
Msg(@Window, '', 'OK', '', 'Operation Aborted':@FM:ErrorMsg)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
If Error_Services('NoError') then
|
Def = ''
|
||||||
Def = ""
|
Def<MCOL$> = -2
|
||||||
|
Def<MROW$> = -2
|
||||||
|
If (ErrorMsg EQ '') then
|
||||||
Def<MICON$> = '*'
|
Def<MICON$> = '*'
|
||||||
Def<MCAPTION$> = 'Success'
|
Def<MCAPTION$> = 'Success'
|
||||||
Def<MTEXT$> = "Update complete!"
|
Def<MTEXT$> = 'Update complete!'
|
||||||
Def<MTYPE$> = "BO"
|
end else
|
||||||
MsgUp = Msg(@window, Def)
|
Def<MICON$> = 'H'
|
||||||
|
Def<MCAPTION$> = 'Update failed!'
|
||||||
|
Def<MTEXT$> = ErrorMsg
|
||||||
end
|
end
|
||||||
|
Def<MTYPE$> = "BO"
|
||||||
|
MsgUp = Msg(@Window, Def, 'OK')
|
||||||
end
|
end
|
||||||
|
|
||||||
end event
|
end event
|
||||||
@ -277,7 +292,7 @@ Event PUB_ON_HOLD.CLICK()
|
|||||||
HoldEntity = 'RDS'
|
HoldEntity = 'RDS'
|
||||||
HoldType = 'HOLD'
|
HoldType = 'HOLD'
|
||||||
HoldData = ''
|
HoldData = ''
|
||||||
HoldData = Dialog_Box('DIALOG_HOLD',@WINDOW,Transition:@FM:@FM:HoldType)
|
HoldData = Dialog_Box('DIALOG_HOLD',@Window,Transition:@FM:@FM:HoldType)
|
||||||
If HoldData NE 'Cancel' then
|
If HoldData NE 'Cancel' then
|
||||||
GoSub GetView
|
GoSub GetView
|
||||||
Hold_Services('EnableMultipleHolds', WOMatKeys, HoldEntity, RDSKeys, 'NDW_RDS_QUERY', '', HoldData)
|
Hold_Services('EnableMultipleHolds', WOMatKeys, HoldEntity, RDSKeys, 'NDW_RDS_QUERY', '', HoldData)
|
||||||
@ -289,7 +304,7 @@ Event PUB_ON_HOLD.CLICK()
|
|||||||
MsgInfo<MTYPE$> = 'BNY'
|
MsgInfo<MTYPE$> = 'BNY'
|
||||||
MsgInfo<MTEXT$> = 'Hold Successful. Would you like to print label(s)?'
|
MsgInfo<MTEXT$> = 'Hold Successful. Would you like to print label(s)?'
|
||||||
MsgInfo<MICON$> = '!'
|
MsgInfo<MICON$> = '!'
|
||||||
PrintLabel = Msg(@WINDOW,MsgInfo,'')
|
PrintLabel = Msg(@Window,MsgInfo,'')
|
||||||
HoldBy = HoldData<1>
|
HoldBy = HoldData<1>
|
||||||
Reason = HoldData<2>
|
Reason = HoldData<2>
|
||||||
Stage = HoldData<4>
|
Stage = HoldData<4>
|
||||||
@ -333,7 +348,7 @@ Event PUB_OFF_HOLD.CLICK()
|
|||||||
Transition = True$
|
Transition = True$
|
||||||
HoldType = 'HOLD'
|
HoldType = 'HOLD'
|
||||||
HoldData = ''
|
HoldData = ''
|
||||||
HoldData = Dialog_Box('DIALOG_HOLD',@WINDOW,Transition:@FM:@FM:HoldType)
|
HoldData = Dialog_Box('DIALOG_HOLD',@Window,Transition:@FM:@FM:HoldType)
|
||||||
If HoldData NE 'Cancel' then
|
If HoldData NE 'Cancel' then
|
||||||
GoSub GetView
|
GoSub GetView
|
||||||
Hold_Services('DisableMultipleHolds', WOMatKeys, 'RDS', RDSKeys, 'NDW_RDS_QUERY', '', HoldData)
|
Hold_Services('DisableMultipleHolds', WOMatKeys, 'RDS', RDSKeys, 'NDW_RDS_QUERY', '', HoldData)
|
||||||
@ -666,7 +681,7 @@ CheckSelectedForHolds:
|
|||||||
Until HoldOnFlag EQ True$ and HoldOffFlag EQ True$
|
Until HoldOnFlag EQ True$ and HoldOffFlag EQ True$
|
||||||
Next K
|
Next K
|
||||||
end
|
end
|
||||||
if MemberOf(@USER4, 'ENG_TECH') OR MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') then
|
if MemberOf(@User4, 'ENG_TECH') OR MemberOf(@User4, 'LEAD') OR MemberOf(@User4, 'SUPERVISOR') then
|
||||||
// IF ANY SELECTED LOTS ARE ON HOLD, ENABLE PUB_OFF_HOLD
|
// IF ANY SELECTED LOTS ARE ON HOLD, ENABLE PUB_OFF_HOLD
|
||||||
Set_Property(@Window:'.PUB_OFF_HOLD', 'ENABLED', HoldOffFlag)
|
Set_Property(@Window:'.PUB_OFF_HOLD', 'ENABLED', HoldOffFlag)
|
||||||
end else
|
end else
|
||||||
|
@ -2035,9 +2035,10 @@ RETURN
|
|||||||
GetQAMet:
|
GetQAMet:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
PSNo = Parms[1,@RM]
|
PSNo = Parms[1,@RM]
|
||||||
PSRec = Parms[COL2()+1,@RM]
|
PSRec = Parms[COL2()+1,@RM]
|
||||||
ReactSchedFlag = Parms[COL2()+1,@RM]
|
ReactSchedFlag = Parms[COL2()+1,@RM]
|
||||||
|
AllSchedFlag = Parms[COL2()+1,@RM]
|
||||||
|
|
||||||
GOSUB StageSortKeys
|
GOSUB StageSortKeys
|
||||||
|
|
||||||
@ -2055,12 +2056,11 @@ GetQAMet:
|
|||||||
|
|
||||||
FOR TestNo = 1 TO MetCnt
|
FOR TestNo = 1 TO MetCnt
|
||||||
|
|
||||||
IF PSStageRec<PRS_STAGE_MET_TEST$,TestNo> NE '' THEN
|
IF (PSStageRec<PRS_STAGE_MET_TEST$,TestNo> NE '') THEN
|
||||||
|
|
||||||
IF ReactSchedFlag = 1 THEN
|
Begin Case
|
||||||
|
Case AllSchedFlag
|
||||||
IF PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo> = 1 THEN
|
// Return all scheduled metrology
|
||||||
|
|
||||||
ResLineCnt += 1
|
ResLineCnt += 1
|
||||||
Result<COL$QA_MET_STAGE,ResLineCnt> = FIELD(PSStageKey,'*',2)
|
Result<COL$QA_MET_STAGE,ResLineCnt> = FIELD(PSStageKey,'*',2)
|
||||||
Result<COL$QA_MET_TEST,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TEST$,TestNo>
|
Result<COL$QA_MET_TEST,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TEST$,TestNo>
|
||||||
@ -2077,36 +2077,56 @@ GetQAMet:
|
|||||||
Result<COL$QA_MET_WFR_QTY,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_QTY$,TestNo>
|
Result<COL$QA_MET_WFR_QTY,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_QTY$,TestNo>
|
||||||
Result<COL$QA_MET_WFR_TYPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_TYPE$,TestNo> ;* Possible Future
|
Result<COL$QA_MET_WFR_TYPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_TYPE$,TestNo> ;* Possible Future
|
||||||
Result<COL$QA_MET_SHIP_DOC,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SHIP_DOC$,TestNo> ;* 12/3/2016 JCH for Mark
|
Result<COL$QA_MET_SHIP_DOC,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SHIP_DOC$,TestNo> ;* 12/3/2016 JCH for Mark
|
||||||
Result<COL$QA_MET_PHASE_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PHASE_MIN$,TestNo>
|
Result<COL$QA_MET_PHASE_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PHASE_MIN$,TestNo>
|
||||||
|
|
||||||
END
|
Case ReactSchedFlag
|
||||||
|
// Just return reactor scheduled metrology
|
||||||
END ELSE
|
IF (PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo> EQ True$) THEN
|
||||||
|
ResLineCnt += 1
|
||||||
ResLineCnt += 1
|
Result<COL$QA_MET_STAGE,ResLineCnt> = FIELD(PSStageKey,'*',2)
|
||||||
Result<COL$QA_MET_STAGE,ResLineCnt> = FIELD(PSStageKey,'*',2)
|
Result<COL$QA_MET_TEST,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TEST$,TestNo>
|
||||||
Result<COL$QA_MET_TEST,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TEST$,TestNo>
|
Result<COL$QA_MET_PROP,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PROP$,TestNo>
|
||||||
Result<COL$QA_MET_PROP,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PROP$,TestNo>
|
Result<COL$QA_MET_TOOL_CLASS,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TOOL_CLASS$,TestNo>
|
||||||
Result<COL$QA_MET_TOOL_CLASS,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TOOL_CLASS$,TestNo>
|
Result<COL$QA_MET_RECIPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE$,TestNo>
|
||||||
Result<COL$QA_MET_RECIPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE$,TestNo>
|
Result<COL$QA_MET_RECIPE_PATTERN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE_PATTERN$,TestNo>
|
||||||
Result<COL$QA_MET_RECIPE_PATTERN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE_PATTERN$,TestNo>
|
Result<COL$QA_MET_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MIN$,TestNo>
|
||||||
Result<COL$QA_MET_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MIN$,TestNo>
|
Result<COL$QA_MET_MAX,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MAX$,TestNo>
|
||||||
Result<COL$QA_MET_MAX,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MAX$,TestNo>
|
Result<COL$QA_MET_SLOT,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SLOT$,TestNo>
|
||||||
Result<COL$QA_MET_SLOT,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SLOT$,TestNo>
|
Result<COL$QA_MET_REACT_SCHED,ResLineCnt> = PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo>
|
||||||
Result<COL$QA_MET_REACT_SCHED,ResLineCnt> = PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo>
|
Result<COL$QA_MET_INTERVAL,ResLineCnt> = PSStageRec<PRS_STAGE_MET_INTERVAL$,TestNo>
|
||||||
Result<COL$QA_MET_INTERVAL,ResLineCnt> = PSStageRec<PRS_STAGE_MET_INTERVAL$,TestNo>
|
Result<COL$QA_MET_START,ResLineCnt> = PSStageRec<PRS_STAGE_MET_START$,TestNo>
|
||||||
Result<COL$QA_MET_START,ResLineCnt> = PSStageRec<PRS_STAGE_MET_START$,TestNo>
|
Result<COL$QA_MET_WFR_QTY,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_QTY$,TestNo>
|
||||||
Result<COL$QA_MET_WFR_QTY,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_QTY$,TestNo>
|
Result<COL$QA_MET_WFR_TYPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_TYPE$,TestNo> ;* Possible Future
|
||||||
Result<COL$QA_MET_WFR_TYPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_TYPE$,TestNo> ;* Possible future
|
Result<COL$QA_MET_SHIP_DOC,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SHIP_DOC$,TestNo> ;* 12/3/2016 JCH for Mark
|
||||||
Result<COL$QA_MET_SHIP_DOC,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SHIP_DOC$,TestNo> ;* 12/3/2016 JCH for Mark
|
Result<COL$QA_MET_PHASE_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PHASE_MIN$,TestNo>
|
||||||
Result<COL$QA_MET_PHASE_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PHASE_MIN$,TestNo>
|
END
|
||||||
|
|
||||||
END ;* End of check for ReactSchedFlag
|
Case Otherwise$
|
||||||
|
// Just return work order scheduled metrology
|
||||||
|
IF (PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo> NE True$) THEN
|
||||||
|
ResLineCnt += 1
|
||||||
|
Result<COL$QA_MET_STAGE,ResLineCnt> = FIELD(PSStageKey,'*',2)
|
||||||
|
Result<COL$QA_MET_TEST,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TEST$,TestNo>
|
||||||
|
Result<COL$QA_MET_PROP,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PROP$,TestNo>
|
||||||
|
Result<COL$QA_MET_TOOL_CLASS,ResLineCnt> = PSStageRec<PRS_STAGE_MET_TOOL_CLASS$,TestNo>
|
||||||
|
Result<COL$QA_MET_RECIPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE$,TestNo>
|
||||||
|
Result<COL$QA_MET_RECIPE_PATTERN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_RECIPE_PATTERN$,TestNo>
|
||||||
|
Result<COL$QA_MET_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MIN$,TestNo>
|
||||||
|
Result<COL$QA_MET_MAX,ResLineCnt> = PSStageRec<PRS_STAGE_MET_MAX$,TestNo>
|
||||||
|
Result<COL$QA_MET_SLOT,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SLOT$,TestNo>
|
||||||
|
Result<COL$QA_MET_REACT_SCHED,ResLineCnt> = PSStageRec<PRS_STAGE_MET_REACT_SCHED$,TestNo>
|
||||||
|
Result<COL$QA_MET_INTERVAL,ResLineCnt> = PSStageRec<PRS_STAGE_MET_INTERVAL$,TestNo>
|
||||||
|
Result<COL$QA_MET_START,ResLineCnt> = PSStageRec<PRS_STAGE_MET_START$,TestNo>
|
||||||
|
Result<COL$QA_MET_WFR_QTY,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_QTY$,TestNo>
|
||||||
|
Result<COL$QA_MET_WFR_TYPE,ResLineCnt> = PSStageRec<PRS_STAGE_MET_WFR_TYPE$,TestNo> ;* Possible Future
|
||||||
|
Result<COL$QA_MET_SHIP_DOC,ResLineCnt> = PSStageRec<PRS_STAGE_MET_SHIP_DOC$,TestNo> ;* 12/3/2016 JCH for Mark
|
||||||
|
Result<COL$QA_MET_PHASE_MIN,ResLineCnt> = PSStageRec<PRS_STAGE_MET_PHASE_MIN$,TestNo>
|
||||||
|
END
|
||||||
|
|
||||||
|
End Case
|
||||||
END
|
END
|
||||||
NEXT TestNo
|
NEXT TestNo
|
||||||
NEXT N
|
NEXT N
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ COMPILE FUNCTION obj_WO_React(Method,Parms)
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
DECLARE FUNCTION Get_Status, Msg, Utility, obj_Tables, NextKey, obj_Prod_Spec, obj_WO_Mat_QA, GetTickCount
|
DECLARE FUNCTION Get_Status, Msg, Utility, obj_Tables, NextKey, obj_Prod_Spec, obj_WO_Mat_QA, GetTickCount
|
||||||
Declare function Environment_Services, Database_Services
|
Declare function Environment_Services, Database_Services
|
||||||
DECLARE SUBROUTINE Set_Status, Msg, obj_Tables, RList, ErrMsg, Btree.Extract, obj_WO_Mat_QA, Mona_Services
|
DECLARE SUBROUTINE Set_Status, Msg, obj_Tables, RList, ErrMsg, Btree.Extract, obj_WO_Mat_QA, Mona_Services
|
||||||
@ -70,222 +69,213 @@ RETURN Result
|
|||||||
AddRdsNo:
|
AddRdsNo:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
StartTick = GetTickCount()
|
StartTick = GetTickCount()
|
||||||
MetricName = 'AddRdsNo'
|
MetricName = 'AddRdsNo'
|
||||||
|
|
||||||
WONo = Parms[1,@RM]
|
WONo = Parms[1,@RM]
|
||||||
StepNo = Parms[COL2()+1,@RM]
|
StepNo = Parms[COL2()+1,@RM]
|
||||||
ReactNo = Parms[COL2()+1,@RM]
|
ReactNo = Parms[COL2()+1,@RM]
|
||||||
RdsNo = Parms[COL2()+1,@RM]
|
RdsNo = Parms[COL2()+1,@RM]
|
||||||
CassNo = Parms[COL2()+1,@RM]
|
CassNo = Parms[COL2()+1,@RM]
|
||||||
|
|
||||||
IF WONo = '' THEN RETURN
|
IF WONo = '' THEN RETURN
|
||||||
IF StepNo = '' THEN RETURN
|
IF StepNo = '' THEN RETURN
|
||||||
IF ReactNo = '' THEN RETURN
|
IF ReactNo = '' THEN RETURN
|
||||||
IF RdsNo = '' THEN RETURN
|
IF RdsNo = '' THEN RETURN
|
||||||
IF CassNo = '' THEN RETURN
|
IF CassNo = '' THEN RETURN
|
||||||
|
|
||||||
WOReactKey = WONo:'*':StepNo:'*':ReactNo
|
WOReactKey = WONo:'*':StepNo:'*':ReactNo
|
||||||
|
|
||||||
otParms = 'WO_REACT':@RM:WOReactKey
|
|
||||||
|
|
||||||
WOReactRec = obj_Tables('ReadOnlyRec',otParms)
|
|
||||||
RDSNos = WOReactRec<WO_REACT_RDS_NO$>
|
|
||||||
CassNos = WOReactRec<WO_REACT_CASS_NO$>
|
|
||||||
|
|
||||||
PSNos = XLATE('WO_LOG',WoNo,'PROD_VER_STEP_PSN','X')
|
|
||||||
PSNo = PSNos<1,StepNo>
|
|
||||||
|
|
||||||
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:@RM:1) ;* * * Get Reactor Scheduled QA Metrology * * *
|
|
||||||
|
|
||||||
IF QAMetData = '' THEN RETURN ;* No reactor scheduled QA_MET specified
|
|
||||||
|
|
||||||
Start = QAMetData<COL$QA_MET_START>
|
|
||||||
Interval = QAMetData<COL$QA_MET_INTERVAL>
|
|
||||||
Stage = QAMetData<COL$QA_MET_STAGE>
|
|
||||||
MetPropCd = QAMetData<COL$QA_MET_PROP>
|
|
||||||
GOSUB BuildAllTestPos ;* Set RDSNos, Start and Interval -> returns AllTestPos
|
|
||||||
|
|
||||||
* * * Find where the the RDS being added will be in the list. * * *
|
|
||||||
|
|
||||||
LOCATE RDSNo IN WOReactRec<WO_REACT_RDS_NO$> USING @VM SETTING InsPos THEN
|
|
||||||
|
|
||||||
otParms = 'WO_REACT':@RM:WOReactKey
|
otParms = 'WO_REACT':@RM:WOReactKey
|
||||||
WOReactRec = obj_Tables('UnlockRec',otParms)
|
|
||||||
|
|
||||||
RETURN ;* RDSNo already in this list -> nothing to do.
|
WOReactRec = obj_Tables('ReadOnlyRec',otParms)
|
||||||
|
RDSNos = WOReactRec<WO_REACT_RDS_NO$>
|
||||||
|
CassNos = WOReactRec<WO_REACT_CASS_NO$>
|
||||||
|
|
||||||
END ELSE
|
PSNos = XLATE('WO_LOG',WoNo,'PROD_VER_STEP_PSN','X')
|
||||||
|
PSNo = PSNos<1,StepNo>
|
||||||
|
|
||||||
LOCATE InsPos IN AllTestPos USING @VM SETTING TrimPos ELSE Null
|
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:@RM:1) ;* * * Get Reactor Scheduled QA Metrology * * *
|
||||||
|
|
||||||
|
IF QAMetData = '' THEN RETURN ;* No reactor scheduled QA_MET specified
|
||||||
|
|
||||||
|
Start = QAMetData<COL$QA_MET_START>
|
||||||
|
Interval = QAMetData<COL$QA_MET_INTERVAL>
|
||||||
|
Stage = QAMetData<COL$QA_MET_STAGE>
|
||||||
|
MetPropCd = QAMetData<COL$QA_MET_PROP>
|
||||||
|
GOSUB BuildAllTestPos ;* Set RDSNos, Start and Interval -> returns AllTestPos
|
||||||
|
|
||||||
|
* * * Find where the the RDS being added will be in the list. * * *
|
||||||
|
|
||||||
|
LOCATE RDSNo IN WOReactRec<WO_REACT_RDS_NO$> USING @VM SETTING InsPos THEN
|
||||||
|
|
||||||
|
otParms = 'WO_REACT':@RM:WOReactKey
|
||||||
|
WOReactRec = obj_Tables('UnlockRec',otParms)
|
||||||
|
|
||||||
|
RETURN ;* RDSNo already in this list -> nothing to do.
|
||||||
|
|
||||||
|
END ELSE
|
||||||
|
|
||||||
|
LOCATE InsPos IN AllTestPos USING @VM SETTING TrimPos ELSE Null
|
||||||
|
|
||||||
|
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
||||||
|
GOSUB RemSchedQA ;* Removes unsigned QAMet from cassettes scheduled past the box being removed
|
||||||
|
|
||||||
|
END
|
||||||
|
|
||||||
|
WOReactRec = INSERT(WOReactRec,WO_REACT_RDS_NO$,InsPos,0,RDSNo)
|
||||||
|
WOReactRec = INSERT(WOReactRec,WO_REACT_CASS_NO$,InsPos,0,CassNo) ;* Inserts the passed in RDSNo & associated cassette number from the data fields
|
||||||
|
|
||||||
|
RDSNos = WOReactRec<WO_REACT_RDS_NO$> ;* List after insert
|
||||||
|
CassNos = WOReactRec<WO_REACT_CASS_NO$> ;* List after insert
|
||||||
|
|
||||||
|
* * * Now build list for cassette
|
||||||
|
|
||||||
|
GOSUB BuildAllTestPos
|
||||||
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
||||||
GOSUB RemSchedQA ;* Removes unsigned QAMet from cassettes scheduled past the box being removed
|
// Add QAMet spec data to cassettes now associated with the test
|
||||||
|
// positions after removing the RDS & Cassno from the lists
|
||||||
END
|
GOSUB AddSchedQA
|
||||||
|
|
||||||
WOReactRec = INSERT(WOReactRec,WO_REACT_RDS_NO$,InsPos,0,RDSNo)
|
otParms = FIELDSTORE(otParms,@RM,4,0,WOReactRec)
|
||||||
WOReactRec = INSERT(WOReactRec,WO_REACT_CASS_NO$,InsPos,0,CassNo) ;* Inserts the passed in RDSNo & associated cassette number from the data fields
|
// Done with updates to the WO_REACT record
|
||||||
|
obj_Tables('WriteOnlyRec',otParms)
|
||||||
|
|
||||||
RDSNos = WOReactRec<WO_REACT_RDS_NO$> ;* List after insert
|
Result = Log
|
||||||
CassNos = WOReactRec<WO_REACT_CASS_NO$> ;* List after insert
|
|
||||||
|
|
||||||
* * * Now build list for cassette
|
EndTick = GetTickCount()
|
||||||
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
||||||
GOSUB BuildAllTestPos
|
|
||||||
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
|
||||||
|
|
||||||
GOSUB AddSchedQA ;* Add QAMet spec data to cassettes now associated with the test positions after removing the RDS & Cassno from the lists
|
|
||||||
|
|
||||||
otParms = FIELDSTORE(otParms,@RM,4,0,WOReactRec)
|
|
||||||
obj_Tables('WriteOnlyRec',otParms) ;* Done with updates to the WO_REACT record
|
|
||||||
|
|
||||||
Result = Log
|
|
||||||
|
|
||||||
EndTick = GetTickCount()
|
|
||||||
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
RemRDSNo:
|
RemRDSNo:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
StartTick = GetTickCount()
|
StartTick = GetTickCount()
|
||||||
MetricName = 'RemRDSNo'
|
MetricName = 'RemRDSNo'
|
||||||
|
|
||||||
WONo = Parms[1,@RM]
|
WONo = Parms[1,@RM]
|
||||||
StepNo = Parms[COL2()+1,@RM]
|
StepNo = Parms[COL2()+1,@RM]
|
||||||
ReactNo = Parms[COL2()+1,@RM]
|
ReactNo = Parms[COL2()+1,@RM]
|
||||||
RdsNo = Parms[COL2()+1,@RM]
|
RdsNo = Parms[COL2()+1,@RM]
|
||||||
CassNo = Parms[COL2()+1,@RM]
|
CassNo = Parms[COL2()+1,@RM]
|
||||||
|
|
||||||
IF WONo = '' THEN RETURN
|
IF WONo = '' THEN RETURN
|
||||||
IF StepNo = '' THEN RETURN
|
IF StepNo = '' THEN RETURN
|
||||||
IF ReactNo = '' THEN RETURN
|
IF ReactNo = '' THEN RETURN
|
||||||
IF RdsNo = '' THEN RETURN
|
IF RdsNo = '' THEN RETURN
|
||||||
IF CassNo = '' THEN RETURN
|
IF CassNo = '' THEN RETURN
|
||||||
|
|
||||||
WOReactKey = WONo:'*':StepNo:'*':ReactNo
|
WOReactKey = WONo:'*':StepNo:'*':ReactNo
|
||||||
|
|
||||||
otParms = 'WO_REACT':@RM:WOReactKey
|
otParms = 'WO_REACT':@RM:WOReactKey
|
||||||
// 10/12/18 Changed to ReadOnlyRec as per Francois' instructions. - djs
|
|
||||||
WOReactRec = obj_Tables('ReadOnlyRec',otParms)
|
WOReactRec = obj_Tables('ReadOnlyRec',otParms)
|
||||||
|
|
||||||
RDSNos = WOReactRec<WO_REACT_RDS_NO$>
|
RDSNos = WOReactRec<WO_REACT_RDS_NO$>
|
||||||
CassNos = WOReactRec<WO_REACT_CASS_NO$>
|
CassNos = WOReactRec<WO_REACT_CASS_NO$>
|
||||||
|
|
||||||
PSNos = XLATE('WO_LOG',WoNo,'PROD_VER_STEP_PSN','X')
|
PSNos = XLATE('WO_LOG',WoNo,'PROD_VER_STEP_PSN','X')
|
||||||
PSNo = PSNos<1,StepNo>
|
PSNo = PSNos<1,StepNo>
|
||||||
|
|
||||||
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:@RM:1) ;* * * Get Reactor Scheduled QA Metrology * * *
|
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:@RM:1) ;* * * Get Reactor Scheduled QA Metrology * * *
|
||||||
|
|
||||||
Start = QAMetData<COL$QA_MET_START>
|
Start = QAMetData<COL$QA_MET_START>
|
||||||
Interval = QAMetData<COL$QA_MET_INTERVAL>
|
Interval = QAMetData<COL$QA_MET_INTERVAL>
|
||||||
Stage = QAMetData<COL$QA_MET_STAGE>
|
Stage = QAMetData<COL$QA_MET_STAGE>
|
||||||
MetPropCd = QAMetData<COL$QA_MET_PROP>
|
MetPropCd = QAMetData<COL$QA_MET_PROP>
|
||||||
|
|
||||||
GOSUB BuildAllTestPos ;* Set RDSNos, Start and Interval -> returns AllTestPos
|
GOSUB BuildAllTestPos ;* Set RDSNos, Start and Interval -> returns AllTestPos
|
||||||
|
|
||||||
IF AllTestPos NE '' THEN
|
IF AllTestPos NE '' THEN
|
||||||
|
|
||||||
* * * Find where the the RDS being removed is in the list. * * *
|
* * * Find where the the RDS being removed is in the list. * * *
|
||||||
|
|
||||||
LOCATE RDSNo IN WOReactRec<WO_REACT_RDS_NO$> USING @VM SETTING RemPos THEN
|
LOCATE RDSNo IN WOReactRec<WO_REACT_RDS_NO$> USING @VM SETTING RemPos THEN
|
||||||
|
|
||||||
LOCATE RemPos IN AllTestPos USING @VM SETTING TrimPos ELSE Null
|
LOCATE RemPos IN AllTestPos USING @VM SETTING TrimPos ELSE Null
|
||||||
|
|
||||||
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
||||||
|
|
||||||
GOSUB RemSchedQA ;* Removes unsigned QAMet from cassettes scheduled past the box being removed
|
GOSUB RemSchedQA ;* Removes unsigned QAMet from cassettes scheduled past the box being removed
|
||||||
END ELSE
|
END ELSE
|
||||||
|
|
||||||
otParms = 'WO_REACT':@RM:WOReactKey
|
otParms = 'WO_REACT':@RM:WOReactKey
|
||||||
WOReactRec = obj_Tables('UnlockRec',otParms)
|
WOReactRec = obj_Tables('UnlockRec',otParms)
|
||||||
|
|
||||||
RETURN ;* RDSNo is not in this list -> nothing to do.
|
RETURN ;* RDSNo is not in this list -> nothing to do.
|
||||||
END
|
END
|
||||||
END ;* End of check for AllTestPos null
|
END ;* End of check for AllTestPos null
|
||||||
|
|
||||||
WOReactRec = DELETE(WOReactRec,WO_REACT_RDS_NO$,RemPos,0)
|
WOReactRec = DELETE(WOReactRec,WO_REACT_RDS_NO$,RemPos,0)
|
||||||
WOReactRec = DELETE(WOReactRec,WO_REACT_CASS_NO$,RemPos,0) ;* Removes the passed in RDSNo & associated cassette number from the data fields
|
WOReactRec = DELETE(WOReactRec,WO_REACT_CASS_NO$,RemPos,0) ;* Removes the passed in RDSNo & associated cassette number from the data fields
|
||||||
|
|
||||||
RDSNos = WOReactRec<WO_REACT_RDS_NO$> ;* List after removal
|
RDSNos = WOReactRec<WO_REACT_RDS_NO$> ;* List after removal
|
||||||
CassNos = WOReactRec<WO_REACT_CASS_NO$> ;* List after removal
|
CassNos = WOReactRec<WO_REACT_CASS_NO$> ;* List after removal
|
||||||
|
|
||||||
* * * Now build list for cassette
|
* * * Now build list for cassette
|
||||||
|
|
||||||
GOSUB BuildAllTestPos
|
GOSUB BuildAllTestPos
|
||||||
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
ChangePosList = FIELD(AllTestPos,@VM,TrimPos,SeqCnt)
|
||||||
|
|
||||||
GOSUB AddSchedQA ;* Add QAMet spec data to cassettes now associated with the test positions after removing the RDS & Cassno from the lists
|
GOSUB AddSchedQA ;* Add QAMet spec data to cassettes now associated with the test positions after removing the RDS & Cassno from the lists
|
||||||
otParms = FIELDSTORE(otParms,@RM,4,0,WOReactRec)
|
otParms = FIELDSTORE(otParms,@RM,4,0,WOReactRec)
|
||||||
// 10/12/18 Changed to WriteOnlyRec as per Francois' instructions. - djs
|
|
||||||
obj_Tables('WriteOnlyRec',otParms) ;* Done with updates to the WO_REACT record
|
|
||||||
|
|
||||||
Result = Log
|
obj_Tables('WriteOnlyRec',otParms) ;* Done with updates to the WO_REACT record
|
||||||
|
|
||||||
EndTick = GetTickCount()
|
Result = Log
|
||||||
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
||||||
|
EndTick = GetTickCount()
|
||||||
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
************** Internal Methods *************
|
************** Internal Methods *************
|
||||||
|
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
BuildAllTestPos:
|
BuildAllTestPos:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
AllTestPos = ''
|
AllTestPos = ''
|
||||||
|
|
||||||
RDSCnt = COUNT(RDSNos,@VM) + (RDSNos NE '')
|
RDSCnt = COUNT(RDSNos,@VM) + (RDSNos NE '')
|
||||||
SeqCnt = 0
|
SeqCnt = 0
|
||||||
|
|
||||||
|
|
||||||
FOR TestSeq = 1 TO RDSCnt
|
FOR TestSeq = 1 TO RDSCnt
|
||||||
IF REM((TestSeq - Start),Interval) = 0 THEN
|
IF REM((TestSeq - Start),Interval) = 0 THEN
|
||||||
AllTestPos<1,-1> = TestSeq ;* Build list of list positions to have QAMet scheduled
|
AllTestPos<1,-1> = TestSeq ;* Build list of list positions to have QAMet scheduled
|
||||||
SeqCnt += 1
|
SeqCnt += 1
|
||||||
END
|
END
|
||||||
NEXT TestSeq
|
NEXT TestSeq
|
||||||
|
|
||||||
Log := 'AllTestPos: ':AllTestPos:@FM
|
Log := 'AllTestPos: ':AllTestPos:@FM
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
RemSchedQA:
|
RemSchedQA:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
chgCnt = COUNT(ChangePosList,@VM) + (ChangePosList NE '')
|
chgCnt = COUNT(ChangePosList,@VM) + (ChangePosList NE '')
|
||||||
|
|
||||||
FOR I = 1 TO chgCnt
|
FOR I = 1 TO chgCnt
|
||||||
RemCassNo = CassNos<1,ChangePoslist<1,I>>
|
RemCassNo = CassNos<1,ChangePoslist<1,I>>
|
||||||
Log:= 'RemSched on CassNo: ':RemCassNo:@FM
|
Log:= 'RemSched on CassNo: ':RemCassNo:@FM
|
||||||
|
|
||||||
owmParms = WONo:@RM:StepNo:@RM:RemCassNo:@RM:Stage:@RM:MetPropCd
|
owmParms = WONo:@RM:StepNo:@RM:RemCassNo:@RM:Stage:@RM:MetPropCd
|
||||||
|
|
||||||
obj_WO_Mat_QA('RemQAMet',owmParms) ;* Unschedule test boxes before list change
|
obj_WO_Mat_QA('RemQAMet',owmParms) ;* Unschedule test boxes before list change
|
||||||
|
|
||||||
IF Get_Status(errCode) THEN
|
IF Get_Status(errCode) THEN
|
||||||
ErrMsg(errCode)
|
ErrMsg(errCode)
|
||||||
END
|
END
|
||||||
|
|
||||||
|
NEXT I
|
||||||
*obj_WO_Mat('RemQAMet',owmParms) ;* Dead 6/5/2015 JCH - Remove after a few days
|
|
||||||
|
|
||||||
*IF Get_Status(errCode) THEN
|
|
||||||
* ErrMsg(errCode)
|
|
||||||
*END
|
|
||||||
NEXT I
|
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
@ -294,47 +284,39 @@ RETURN
|
|||||||
AddSchedQA:
|
AddSchedQA:
|
||||||
* * * * * * *
|
* * * * * * *
|
||||||
|
|
||||||
chgCnt = COUNT(ChangePosList,@VM) + (ChangePosList NE '')
|
chgCnt = COUNT(ChangePosList,@VM) + (ChangePosList NE '')
|
||||||
|
|
||||||
FOR I = 1 TO chgCnt
|
FOR I = 1 TO chgCnt
|
||||||
AddCassNo = CassNos<1,ChangePoslist<1,I>>
|
AddCassNo = CassNos<1,ChangePoslist<1,I>>
|
||||||
|
|
||||||
Log:= 'AddSched on CassNo: ':AddCassNo:@FM
|
Log:= 'AddSched on CassNo: ':AddCassNo:@FM
|
||||||
|
|
||||||
owmParms = WONo:@RM
|
owmParms = WONo:@RM
|
||||||
owmParms := StepNo:@RM
|
owmParms := StepNo:@RM
|
||||||
owmParms := AddCassNo:@RM
|
owmParms := AddCassNo:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_STAGE>:@RM
|
owmParms := QAMetData<COL$QA_MET_STAGE>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_TEST>:@RM
|
owmParms := QAMetData<COL$QA_MET_TEST>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_PROP>:@RM
|
owmParms := QAMetData<COL$QA_MET_PROP>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_TOOL_CLASS>:@RM
|
owmParms := QAMetData<COL$QA_MET_TOOL_CLASS>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_MIN>:@RM
|
owmParms := QAMetData<COL$QA_MET_MIN>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_MAX>:@RM
|
owmParms := QAMetData<COL$QA_MET_MAX>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_SLOT>:@RM
|
owmParms := QAMetData<COL$QA_MET_SLOT>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_RECIPE>:@RM
|
owmParms := QAMetData<COL$QA_MET_RECIPE>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_RECIPE_PATTERN>:@RM
|
owmParms := QAMetData<COL$QA_MET_RECIPE_PATTERN>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_WFR_QTY>:@RM
|
owmParms := QAMetData<COL$QA_MET_WFR_QTY>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_WFR_TYPE>:@RM
|
owmParms := QAMetData<COL$QA_MET_WFR_TYPE>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_REACT_SCHED>:@RM
|
owmParms := QAMetData<COL$QA_MET_REACT_SCHED>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_SHIP_DOC>:@RM
|
owmParms := QAMetData<COL$QA_MET_SHIP_DOC>:@RM
|
||||||
owmParms := QAMetData<COL$QA_MET_PHASE_MIN> ; // 10/15/18 - djs - Added Phase Min Spec for HgCV
|
owmParms := QAMetData<COL$QA_MET_PHASE_MIN> ; // 10/15/18 - djs - Added Phase Min Spec for HgCV
|
||||||
|
|
||||||
|
|
||||||
obj_WO_Mat_QA('AddQAMet', owmParms) ;* Schedule test boxes after list change
|
obj_WO_Mat_QA('AddQAMet', owmParms) ;* Schedule test boxes after list change
|
||||||
|
|
||||||
IF Get_Status(errCode) THEN
|
IF Get_Status(errCode) THEN
|
||||||
ErrMsg(errCode)
|
ErrMsg(errCode)
|
||||||
END
|
END
|
||||||
|
|
||||||
*obj_WO_Mat('AddQAMet',owmParms) ;* Dead 6/5/2015 JCH - remove after a few days
|
NEXT I
|
||||||
|
|
||||||
*IF Get_Status(errCode) THEN
|
|
||||||
* ErrMsg(errCode)
|
|
||||||
*END
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NEXT I
|
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@ $Insert PRS_LAYER_EQUATES
|
|||||||
$Insert PRS_STAGE_EQUATES
|
$Insert PRS_STAGE_EQUATES
|
||||||
$Insert PROD_VER_EQUATES
|
$Insert PROD_VER_EQUATES
|
||||||
$Insert QA_MET_EQUATES ;* Used in GetQAMet data structure return variable
|
$Insert QA_MET_EQUATES ;* Used in GetQAMet data structure return variable
|
||||||
|
$Insert RDS_EQUATES
|
||||||
|
$Insert WO_REACT_EQUATES
|
||||||
|
|
||||||
Declare function Database_Services, SRP_JSON, Error_Services, obj_Prod_Spec, Wo_Mat_Qa_Services
|
Declare function Database_Services, SRP_JSON, Error_Services, obj_Prod_Spec, Wo_Mat_Qa_Services
|
||||||
Declare subroutine Database_Services, SRP_JSON, Error_Services
|
Declare subroutine Database_Services, SRP_JSON, Error_Services
|
||||||
@ -192,130 +194,168 @@ End Service
|
|||||||
|
|
||||||
|
|
||||||
Service UpdateQAMet(WOMatKey)
|
Service UpdateQAMet(WOMatKey)
|
||||||
|
|
||||||
WOMatQARec = ''
|
WOMatQARec = ''
|
||||||
ErrorMsg = ''
|
ErrorMsg = ''
|
||||||
If (WOMatKey NE '') then
|
If (WOMatKey NE '') then
|
||||||
|
WONo = Field(WOMatKey, '*', 1)
|
||||||
WONo = Field(WOMatKey, '*', 1)
|
CassNo = Field(WOMatKey, '*', 2)
|
||||||
CassNo = Field(WOMatKey, '*', 2)
|
RDSNo = Database_Services('ReadDataColumn', 'WO_MAT', WOMatKey, WO_MAT_RDS_NO$)
|
||||||
|
If Error_Services('NoError') then
|
||||||
* * * * * * * * Build QA_MET profile - Work Order scheduled only * * * * * * * *
|
If (RDSNo NE '') then
|
||||||
WOStepKeys = XLATE('WO_LOG', WONo, WO_LOG_WO_STEP_KEY$, 'X')
|
// Check if it has been assigned to a reactor
|
||||||
|
ReactNo = Database_Services('ReadDataColumn', 'RDS', RDSNo, RDS_REACTOR$)
|
||||||
StepCnt = DCount(WOStepKeys,@VM)
|
If Error_Services('HasError') then
|
||||||
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
EpiProPSNo = ''
|
end
|
||||||
EpiProPSRec = ''
|
end else
|
||||||
|
// Either not signed into a reactor yet or this WO_MAT is EpiPro and therefore there is no
|
||||||
MetLine = 1
|
// 1-to-1 RDS record. Because of this, reactor scheduled QA met is not possible with EpiPro.
|
||||||
|
ReactNo = ''
|
||||||
// Get original WO_MAT_QA record to copy any test results
|
end
|
||||||
OrigWOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
|
If (ErrorMsg EQ '') then
|
||||||
OrigQAStages = OrigWOMatQARec<WO_MAT_QA_STAGE$>
|
WOStepKeys = Database_Services('ReadDataColumn', 'WO_LOG', WONo, WO_LOG_WO_STEP_KEY$)
|
||||||
OrigQAProfiles = OrigWOMatQARec<WO_MAT_QA_PROFILE$>
|
If Error_Services('NoError') then
|
||||||
OrigQASlots = OrigWOMatQARec<WO_MAT_QA_SLOT$>
|
StepCnt = DCount(WOStepKeys,@VM)
|
||||||
OrigQASlotTests = OrigWOMatQARec<WO_MAT_QA_SLOT_TEST$>
|
MetLine = 1
|
||||||
OrigQAResults = OrigWOMatQARec<WO_MAT_QA_RESULT$>
|
// Get original WO_MAT_QA record to copy any test results
|
||||||
OrigQASigs = OrigWOMatQARec<WO_MAT_QA_SIG$>
|
OrigWOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
|
||||||
OrigQASigDtms = OrigWOMatQARec<WO_MAT_QA_SIG_DTM$>
|
OrigQAStages = OrigWOMatQARec<WO_MAT_QA_STAGE$>
|
||||||
OrigQAStdResults = OrigWOMatQARec<WO_MAT_QA_STD_RESULT$>
|
OrigQAProfiles = OrigWOMatQARec<WO_MAT_QA_PROFILE$>
|
||||||
OrigQADataPoints = OrigWOMatQARec<WO_MAT_QA_DATA_POINTS$>
|
OrigQASlots = OrigWOMatQARec<WO_MAT_QA_SLOT$>
|
||||||
OrigQAMinResults = OrigWOMatQARec<WO_MAT_QA_MIN_RESULT$>
|
OrigQASlotTests = OrigWOMatQARec<WO_MAT_QA_SLOT_TEST$>
|
||||||
OrigQAMaxResults = OrigWOMatQARec<WO_MAT_QA_MAX_RESULT$>
|
OrigQAResults = OrigWOMatQARec<WO_MAT_QA_RESULT$>
|
||||||
OrigQARangeResults = OrigWOMatQARec<WO_MAT_QA_RANGE_PCT_RESULT$>
|
OrigQASigs = OrigWOMatQARec<WO_MAT_QA_SIG$>
|
||||||
OrigQAEdgeResults = OrigWOMatQARec<WO_MAT_QA_EDGE_MEAN_RESULT$>
|
OrigQASigDtms = OrigWOMatQARec<WO_MAT_QA_SIG_DTM$>
|
||||||
OrigQA5mmResults = OrigWOMatQARec<WO_MAT_QA_5MM_PCT_RESULT$>
|
OrigQAStdResults = OrigWOMatQARec<WO_MAT_QA_STD_RESULT$>
|
||||||
OrigQAOutOfSpecs = OrigWOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
|
OrigQADataPoints = OrigWOMatQARec<WO_MAT_QA_DATA_POINTS$>
|
||||||
OrigQAFailReasons = OrigWOMatQARec<WO_MAT_QA_FAIL_REASON$>
|
OrigQAMinResults = OrigWOMatQARec<WO_MAT_QA_MIN_RESULT$>
|
||||||
|
OrigQAMaxResults = OrigWOMatQARec<WO_MAT_QA_MAX_RESULT$>
|
||||||
* WO_MAT record is used to check for pre-existing signatures jch 6/7/2015
|
OrigQARangeResults = OrigWOMatQARec<WO_MAT_QA_RANGE_PCT_RESULT$>
|
||||||
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
|
OrigQAEdgeResults = OrigWOMatQARec<WO_MAT_QA_EDGE_MEAN_RESULT$>
|
||||||
|
OrigQA5mmResults = OrigWOMatQARec<WO_MAT_QA_5MM_PCT_RESULT$>
|
||||||
FOR WOStepNo = 1 TO StepCnt
|
OrigQAOutOfSpecs = OrigWOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
|
||||||
PSNo = XLATE('WO_STEP', WOStepKeys<1,WOStepNo>, WO_STEP_PROD_SPEC_ID$, 'X')
|
OrigQAFailReasons = OrigWOMatQARec<WO_MAT_QA_FAIL_REASON$>
|
||||||
PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
|
|
||||||
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:PSRec)
|
FOR WOStepNo = 1 TO StepCnt
|
||||||
QAStages = QAMetData<COL$QA_MET_STAGE>
|
PSNo = Database_Services('ReadDataColumn', 'WO_STEP', WOStepKeys<1,WOStepNo>, WO_STEP_PROD_SPEC_ID$)
|
||||||
StageCnt = COUNT(QAStages,@VM) + (QAStages NE '')
|
If Error_Services('NoError') then
|
||||||
|
PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
|
||||||
FOR StageNo = 1 TO StageCnt
|
If Error_Services('NoError') then
|
||||||
Stage = QAMetData<COL$QA_MET_STAGE,StageNo>
|
QAMetData = obj_Prod_Spec('GetQAMet',PSNo:@RM:PSRec:@RM:@RM:True$)
|
||||||
|
QAStages = QAMetData<COL$QA_MET_STAGE>
|
||||||
MetTest = QAMetData<COL$QA_MET_TEST,StageNo> ;* StageRec<PRS_STAGE_MET_TEST$>
|
StageCnt = DCount(QAStages,@VM)
|
||||||
|
|
||||||
Interval = QAMetData<COL$QA_MET_INTERVAL,StageNo> ;* StageRec<PRS_STAGE_MET_INTERVAL$,StageNo>
|
If (ReactNo NE '') then
|
||||||
Start = QAMetData<COL$QA_MET_START,StageNo> ;* StageRec<PRS_STAGE_MET_START$,StageNo>
|
WOReactKey = WONo:'*':WOStepNo:'*':ReactNo
|
||||||
ReactSched = QAMetData<COL$QA_MET_REACT_SCHED,StageNo> ;* StageRec<PRS_STAGE_MET_REACT_SCHED$,StageNo>
|
end else
|
||||||
TestFlag = 0
|
WOReactKey = ''
|
||||||
|
end
|
||||||
IF Interval NE '' AND Start NE '' THEN
|
|
||||||
IF Interval = Start THEN
|
If (WOReactKey NE '') then
|
||||||
IF REM(CassNo,Interval) = 0 THEN TestFlag = 1
|
WOReactRDSNos = Database_Services('ReadDataColumn', 'WO_REACT', WOReactKey, WO_REACT_RDS_NO$)
|
||||||
END ELSE
|
If Error_Services('HasError') then
|
||||||
IF ABS((Start + INT(CassNo/Interval)*Interval) - CassNo) = 0 THEN TestFlag = 1
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
END
|
end
|
||||||
IF TestFlag AND NOT(ReactSched) THEN
|
end
|
||||||
WOMatQARec<WO_MAT_QA_PROFILE$,MetLine> = WOStepNo:QAMetData<COL$QA_MET_TEST,StageNo> ;* StageRec<PRS_STAGE_MET_TEST$,N>
|
|
||||||
WOMatQARec<WO_MAT_QA_PROP$,MetLine> = QAMetData<COL$QA_MET_PROP,StageNo> ;* StageRec<PRS_STAGE_MET_PROP$,N>
|
If (ErrorMsg EQ '') then
|
||||||
WOMatQARec<WO_MAT_QA_TOOL_CLASS$,MetLine> = QAMetData<COL$QA_MET_TOOL_CLASS,StageNo> ;* StageRec<PRS_STAGE_MET_TOOL_CLASS$,N>
|
For StageNo = 1 to StageCnt
|
||||||
WOMatQARec<WO_MAT_QA_STAGE$,MetLine> = QAMetData<COL$QA_MET_STAGE,StageNo>
|
Stage = QAMetData<COL$QA_MET_STAGE,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_MIN$,MetLine> = QAMetData<COL$QA_MET_MIN,StageNo> ;* StageRec<PRS_STAGE_MET_MIN$,N>
|
MetTest = QAMetData<COL$QA_MET_TEST,StageNo> ;* StageRec<PRS_STAGE_MET_TEST$>
|
||||||
WOMatQARec<WO_MAT_QA_MAX$,MetLine> = QAMetData<COL$QA_MET_MAX,StageNo> ;* StageRec<PRS_STAGE_MET_MAX$,N>
|
Interval = QAMetData<COL$QA_MET_INTERVAL,StageNo> ;* StageRec<PRS_STAGE_MET_INTERVAL$,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_SLOT$,MetLine> = QAMetData<COL$QA_MET_SLOT,StageNo> ;* StageRec<PRS_STAGE_MET_SLOT$,N>
|
Start = QAMetData<COL$QA_MET_START,StageNo> ;* StageRec<PRS_STAGE_MET_START$,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_RECIPE$,MetLine> = QAMetData<COL$QA_MET_RECIPE,StageNo> ;* StageRec<PRS_STAGE_MET_RECIPE$,N>
|
ReactSched = QAMetData<COL$QA_MET_REACT_SCHED,StageNo> ;* StageRec<PRS_STAGE_MET_REACT_SCHED$,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_RECIPE_PATTERN$,MetLine> = QAMetData<COL$QA_MET_RECIPE_PATTERN,StageNo> ;* StageRec<PRS_STAGE_MET_RECIPE_PATTERN$,StageNo>
|
TestFlag = False$
|
||||||
WOMatQARec<WO_MAT_QA_WFR_QTY$,MetLine> = QAMetData<COL$QA_MET_WFR_QTY,StageNo> ;* StageRec<PRS_STAGE_MET_WFR_QTY$,StageNo>
|
|
||||||
WOMatQARec<WO_MAT_QA_WFR_TYPE$,MetLine> = QAMetData<COL$QA_MET_WFR_TYPE,StageNo> ;* StageRec<PRS_STAGE_MET_WFR_TYPE$,StageNo>
|
If ( (Interval NE '') and (Start NE '') ) then
|
||||||
WOMatQARec<WO_MAT_QA_REACT_SCHED$,MetLine> = ReactSched ;* StageRec<PRS_STAGE_MET_REACT_SCHED$,StageNo>
|
// Add Work Order scheduled tests (i.e., not reactor scheduled tests)
|
||||||
WOMatQARec<WO_MAT_QA_SHIP_DOC$,MetLine> = QAMetData<COL$QA_MET_SHIP_DOC,StageNo> ;* StageRec<PRS_STAGE_MET_SHIP_DOC$,StageNo>
|
If Not(ReactSched) then
|
||||||
WOMatQARec<WO_MAT_QA_PHASE_MIN$,MetLine> = QAMetData<COL$QA_MET_PHASE_MIN,StageNo>
|
If Interval = Start then
|
||||||
|
If ( Rem(CassNo, Interval) EQ 0 ) then TestFlag = True$
|
||||||
If OrigWOMatQARec NE '' then
|
end else
|
||||||
CurrStage = QAMetData<COL$QA_MET_STAGE,StageNo>
|
If ( Abs( (Start + Int(CassNo / Interval)*Interval) - CassNo ) EQ 0) then TestFlag = True$
|
||||||
CurrProfile = WOStepNo:QAMetData<COL$QA_MET_TEST,StageNo>
|
end
|
||||||
CurrSlot = QAMetData<COL$QA_MET_SLOT,StageNo>
|
end else
|
||||||
// Copy any existing results from the original WO_MAT_QA record.
|
Locate RDSNo in WOReactRDSNos using @VM setting TestSeq then
|
||||||
If OrigQAStages NE '' then
|
If ( Rem( (TestSeq - Start), Interval) EQ 0 ) then TestFlag = True$
|
||||||
Found = False$
|
end
|
||||||
For each OrigQAStage in OrigQAStages using @VM setting sPos
|
end
|
||||||
OrigQAProfile = OrigQAProfiles<0, sPos>
|
If TestFlag then
|
||||||
OrigQASlot = OrigQASlots<0, sPos>
|
WOMatQARec<WO_MAT_QA_PROFILE$,MetLine> = WOStepNo:MetTest
|
||||||
If ( (CurrStage EQ OrigQAStage) and (CurrProfile EQ OrigQAProfile) and (CurrSlot EQ OrigQASlot) ) then
|
WOMatQARec<WO_MAT_QA_PROP$,MetLine> = QAMetData<COL$QA_MET_PROP,StageNo>
|
||||||
Found = True$
|
WOMatQARec<WO_MAT_QA_TOOL_CLASS$,MetLine> = QAMetData<COL$QA_MET_TOOL_CLASS,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_SLOT_TEST$,MetLine> = OrigQASlotTests<0, sPos>
|
WOMatQARec<WO_MAT_QA_STAGE$,MetLine> = Stage
|
||||||
WOMatQARec<WO_MAT_QA_RESULT$,MetLine> = OrigQAResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_MIN$,MetLine> = QAMetData<COL$QA_MET_MIN,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_SIG$,MetLine> = OrigQASigs<0, sPos>
|
WOMatQARec<WO_MAT_QA_MAX$,MetLine> = QAMetData<COL$QA_MET_MAX,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_SIG_DTM$,MetLine> = OrigQASigDtms<0, sPos>
|
WOMatQARec<WO_MAT_QA_SLOT$,MetLine> = QAMetData<COL$QA_MET_SLOT,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_STD_RESULT$,MetLine> = OrigQAStdResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_RECIPE$,MetLine> = QAMetData<COL$QA_MET_RECIPE,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_DATA_POINTS$,MetLine> = OrigQADataPoints<0, sPos>
|
WOMatQARec<WO_MAT_QA_RECIPE_PATTERN$,MetLine> = QAMetData<COL$QA_MET_RECIPE_PATTERN,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_MIN_RESULT$,MetLine> = OrigQAMinResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_WFR_QTY$,MetLine> = QAMetData<COL$QA_MET_WFR_QTY,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_MAX_RESULT$,MetLine> = OrigQAMaxResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_WFR_TYPE$,MetLine> = QAMetData<COL$QA_MET_WFR_TYPE,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_RANGE_PCT_RESULT$,MetLine> = OrigQARangeResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_REACT_SCHED$,MetLine> = ReactSched
|
||||||
WOMatQARec<WO_MAT_QA_EDGE_MEAN_RESULT$,MetLine> = OrigQAEdgeResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_SHIP_DOC$,MetLine> = QAMetData<COL$QA_MET_SHIP_DOC,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_5MM_PCT_RESULT$,MetLine> = OrigQA5mmResults<0, sPos>
|
WOMatQARec<WO_MAT_QA_PHASE_MIN$,MetLine> = QAMetData<COL$QA_MET_PHASE_MIN,StageNo>
|
||||||
WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$,MetLine> = OrigQAOutOfSpecs<0, sPos>
|
|
||||||
WOMatQARec<WO_MAT_QA_FAIL_REASON$,MetLine> = OrigQAFailReasons<0, sPos>
|
If OrigWOMatQARec NE '' then
|
||||||
end
|
CurrStage = QAMetData<COL$QA_MET_STAGE,StageNo>
|
||||||
Until Found
|
CurrProfile = WOStepNo:MetTest
|
||||||
Next OrigQAStage
|
CurrSlot = QAMetData<COL$QA_MET_SLOT,StageNo>
|
||||||
end
|
// Copy any existing results from the original WO_MAT_QA record.
|
||||||
end
|
If OrigQAStages NE '' then
|
||||||
MetLine += 1
|
Found = False$
|
||||||
END
|
For each OrigQAStage in OrigQAStages using @VM setting sPos
|
||||||
END
|
OrigQAProfile = OrigQAProfiles<0, sPos>
|
||||||
|
OrigQASlot = OrigQASlots<0, sPos>
|
||||||
NEXT StageNo
|
If ( (CurrStage EQ OrigQAStage) and (CurrProfile EQ OrigQAProfile) and (CurrSlot EQ OrigQASlot) ) then
|
||||||
|
Found = True$
|
||||||
NEXT WOStepNo
|
WOMatQARec<WO_MAT_QA_SLOT_TEST$,MetLine> = OrigQASlotTests<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_RESULT$,MetLine> = OrigQAResults<0, sPos>
|
||||||
Database_Services('WriteDataRow', 'WO_MAT_QA', WONo:'*':CassNo, WOMatQARec)
|
WOMatQARec<WO_MAT_QA_SIG$,MetLine> = OrigQASigs<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_SIG_DTM$,MetLine> = OrigQASigDtms<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_STD_RESULT$,MetLine> = OrigQAStdResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_DATA_POINTS$,MetLine> = OrigQADataPoints<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_MIN_RESULT$,MetLine> = OrigQAMinResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_MAX_RESULT$,MetLine> = OrigQAMaxResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_RANGE_PCT_RESULT$,MetLine> = OrigQARangeResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_EDGE_MEAN_RESULT$,MetLine> = OrigQAEdgeResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_5MM_PCT_RESULT$,MetLine> = OrigQA5mmResults<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$,MetLine> = OrigQAOutOfSpecs<0, sPos>
|
||||||
|
WOMatQARec<WO_MAT_QA_FAIL_REASON$,MetLine> = OrigQAFailReasons<0, sPos>
|
||||||
|
end
|
||||||
|
Until Found
|
||||||
|
Next OrigQAStage
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MetLine += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Next StageNo
|
||||||
|
end
|
||||||
|
end else
|
||||||
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
|
end
|
||||||
|
end else
|
||||||
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
|
end
|
||||||
|
Until (ErrorMsg NE '')
|
||||||
|
Next WOStepNo
|
||||||
|
If (ErrorMsg EQ '') then
|
||||||
|
Database_Services('WriteDataRow', 'WO_MAT_QA', WONo:'*':CassNo, WOMatQARec)
|
||||||
|
If Error_Services('HasError') then ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
|
end
|
||||||
|
end else
|
||||||
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else
|
||||||
|
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
|
||||||
|
end
|
||||||
end else
|
end else
|
||||||
ErrorMsg = 'Error in ':Service:' service. Null WOMatKey passed in.'
|
ErrorMsg = 'Error in ':Service:' service. Null WOMatKey passed in.'
|
||||||
end
|
end
|
||||||
|
|
||||||
If ErrorMsg NE '' then
|
If (ErrorMsg NE '') then
|
||||||
Error_Services('Add', ErrorMsg)
|
Error_Services('Add', ErrorMsg)
|
||||||
end else
|
end else
|
||||||
Response = WOMatQARec
|
Response = WOMatQARec
|
||||||
@ -469,7 +509,7 @@ end service
|
|||||||
|
|
||||||
|
|
||||||
Service GetMUWaferQAComplete(WOMatKey)
|
Service GetMUWaferQAComplete(WOMatKey)
|
||||||
|
|
||||||
ErrorMsg = ''
|
ErrorMsg = ''
|
||||||
|
|
||||||
If WOMatKey NE '' then
|
If WOMatKey NE '' then
|
||||||
@ -521,4 +561,3 @@ Service GetMUWaferQAComplete(WOMatKey)
|
|||||||
|
|
||||||
end service
|
end service
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user