Initial commit. Create FQASignatureReady service in QA_SERVICES. Create SignFQA service in SIGNATURE_SERVICES. Commit remaining portion of project. Implement changes requested in review meeting. Fix typo. Add new MU logic to final entry point. Restrict logic to only apply to 'THICK' inspections. Bypass new logic if Biorad 4 and 5 are down.
905 lines
40 KiB
Plaintext
905 lines
40 KiB
Plaintext
Function WO_MAT_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
/***********************************************************************************************************************
|
|
|
|
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 : WO_MAT_Actions
|
|
|
|
Description : Handles calculated columns and MFS calls for the current table.
|
|
|
|
Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly.
|
|
If called from outside of a calculated column these will need to be set and restored.
|
|
|
|
Parameters :
|
|
Action [in] -- Name of the action to be taken
|
|
CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be
|
|
populated when the CalcField action is being used.
|
|
FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM
|
|
delimited array, with the current MFS name as the first value in the array, and the BFS
|
|
name as the last value. Normally set by a calling MFS.
|
|
Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the
|
|
entire handle structure that the Basic+ Open statement would provide. Normally set by a
|
|
calling MFS.
|
|
Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS.
|
|
FMC [in] -- Various functions. Normally set by a calling MFS.
|
|
Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for
|
|
"get handle" functions). Normally set by a calling MFS.
|
|
Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but
|
|
for some actions can be set by the action handler to indicate failure.
|
|
OrigRecord [in] -- Original content of the record being processed by the current action. This is
|
|
automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within
|
|
BASE_MFS.
|
|
Param1-10 [in/out] -- Additional request parameter holders
|
|
ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.)
|
|
Can also be used to return a special value, such as the results of the CalcField
|
|
method.
|
|
|
|
History : (Date, Initials, Notes)
|
|
07/28/10 dmb Original programmer.
|
|
10/13/10 dmb Fix logic to extract the file handle if file has an index
|
|
03/26/11 dmb Add logic to save and restore @FILE.ERROR
|
|
|
|
***********************************************************************************************************************/
|
|
|
|
$insert APP_INSERTS
|
|
$insert FILE.SYSTEM.EQUATES
|
|
$insert ACTION_SETUP
|
|
$insert WO_MAT_EQUATES
|
|
$insert WO_LOG_EQUATES
|
|
$insert WO_STEP_EQUATES
|
|
$insert MAKEUP_WAFERS_EQUATES
|
|
$insert RLIST_EQUATES
|
|
|
|
Equ Comma$ to ','
|
|
|
|
Declare function Error_Services, Database_Services, Environment_Services, Logging_Services, obj_WO_Mat, Max
|
|
Declare function GaN_Services, Signature_Services, obj_WO_LOG, SRP_Array, MemberOf, Datetime
|
|
Declare subroutine Error_Services, Database_Services, Environment_Services, Logging_Services, Obj_SAP, obj_Notes
|
|
Declare subroutine SAP_Services, Material_Services, RList, Work_Order_Services, Service_Services, Set_Status
|
|
|
|
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_Mat'
|
|
LogDate = Oconv(Date(), 'D4/')
|
|
LogTime = Oconv(Time(), 'MTS')
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Work Order Log.csv'
|
|
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'WOMatKeyID' : @FM : 'HotLot' : @FM : 'HotLotOrig' : @FM : 'Notes'
|
|
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
|
|
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Work Order Material.csv'
|
|
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'WOMatKeyID' : @FM : 'Notes'
|
|
objLog2 = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Erase Attempt.csv'
|
|
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'RDSNo' : @FM : 'WOMatKeyID' : @FM : 'RDS<WO_MAT_KEY>' : @FM : 'Error'
|
|
objLog3 = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' NCR Slot List.csv'
|
|
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'WOMatKeyID' : @FM : 'NCR by Slot' : @FM : 'Stack'
|
|
objNCRLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Slot List Error.csv'
|
|
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'WOMatKeyID' : @FM : 'Last Slot' : @FM : 'Stack'
|
|
objSlotLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
|
|
If KeyID then GoSub Initialize_System_Variables
|
|
|
|
Begin Case
|
|
|
|
Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn
|
|
Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE
|
|
Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD
|
|
Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE
|
|
Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD
|
|
Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE
|
|
Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD
|
|
Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE
|
|
Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD
|
|
Case Otherwise$ ; Status = 'Invalid Action'
|
|
|
|
End Case
|
|
|
|
If KeyID then GoSub Restore_System_Variables
|
|
|
|
If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$
|
|
|
|
Return ActionFlow
|
|
|
|
|
|
// ----- Calculated Columns --------------------------------------------------------------------------------------------
|
|
//
|
|
// The typical structure of a calculated column will look like this:
|
|
//
|
|
// Declare function TableName_Actions
|
|
//
|
|
// A = {COL1} ; * Reference as many data columns in this way to ensure the dictionary dependency is generated.
|
|
//
|
|
// @ANS = TableName_Actions('CalcField', 'CalcColName')
|
|
//
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
CalculateColumn:
|
|
|
|
// Make sure the ActionFlow return variable is cleared in case nothing is calculated.
|
|
ActionFlow = ''
|
|
|
|
Begin Case
|
|
Case CalcColName EQ 'CURR_LOCATION' ; GoSub CURR_LOCATION
|
|
Case CalcColName EQ 'HOT_LOT_FLAG' ; GoSub HOT_LOT_FLAG
|
|
Case CalcColName EQ 'LOAD_WFR_CNT' ; GoSub LOAD_WFR_CNT
|
|
Case CalcColName EQ 'SAP_YIELD' ; GoSub SAP_YIELD
|
|
Case CalcColName EQ 'WO_REACT_TYPE' ; GoSub WO_REACT_TYPE
|
|
Case CalcColName EQ 'FINAL_SIG_DT' ; GoSub FINAL_SIG_DT
|
|
Case CalcColName EQ 'FINAL_SIG_DTM' ; GoSub FINAL_SIG_DTM
|
|
End Case
|
|
|
|
return
|
|
|
|
|
|
CURR_LOCATION:
|
|
|
|
LastWH = @RECORD<6>[-1,'B':@VM]
|
|
LastLoc = @RECORD<7>[-1,'B':@VM]
|
|
Tmp = ''
|
|
IF @RECORD<13> NE '' THEN
|
|
Tmp = '' ;* Shipped
|
|
END ELSE
|
|
IF LastWH NE '' AND LastLoc NE '' THEN
|
|
Tmp = LastWH:'*':LastLoc
|
|
IF Tmp = 'SR*SB' THEN Tmp = ''
|
|
END
|
|
END
|
|
ActionFlow = Tmp
|
|
|
|
return
|
|
|
|
|
|
FINAL_SIG_DT:
|
|
|
|
ActionFlow = {FQA_DT}
|
|
|
|
return
|
|
|
|
|
|
FINAL_SIG_DTM:
|
|
|
|
ActionFlow = {FQA_DTM}
|
|
|
|
return
|
|
|
|
|
|
HOT_LOT_FLAG:
|
|
|
|
ActionFlow = Xlate('WO_LOG', {WO_NO}, 'HOT_FLAG', 'X')
|
|
|
|
return
|
|
|
|
|
|
LOAD_WFR_CNT:
|
|
|
|
ActionFlow = '' ; // Default description.
|
|
|
|
WOLogRow = Database_Services('ReadDataRow', 'WO_LOG', {WO_NO})
|
|
ReactType = WOLogRow<WO_LOG_REACT_TYPE$>
|
|
If ReactType _EQC 'EPP' OR ReactType _EQC 'EpiPro' then
|
|
WOStepKeyID = WOLogRow<WO_LOG_WO_STEP_KEY$>
|
|
WOStepRow = Database_Services('ReadDataRow', 'WO_STEP', WOStepKeyID)
|
|
Cassette = @ID[-1, 'B*']
|
|
RDSNo = WOStepRow<WO_STEP_RDS_KEY$, Cassette>
|
|
ActionFlow = Xlate('REACT_RUN', RDSNo, 'LOAD_WFR_CNT', 'X')
|
|
end else
|
|
ActionFlow = ''
|
|
end
|
|
|
|
return
|
|
|
|
|
|
SAP_YIELD:
|
|
|
|
If {REACTOR_TYPE} NE 'GAN' then
|
|
SAPData = obj_WO_Mat('GetGRProps',@ID:@RM:@RECORD)
|
|
* SAPData = GRWfrQty:@FM:ScrapQty:@FM:ProdTWQty:@FM:MUWfrQty
|
|
ActionFlow = SAPData<1> + SAPData<4>
|
|
|
|
end else
|
|
YieldInfo = Gan_Services('GetYieldInfo', {RDS_NO}, '')
|
|
GRWfrQty = YieldInfo<1>
|
|
ScrapQty = YieldInfo<2>
|
|
ProdTWQty = YieldInfo<3>
|
|
DummyQty = YieldInfo<4>
|
|
Yield = GRWfrQty - ScrapQty - ProdTWQty - DummyQty
|
|
ActionFlow = Yield
|
|
end
|
|
|
|
return
|
|
|
|
|
|
WO_REACT_TYPE:
|
|
|
|
WOLogRow = Database_Services('ReadDataRow', 'WO_LOG', {WO_NO})
|
|
ActionFlow = WOLogRow<WO_LOG_REACT_TYPE$>
|
|
|
|
return
|
|
|
|
|
|
// ----- MFS calls -----------------------------------------------------------------------------------------------------
|
|
|
|
READ_RECORD_PRE:
|
|
// In order to stop a record from being read in this action these lines of code must be used:
|
|
//
|
|
// OrigFileError = 100 : @FM : KeyID
|
|
// Status = 0
|
|
// Record = ''
|
|
// ActionFlow = ACTION_STOP$
|
|
return
|
|
|
|
|
|
READ_RECORD:
|
|
// In order to stop a record from being read in this action these lines of code must be used:
|
|
//
|
|
// OrigFileError = 100 : @FM : KeyID
|
|
// Status = 0
|
|
// Record = ''
|
|
return
|
|
|
|
|
|
READONLY_RECORD_PRE:
|
|
// In order to stop a record from being read in this action these lines of code must be used:
|
|
//
|
|
// OrigFileError = 100 : @FM : KeyID
|
|
// Status = 0
|
|
// Record = ''
|
|
// ActionFlow = ACTION_STOP$
|
|
return
|
|
|
|
|
|
READONLY_RECORD:
|
|
// In order to stop a record from being read in this action these lines of code must be used:
|
|
//
|
|
// OrigFileError = 100 : @FM : KeyID
|
|
// Status = 0
|
|
// Record = ''
|
|
return
|
|
|
|
|
|
WRITE_RECORD_PRE:
|
|
|
|
WOMatKeyID = Name
|
|
OrigRDSNo = OrigRecord<WO_MAT_RDS_NO$>
|
|
NewRDSNo = Record<WO_MAT_RDS_NO$>
|
|
|
|
If OrigRDSNo NE '' and NewRDSNo EQ '' and Not(MemberOf(@User4, 'OI_ADMIN')) then
|
|
|
|
Record<WO_MAT_RDS_NO$> = OrigRDSNo
|
|
SaveRecord = Record
|
|
LogData = ''
|
|
LogData<1> = LoggingDTM
|
|
LogData<2> = @USER4
|
|
LogData<3> = OrigRDSNo
|
|
LogData<4> = WOMatKeyID
|
|
If OrigRDSNo NE '' then
|
|
LogData<5> = Xlate('RDS', OrigRDSNo, 'WO_MAT_KEY', 'X')
|
|
end else
|
|
LogData<5> = ''
|
|
end
|
|
LogData<6> = 'RDS number cannot be removed. Setting RDS number back.'
|
|
Machine = Environment_Services('GetServer')
|
|
Logging_Services('AppendLog', ObjLog3, LogData, @RM, @FM, False$)
|
|
|
|
end
|
|
|
|
WaferQty = Record<WO_MAT_WAFER_QTY$>
|
|
If ( (WaferQty LT 0) or (WaferQty GT 25) ) then
|
|
// Erroneous wafer quantity save attempt. Fallback to default wafer quantity of 25.
|
|
Record<WO_MAT_WAFER_QTY$> = 25
|
|
SaveRecord = Record
|
|
end
|
|
|
|
If ({REACTOR_TYPE} EQ 'GAN') and ({FQA_DTM} NE {CASS_FINAL_SIG_DTM}) then
|
|
// Copy FQA date and datetime
|
|
DTM = {CASS_FINAL_SIG_DTM}
|
|
{FQA_DTM} = DTM
|
|
Date = {CASS_FINAL_SIG_DTM}[1, 'F.']
|
|
{FQA_DT} = Date
|
|
SaveRecord = @Record
|
|
end
|
|
|
|
// Sync up NCR signatures
|
|
NewNCRList = Record<WO_MAT_NCR_KEYS$>
|
|
OrigNCRList = OrigRecord<WO_MAT_NCR_KEYS$>
|
|
NewNCRSigs = Record<WO_MAT_NCR_FINAL_SIG$>
|
|
NewNCRSigDTMs = Record<WO_MAT_NCR_FINAL_SIG_DTM$>
|
|
|
|
// Check for deleted NCRs to remove final NCR signatures as needed.
|
|
For each OrigNCRNo in OrigNCRList using @VM setting vPos
|
|
NewNCRNo = NewNCRList<0, vPos>
|
|
If NewNCRNo EQ '' then
|
|
// An NCR has been deleted so we need to remove any final NCR signatures associate with it.
|
|
NewNCRSigs<0, vPos> = ''
|
|
NewNCRSigDTMs<0, vPos> = ''
|
|
end
|
|
Next OrigNCRNo
|
|
|
|
// Check for new NCRs to copy their final signature to the WO_MAT record.
|
|
For each NewNCRNo in NewNCRList using @VM setting vPos
|
|
// This is a new NCR, so copy the signature.
|
|
NewNCRSigs<0, vPos> = Xlate('NCR', NewNCRNo, 'AUTH_SHIP_SIG', 'X')
|
|
NewNCRSigDTMs<0, vPos> = Xlate('NCR', NewNCRNo, 'AUTH_SHIP_SIG_DTM', 'X')
|
|
Next NewNCRNo
|
|
|
|
// Trim trailing @VMs to avoid WO_MAT CURR_STATUS from erroneously calculating an open NCR is present.
|
|
NewNCRSigs = SRP_Array('Clean', NewNCRSigs, 'Trim', @VM)
|
|
NewNCRSigDTMs = SRP_Array('Clean', NewNCRSigDTMs, 'Trim', @VM)
|
|
Record<WO_MAT_NCR_FINAL_SIG$> = NewNCRSigs
|
|
Record<WO_MAT_NCR_FINAL_SIG_DTM$> = NewNCRSigDTMs
|
|
SaveRecord = Record
|
|
|
|
WONo = Field(Name, '*', 1)
|
|
ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X')
|
|
GaN = (ReactType EQ 'GAN')
|
|
If GaN then
|
|
// Sync QA signature with WO_MAT signature profile.
|
|
OrigCassFinalSig = OrigRecord<WO_MAT_CASS_FINAL_SIG$>
|
|
OrigCassFinalSigDTM = OrigRecord<WO_MAT_CASS_FINAL_SIG_DTM$>
|
|
CassFinalSig = Record<WO_MAT_CASS_FINAL_SIG$>
|
|
CassFinalSigDTM = Record<WO_MAT_CASS_FINAL_SIG_DTM$>
|
|
|
|
If ( (OrigCassFinalSig NE CassFinalSig) or (OrigCassFinalSigDTM NE CassFinalSigDTM) ) then
|
|
WOMatStage = '1G_FQA'
|
|
SigProf = Record<WO_MAT_SIG_PROFILE$>
|
|
Sigs = Record<WO_MAT_SIGNATURE$>
|
|
SigDTMs = Record<WO_MAT_SIG_DTM$>
|
|
Locate WOMatStage in SigProf using @VM setting vPos then
|
|
Sigs<0, vPos> = CassFinalSig
|
|
SigDTMs<0, vPos> = CassFinalSigDTM
|
|
Record<WO_MAT_SIGNATURE$> = Sigs
|
|
Record<WO_MAT_SIG_DTM$> = SigDTMs
|
|
SaveRecord = Record
|
|
end
|
|
end
|
|
end
|
|
|
|
Begin Case
|
|
Case {REACTOR_TYPE} EQ 'EPP'
|
|
// EpiPro Silicon - Populate OUT_SLOT_NCR column in WO_MAT record
|
|
NCRKeyChange = (OrigRecord<WO_MAT_NCR_KEYS$> NE Record<WO_MAT_NCR_KEYS$>)
|
|
NCRSlotChange = (OrigRecord<WO_MAT_EPOS_NCR$> NE Record<WO_MAT_EPOS_NCR$>)
|
|
WOMatSlotNCRs = {EPOS_NCR}
|
|
NCRKeys = {NCR_KEYS}
|
|
ChangeDetected = (NCRKeyChange or NCRSlotChange)
|
|
If ChangeDetected then
|
|
For each NCRKey in NCRKeys using @VM setting vPos
|
|
OutSlotNos = Xlate('NCR', NCRKey, 'OUT_SLOT_NO', 'X')
|
|
If OutSlotNos NE '' then
|
|
For each SlotNo in OutSlotNos using @VM setting sPos
|
|
WOMatSlotNCRs<0, SlotNo> = NCRKey
|
|
Next SlotNo
|
|
end
|
|
Next NCRKey
|
|
// Pad value marks if necessary
|
|
NumSlots = DCount(WOMatSlotNCRs, @VM)
|
|
If NumSlots LT 25 then WOMatSlotNCRs<0, 25> = ''
|
|
Record<WO_MAT_EPOS_NCR$> = WOMatSlotNCRs
|
|
SaveRecord = Record
|
|
end
|
|
Case {REACTOR_TYPE} EQ 'GAN'
|
|
// Galiumn Nitride - Currently no issues with NCR keys getting erased, so nothing to do here.
|
|
Null
|
|
Case Otherwise$
|
|
// Non-EpiPro Silicon - Populate SLOT_NCR column in WO_MAT record
|
|
NCRKeyChange = (OrigRecord<WO_MAT_NCR_KEYS$> NE Record<WO_MAT_NCR_KEYS$>)
|
|
NCRSlotChange = (OrigRecord<WO_MAT_SLOT_NCR$> NE Record<WO_MAT_SLOT_NCR$>)
|
|
ChangeDetected = (NCRKeyChange or NCRSlotChange)
|
|
If ChangeDetected then
|
|
SlotNCRs = {SLOT_NCR}
|
|
NCRKeys = {NCR_KEYS}
|
|
For each NCRKey in NCRKeys using @VM setting vPos
|
|
NCRSlotNos = Xlate('NCR', NCRKey, 'SLOT_NO', 'X')
|
|
If NCRSlotNos NE '' then
|
|
For each SlotNo in NCRSlotNos using @VM setting Dummy
|
|
SlotNCRs<0, SlotNo> = NCRKey
|
|
Next SlotNo
|
|
end
|
|
Next NCRKey
|
|
Record<WO_MAT_SLOT_NCR$> = SlotNCRs
|
|
SaveRecord = Record
|
|
end
|
|
NewMUFlag = Record<WO_MAT_MAKEUP_BOX$>
|
|
OrigMUFlag = OrigRecord<WO_MAT_MAKEUP_BOX$>
|
|
UnloadCheck = Signature_Services('GetStageSummary', WOMatKeyID, 'UNLOAD')<2>
|
|
If (NewMUFlag EQ True$) AND (OrigMUFlag NE True$) then
|
|
If UnloadCheck NE True$ then
|
|
OrigFileError = 104:': Cassette ineligible to be converted to makeup wafer until unload is signed.'
|
|
Status = 0
|
|
Record = ''
|
|
ActionFlow = ACTION_STOP$
|
|
end
|
|
end
|
|
|
|
End Case
|
|
|
|
TWChangeDetected = (OrigRecord<WO_MAT_SLOT_MET_NO$> NE Record<WO_MAT_SLOT_MET_NO$>)
|
|
If TWChangeDetected then
|
|
Begin Case
|
|
Case {REACTOR_TYPE} EQ 'EPP'
|
|
// EpiPro silicon -> build list of RDS_TEST keys and select those with TW_USE key(s).
|
|
RDSNos = Xlate('WM_IN', {WMI_KEY}, 'RDS_NO', 'X')
|
|
RDSNos = SRP_Array('Clean', RDSNos, 'TrimAndMakeUnique', @VM)
|
|
If RDSNos NE '' then
|
|
Query = 'SELECT RDS_TEST '
|
|
For each RDSNo in RDSNos using @VM setting vPos
|
|
If vPos EQ 1 then
|
|
Query := 'WITH RDS_NO EQ ':RDSNo:' '
|
|
end else
|
|
Query := 'OR WITH RDS_NO EQ ':RDSNo:' '
|
|
end
|
|
Next RDSNo
|
|
EOF = False$
|
|
RecordCopy = Record
|
|
RList(Query, TARGET_LATENTLIST$, '', '', '')
|
|
Query = 'SELECT RDS_TEST WITH TW_USE_ID NE ""'
|
|
RList(Query, TARGET_LATENTLIST$, '', '', '')
|
|
RDSTestKeys = ''
|
|
Loop
|
|
ReadNext KeyID else EOF = True$
|
|
Until EOF
|
|
RDSTestKeys<0, -1> = KeyID
|
|
Repeat
|
|
TWUseKeys = Xlate('RDS_TEST', RDSTestKeys, 'TW_USE_ID', 'X')
|
|
WaferIDs = Xlate('TW_USE', TWUseKeys, 'WAFER_ID', 'X')
|
|
SlotMetNos = ''
|
|
For each WaferID in WaferIDs using @VM setting vPos
|
|
SlotNo = Field(WaferID, '*', 3)
|
|
SlotMetNos<0, SlotNo> = TWUseKeys<0, vPos>
|
|
Next WaferID
|
|
Done = False$
|
|
NumVMs = DCount(SlotMetNos, @VM)
|
|
// Pad column with @VMs
|
|
If NumVMs LT 25 then SlotMetNos<0, 25> = ''
|
|
Record = RecordCopy
|
|
Record<WO_MAT_SLOT_MET_NO$> = SlotMetNos
|
|
SaveRecord = Record
|
|
end
|
|
Case {REACTOR_TYPE} EQ 'GAN'
|
|
// Gallium nitride -> TW_USE records do not apply, so nothing to do.
|
|
Null
|
|
Case Otherwise$
|
|
|
|
// Non-EpiPro silicon -> lookup RDS_TEST record and interrogate it for TW_USE key(s).
|
|
RDSNo = Record<WO_MAT_RDS_NO$>
|
|
If RDSNo NE '' then
|
|
Query = 'SELECT RDS_TEST WITH RDS_NO EQ ':RDSNo
|
|
EOF = False$
|
|
RecordCopy = Record
|
|
RList(Query, TARGET_LATENTLIST$, '', '', '')
|
|
Query = 'SELECT RDS_TEST WITH TW_USE_ID NE ""'
|
|
RList(Query, TARGET_LATENTLIST$, '', '', '')
|
|
RDSTestKeys = ''
|
|
Loop
|
|
ReadNext KeyID else EOF = True$
|
|
Until EOF
|
|
RDSTestKeys<0, -1> = KeyID
|
|
Repeat
|
|
TWUseKeys = Xlate('RDS_TEST', RDSTestKeys, 'TW_USE_ID', 'X')
|
|
// Rebuild list
|
|
SlotMetNos = ''
|
|
For each TWUseKey in TWUseKeys using @VM setting tPos
|
|
WaferIDs = Xlate('TW_USE', TWUseKey, 'WAFER_ID', 'X')
|
|
For each WaferID in WaferIDs using @VM setting vPos
|
|
SlotNo = Field(WaferID, '*', 3)
|
|
SlotMetNos<0, SlotNo> = TWUseKey
|
|
Next WaferID
|
|
Next TWUseKey
|
|
NumVMs = DCount(SlotMetNos, @VM)
|
|
// Pad column with @VMs
|
|
If NumVMs LT 25 then SlotMetNos<0, 25> = ''
|
|
Record = RecordCopy
|
|
Record<WO_MAT_SLOT_MET_NO$> = SlotMetNos
|
|
SaveRecord = Record
|
|
end
|
|
|
|
End Case
|
|
end
|
|
|
|
// Verify slot list does not exceed 25
|
|
NewSlotList = Record<WO_MAT_SLOT_NO$>
|
|
NumSlots = DCount(NewSlotList, @VM)
|
|
LastSlot = NewSlotList[-1, 'B':@VM]
|
|
If ( (NumSlots GT 25) or (LastSlot GT 25) ) then
|
|
|
|
LogCount = Max(NumSlots, LastSlot)
|
|
// Correct the slot column
|
|
NewSlotList = ''
|
|
For Slot = 1 to 25
|
|
NewSlotList<0, Slot> = Slot
|
|
Next Slot
|
|
Record<WO_MAT_SLOT_NO$> = NewSlotList
|
|
SaveRecord = Record
|
|
|
|
// Log the error
|
|
Stack = RetStack()
|
|
Swap @FM with CRLF$ in Stack
|
|
LogData = ''
|
|
LogData<1> = LoggingDTM
|
|
LogData<2> = @User4
|
|
LogData<3> = Name
|
|
LogData<4> = LogCount
|
|
LogData<5> = CRLF$:Stack
|
|
Logging_Services('AppendLog', objSlotLog, LogData, @RM, @FM)
|
|
|
|
// Send internal LSL message to OI admins
|
|
Recipients = XLATE('SEC_GROUPS', 'OI_ADMIN', 'USER', 'X')
|
|
SentFrom = @USER4
|
|
Subject = 'Slot count exceeds 25!'
|
|
Message = 'WO_MAT key ':Name
|
|
AttachWindow = 'WO_MAT'
|
|
AttachKey = Name
|
|
SendToGroup = ''
|
|
Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
|
|
obj_Notes('Create',Parms)
|
|
end
|
|
|
|
If {REACTOR_TYPE} EQ 'EPP' then
|
|
WMKey = Field(Name, '*', 1):'*1*':Field(Name, '*', 2)
|
|
// Only set fields if the records exist, otherwise WO_MAT curr status can be calculated incorrectly.
|
|
If RowExists('WM_IN', WMKey) then Record<WO_MAT_WMI_KEY$> = WMKey
|
|
If RowExists('WM_OUT', WMKey) then Record<WO_MAT_WMO_KEY$> = WMKey
|
|
SaveRecord = Record
|
|
end
|
|
|
|
SigProf = Record<WO_MAT_SIG_PROFILE$>
|
|
Sigs = Record<WO_MAT_SIGNATURE$>
|
|
SigDtms = Record<WO_MAT_SIG_DTM$>
|
|
NumSteps = DCount(SigProf, @VM)
|
|
Record<WO_MAT_SIGNATURE$> = Field(Sigs, @VM, 1, NumSteps)
|
|
Record<WO_MAT_SIG_DTM$> = Field(SigDtms, @VM, 1, NumSteps)
|
|
SaveRecord = Record
|
|
|
|
NewMUFlag = Record<WO_MAT_MAKEUP_BOX$>
|
|
OrigMUFlag = OrigRecord<WO_MAT_MAKEUP_BOX$>
|
|
If NewMUFlag NE OrigMUFlag then
|
|
SAPBatchNo = Record<WO_MAT_SAP_BATCH_NO$>
|
|
SAPTXDtm = Record<WO_MAT_SAP_TX_DTM$>
|
|
AwaitingBatchNo = ( (SAPTXDtm NE '') and (SAPBatchNo EQ '') )
|
|
FullBoxReject = (SAPBatchNo[-1, 1] = 'R')
|
|
Begin Case
|
|
Case AwaitingBatchNo
|
|
Error_Services('Add', 'Cassette ineligible to be converted as it is awaiting a batch number from SAP.')
|
|
OrigFileError = 104:': Cassette ineligible to be converted as it is awaiting a batch number from SAP.'
|
|
Status = 0
|
|
Record = ''
|
|
ActionFlow = ACTION_STOP$
|
|
Case FullBoxReject
|
|
Error_Services('Add', 'Cassette ineligible to be converted as it is a full box reject.')
|
|
OrigFileError = 104:': Cassette ineligible to be converted as it is a full box reject.'
|
|
Status = 0
|
|
Record = ''
|
|
ActionFlow = ACTION_STOP$
|
|
Case Otherwise$
|
|
Null
|
|
End Case
|
|
end
|
|
|
|
return
|
|
|
|
|
|
WRITE_RECORD:
|
|
|
|
WONo = Field(Name, '*', 1)
|
|
CassNo = Field(Name, '*', 2)
|
|
WOMatKeyID = Name
|
|
|
|
If {REACTOR_TYPE} NE 'EPP' then
|
|
If {MAKEUP_BOX} then
|
|
CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID)
|
|
CurrStatus = {CURR_STATUS}
|
|
If ( (CurrWaferCount GT 0) and (CurrStatus NE 'VOID') ) then
|
|
// Populate MAKEUP_WAFERS table
|
|
// Add/update cassette data to the MAKEUP_WAFERS table
|
|
If RowExists('MAKEUP_WAFERS', WOMatKeyID) then
|
|
MUWfrRec = Database_Services('ReadDataRow', 'MAKEUP_WAFERS', WOMatKeyID)
|
|
end else
|
|
MUWfrRec = ''
|
|
end
|
|
MUWfrRec<MAKEUP_WAFERS.SAP_BATCH_NO$> = {SAP_BATCH_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.PS_NO$> = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
|
|
MUWfrRec<MAKEUP_WAFERS.CUST_NO$> = {CUST_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.PROD_ORD_NO$> = {PROD_ORD_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.WAFER_SIZE$> = {WAFER_SIZE}
|
|
MUWfrRec<MAKEUP_WAFERS.EPI_PART_NO$> = {EPI_PART_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.RDS_NO$> = {RDS_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.WM_OUT_NO$> = '' ; // Only applies to EPP
|
|
MUWfrRec<MAKEUP_WAFERS.PROD_VER_NO$> = {PROD_VER_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.CUST_PART_NO$> = {CUST_PART_NO}
|
|
MUWfrRec<MAKEUP_WAFERS.REACT_TYPE$> = {REACTOR_TYPE}
|
|
MUWfrRec<MAKEUP_WAFERS.CURR_STATUS_STATIC$> = CurrStatus
|
|
MUWfrRec<MAKEUP_WAFERS.WFR_QTY$> = CurrWaferCount
|
|
DateOut = Xlate('RDS', {RDS_NO}, 'DATE_OUT', 'X')
|
|
TimeOut = Xlate('RDS', {RDS_NO}, 'TIME_OUT', 'X') / 86400
|
|
TimeOut[1, 2] = ''
|
|
TimeOut = TimeOut[1, 5]
|
|
UnloadDTM = DateOut:'.':TimeOut
|
|
MUWfrRec<MAKEUP_WAFERS.UNLOAD_DTM$> = UnloadDTM
|
|
Database_Services('WriteDataRow', 'MAKEUP_WAFERS', WOMatKeyID, MUWfrRec, True$, False$, True$)
|
|
end else
|
|
// Remove cassette data from MAKEUP_WAFERS table if it is present
|
|
If RowExists('MAKEUP_WAFERS', WOMatKeyID) then
|
|
Database_Services('DeleteDataRow', 'MAKEUP_WAFERS', WOMatKeyID, True$, False$)
|
|
end
|
|
end
|
|
end else
|
|
// Remove cassette data from MAKEUP_WAFERS table if it is present
|
|
If RowExists('MAKEUP_WAFERS', WOMatKeyID) then
|
|
Database_Services('DeleteDataRow', 'MAKEUP_WAFERS', WOMatKeyID, True$, False$)
|
|
end
|
|
end
|
|
end
|
|
|
|
OrigSlotNos = OrigRecord<WO_MAT_SLOT_NO$>
|
|
OrigSlotNCRs = OrigRecord<WO_MAT_SLOT_NCR$>
|
|
OrigSlotMetNos = OrigRecord<WO_MAT_SLOT_MET_NO$>
|
|
OrigSlotMovedTos = OrigRecord<WO_MAT_SLOT_MOVED_TO$>
|
|
OrigSlotRepWaferIDs = OrigRecord<WO_MAT_SLOT_REP_WAFER_ID$>
|
|
OrigVoid = OrigRecord<WO_MAT_VOID$>
|
|
OrigShipNo = OrigRecord<WO_MAT_SHIP_NO$>
|
|
OrigInvLoc = OrigRecord<WO_MAT_INV_LOCATION$>
|
|
OrigInvWH = OrigRecord<WO_MAT_INV_WH$>
|
|
OrigWMICurrStatus = OrigRecord<WO_MAT_WMI_CURR_STATUS$>
|
|
OrigWMOCurrStatus = OrigRecord<WO_MAT_WMO_CURR_STATUS$>
|
|
OrigHoldEntity = OrigRecord<WO_MAT_HOLD_ENTITY$>
|
|
OrigSigs = OrigRecord<WO_MAT_SIGNATURE$>
|
|
OrigCancelled = OrigRecord<WO_MAT_CANCELLED$>
|
|
OrigSubSupplBy = OrigRecord<WO_MAT_SUB_SUPPL_BY$>
|
|
OrigRetRejects = OrigRecord<WO_MAT_RET_REJECTS$>
|
|
OrigMakeupBox = OrigRecord<WO_MAT_MAKEUP_BOX$>
|
|
OrigNCRKeys = OrigRecord<WO_MAT_NCR_KEYS$>
|
|
OrigNCRFinalSig = OrigRecord<WO_MAT_NCR_FINAL_SIG$>
|
|
OrigSlotNo = OrigRecord<WO_MAT_SLOT_NO$>
|
|
OrigSlotNCR = OrigRecord<WO_MAT_SLOT_NCR$>
|
|
OrigSlotMetNo = OrigRecord<WO_MAT_SLOT_MET_NO$>
|
|
OrigSlotMovedTo = OrigRecord<WO_MAT_SLOT_MOVED_TO$>
|
|
OrigSlotRepWaferID = OrigRecord<WO_MAT_SLOT_REP_WAFER_ID$>
|
|
OrigSAPBatchNo = OrigRecord<WO_MAT_SAP_BATCH_NO$>
|
|
OrigQty = OrigRecord<WO_MAT_WAFER_QTY$>
|
|
|
|
NewSlotNos = Record<WO_MAT_SLOT_NO$>
|
|
NewSlotNCRs = Record<WO_MAT_SLOT_NCR$>
|
|
NewSlotMetNos = Record<WO_MAT_SLOT_MET_NO$>
|
|
NewSlotMovedTos = Record<WO_MAT_SLOT_MOVED_TO$>
|
|
NewSlotRepWaferIDs = Record<WO_MAT_SLOT_REP_WAFER_ID$>
|
|
NewVoid = Record<WO_MAT_VOID$>
|
|
NewShipNo = Record<WO_MAT_SHIP_NO$>
|
|
NewInvLoc = Record<WO_MAT_INV_LOCATION$>
|
|
NewInvWH = Record<WO_MAT_INV_WH$>
|
|
NewWMICurrStatus = Record<WO_MAT_WMI_CURR_STATUS$>
|
|
NewWMOCurrStatus = Record<WO_MAT_WMO_CURR_STATUS$>
|
|
NewHoldEntity = Record<WO_MAT_HOLD_ENTITY$>
|
|
NewSigs = Record<WO_MAT_SIGNATURE$>
|
|
NewCancelled = Record<WO_MAT_CANCELLED$>
|
|
NewSubSupplBy = Record<WO_MAT_SUB_SUPPL_BY$>
|
|
NewRetRejects = Record<WO_MAT_RET_REJECTS$>
|
|
NewMakeupBox = Record<WO_MAT_MAKEUP_BOX$>
|
|
NewNCRKeys = Record<WO_MAT_NCR_KEYS$>
|
|
NewNCRFinalSig = Record<WO_MAT_NCR_FINAL_SIG$>
|
|
NewSlotNo = Record<WO_MAT_SLOT_NO$>
|
|
NewSlotNCR = Record<WO_MAT_SLOT_NCR$>
|
|
NewSlotMetNo = Record<WO_MAT_SLOT_MET_NO$>
|
|
NewSlotMovedTo = Record<WO_MAT_SLOT_MOVED_TO$>
|
|
NewSlotRepWaferID = Record<WO_MAT_SLOT_REP_WAFER_ID$>
|
|
NewSAPBatchNo = Record<WO_MAT_SAP_BATCH_NO$>
|
|
NewQty = Record<WO_MAT_WAFER_QTY$>
|
|
|
|
** NCR log for troubleshooting ****************************
|
|
LogData = ''
|
|
LogData<1> = LoggingDTM
|
|
LogData<2> = @User4
|
|
LogData<3> = WOMatKeyID
|
|
LogData<4> = NewSlotNCRs
|
|
LogData<5> = RetStack()
|
|
Logging_Services('AppendLog', objNCRLog, LogData, @RM, @FM)
|
|
***********************************************************
|
|
|
|
// Check for ship quantity changes and update WO_LOG<WO_LOG_STATIC_SHIP_QTY$>
|
|
ShipQtyChange = ( (OrigSlotNos NE NewSlotNos) or (OrigSlotNCRs NE NewSlotNCRs) or (OrigSlotMetNos NE NewSlotMetNos) or (OrigSlotMovedTos NE NewSlotMovedTos) or (OrigSlotRepWaferIDs NE NewSlotRepWaferIDs) )
|
|
If ShipQtyChange then
|
|
WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo)
|
|
OrigShipQty = WOLogRec<WO_LOG_STATIC_SHIP_QTY$>
|
|
NewShipQty = obj_WO_Log('ShipQty',WONo:@RM:WOLogRec)
|
|
If OrigShipQty NE NewShipQty then
|
|
WOLogRec<WO_LOG_STATIC_SHIP_QTY$> = NewShipQty
|
|
Database_Services('WriteDataRow', 'WO_LOG', WONo, WOLogRec, True$, False$, True$)
|
|
end
|
|
end
|
|
|
|
// Original MU wafer transaction
|
|
IF OrigSAPBatchNo EQ '' AND NewSAPBatchNo NE '' then
|
|
MULotFlag = False$
|
|
If {REACTOR_TYPE} NE 'EPP' then
|
|
MULotFlag = Record<WO_MAT_MAKEUP_BOX$>
|
|
end else
|
|
WMOKey = Record<WO_MAT_WMO_KEY$>
|
|
IF WMOKey NE '' then
|
|
MULotFlag = XLATE('WM_OUT', WMOKey, 'MAKEUP_BOX', 'X')
|
|
If MULotFlag EQ '' then MULotFlag = False$
|
|
end
|
|
end
|
|
Sap_Services('SendUnTransMU', WOMatKeyID, NewSAPBatchNo, MULotFlag)
|
|
end
|
|
|
|
// SAP transactions
|
|
MakeupBox = Record<WO_MAT_MAKEUP_BOX$>
|
|
SAPBatchNo = Trim(Record<WO_MAT_SAP_BATCH_NO$>)
|
|
MakeupBoxOrig = OrigRecord<WO_MAT_MAKEUP_BOX$>
|
|
|
|
Begin Case
|
|
Case ( (MakeupBox EQ True$) and ( (MakeupBoxOrig EQ False$) or (MakeupBoxOrig EQ '') ) and (SAPBatchNo EQ '') )
|
|
// Intial WIP to MU conversion -> Send CASS_COMP SAP transaction to get a batch number.
|
|
SAP_Services('AddCassCompTransaction', WOMatKeyID)
|
|
Case ( (MakeupBox EQ True$) and ( (MakeupBoxOrig EQ False$) or (MakeupBoxOrig EQ '') ) and (SAPBatchNo NE '') )
|
|
// Converting finished goods cassette into MU cassette -> Send BATCH_CONV transaction to SAP.
|
|
SAP_Services('AddBatchConvTransaction', WOMatKeyID)
|
|
Case ( ( (MakeupBox EQ False$) or (MakeupBox EQ '') ) and (MakeupBoxOrig EQ True$) and (SAPBatchNo NE '') )
|
|
// Converting MU cassette into finished goods cassette -> Send BATCH_CONV transaction to SAP.
|
|
SAP_Services('AddBatchConvTransaction', WOMatKeyID)
|
|
End Case
|
|
|
|
SAPTestFlag = Xlate('APP_INFO', 'SAP_TEST_FLAG', 1, 'X')
|
|
If SAPTestFlag then
|
|
// If makeup wafers added/removed after CASS_COMP and if not shipped -> send to SAP
|
|
IF ({SAP_BATCH_NO} NE '') THEN
|
|
|
|
MakeupBox = {MAKEUP_BOX}
|
|
OrigMUWfrIDs = OrigRecord<WO_MAT_SLOT_MOVED_FROM$>
|
|
NewMUWfrIDs = Record<WO_MAT_SLOT_MOVED_FROM$>
|
|
SAPSLocFrom = ''
|
|
SAPSLocTo = ''
|
|
If (OrigMUWfrIDs NE NewMUWfrIDs) then
|
|
Material = Xlate('WO_LOG', WONo, 'EPI_PART_NO', 'X')
|
|
For WfrIndex = 1 to 25
|
|
BatchFrom = ''
|
|
BatchTo = ''
|
|
OrigMUWfrID = OrigMUWfrIDs<0, WfrIndex>
|
|
NewMUWfrID = NewMUWfrIDs<0, WfrIndex>
|
|
Begin Case
|
|
Case ( (OrigMUWfrID EQ '') and (NewMUWfrID NE '') )
|
|
// MU wafer added
|
|
If MakeupBox EQ True$ then
|
|
// Current box is a makeup box and new box is a makeup box. We want to update
|
|
// the batch number in SAP.
|
|
SAPSLocFrom = '0400'
|
|
SAPSLocTo = '0400'
|
|
end else
|
|
SAPSLocFrom = '0400'
|
|
SAPSLocTo = '0500'
|
|
end
|
|
// Add transaction
|
|
NewMUCassID = Field(NewMUWfrID, '.', 1, 2)
|
|
Convert '.' to '*' in NewMUCassID
|
|
BatchFrom = Xlate('WO_MAT', NewMUCassID, 'SAP_BATCH_NO', 'X')
|
|
BatchTo = {SAP_BATCH_NO}
|
|
If ( (BatchFrom NE '') and (BatchTo NE '') ) then
|
|
TransQty = 1
|
|
obj_SAP('AddTransaction','BATCHMOVE_IN':@RM:Material:@RM:BatchFrom:@RM:BatchTo:@RM:SAPSLocFrom:@RM:SAPSLocTo:@RM:TransQty)
|
|
end
|
|
Case ( (OrigMUWfrID NE '') and (NewMUWfrID EQ '') )
|
|
// MU wafer removed
|
|
If MakeupBox EQ True$ then
|
|
// Current box is a makeup box and new box is a makeup box. We want to update
|
|
// the batch number in SAP.
|
|
SAPSLocFrom = '0400'
|
|
SAPSLocTo = '0400'
|
|
end else
|
|
SAPSLocFrom = '0500'
|
|
SAPSLocTo = '0400'
|
|
end
|
|
// Add transaction
|
|
OrigMUCassID = Field(OrigMUWfrID, '.', 1, 2)
|
|
Convert '.' to '*' in OrigMUCassID
|
|
BatchFrom = {SAP_BATCH_NO}
|
|
BatchTo = Xlate('WO_MAT', OrigMUCassID, 'SAP_BATCH_NO', 'X')
|
|
If ( (BatchTo NE '') and (BatchFrom NE '') ) then
|
|
TransQty = 1
|
|
obj_SAP('AddTransaction','BATCHMOVE_IN':@RM:Material:@RM:BatchFrom:@RM:BatchTo:@RM:SAPSLocFrom:@RM:SAPSLocTo:@RM:TransQty)
|
|
end
|
|
Case Otherwise$
|
|
// No change
|
|
Null
|
|
End Case
|
|
Next WfrIndex
|
|
end
|
|
end
|
|
end
|
|
|
|
PSNo = {WO_STEP_PS_NO}
|
|
|
|
If {REACTOR_TYPE} EQ 'EPP' then
|
|
NewEppMUFlag = Record<WO_MAT_EPO_MAKEUP_BOX$>
|
|
OrigEppMUFlag = OrigRecord<WO_MAT_EPO_MAKEUP_BOX$>
|
|
NewInvActions = Record<WO_MAT_INV_ACTION$>
|
|
OrigInvActions = OrigRecord<WO_MAT_INV_ACTION$>
|
|
If ( (NewEppMUFlag NE OrigEppMUFlag) or (NewInvActions NE OrigInvActions) ) then
|
|
// Need to trigger an update WMO Curr Status field because WM_MFS is not
|
|
// attached to the WO_MAT table and the WMO status may have changed.
|
|
WMOKey = {WMO_KEY}
|
|
WMORec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey)
|
|
If Error_Services('NoError') then
|
|
Database_Services('WriteDataRow', 'WM_OUT', WMOKey, WMORec, True$, False$, True$)
|
|
end
|
|
end
|
|
end
|
|
|
|
If OrigRecord<WO_MAT_WAFER_QTY$> NE Record<WO_MAT_WAFER_QTY$> then
|
|
Work_Order_Services('UpdateReceivedQty', WONo)
|
|
Work_Order_Services('UpdateReleasedQty', WONo)
|
|
end
|
|
|
|
CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID)
|
|
If CurrWaferCount EQ 0 then
|
|
// This should catch cases where the entire cassette is "peeled off", NCR'ed, or used for destructive testing.
|
|
Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'MarkCassProcessed':@VM:WONo:@VM:CassNo:@VM:Datetime())
|
|
end
|
|
|
|
return
|
|
|
|
|
|
DELETE_RECORD_PRE:
|
|
return
|
|
|
|
|
|
DELETE_RECORD:
|
|
return
|
|
|
|
|
|
// ----- Internal Methods ----------------------------------------------------------------------------------------------
|
|
|
|
Initialize_System_Variables:
|
|
|
|
// Save these for restoration later
|
|
SaveDict = @DICT
|
|
SaveID = @ID
|
|
SaveRecord = @RECORD
|
|
OrigFileError = @FILE.ERROR
|
|
|
|
// Now make sure @DICT, ID, and @RECORD are populated
|
|
CurrentDictName = ''
|
|
If @DICT then
|
|
DictHandle = @DICT<1, 2>
|
|
Locate DictHandle in @TABLES(5) Using @FM Setting fPos then
|
|
CurrentDictName = Field(@TABLES(0), @FM, fPos, 1)
|
|
end
|
|
end
|
|
|
|
If CurrentDictName NE DictName then
|
|
Open DictName to @DICT else Status = 'Unable to initialize @DICT'
|
|
end
|
|
|
|
@ID = KeyID
|
|
If Record else
|
|
// Record might not have been passed in. Read the record from the database table just to make sure.
|
|
@FILE.ERROR = ''
|
|
Open TableName to hTable then
|
|
FullFSList = hTable[1, 'F' : @VM]
|
|
BFS = FullFSList[-1, 'B' : @SVM]
|
|
LastHandle = hTable[-1, 'B' : \0D\]
|
|
FileHandle = \0D\ : LastHandle[1, @VM]
|
|
|
|
Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus)
|
|
end
|
|
end
|
|
@RECORD = Record
|
|
|
|
return
|
|
|
|
|
|
Restore_System_Variables:
|
|
|
|
Transfer SaveDict to @DICT
|
|
Transfer SaveID to @ID
|
|
Transfer SaveRecord to @RECORD
|
|
@FILE.ERROR = OrigFileError
|
|
|
|
return
|
|
|