Function WO_LOG_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
/***********************************************************************************************************************

    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_LOG_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

***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert APP_INSERTS
$Insert FILE.SYSTEM.EQUATES
$Insert ACTION_SETUP
$Insert WO_MAT_EQUATES
$Insert WO_LOG_EQUATES
$Insert WO_STEP_EQUATES
$Insert RLIST_EQUATES
$Insert SCHED_DET_NG_EQUATES
$Insert IFX_EQUATES

Equ Comma$ to ','

Declare function   Error_Services, Database_Services, Environment_Services, Logging_Services, obj_WO_Mat, Datetime
Declare function   GaN_Services, obj_WO_Log, SRP_Date
Declare subroutine Error_Services, Database_Services, Environment_Services, Logging_Services, Obj_SAP
Declare subroutine Logging_Services, Set_Status, Schedule_Services, Work_Order_Services, obj_Notes
Declare subroutine Schedule_Services, Service_Services

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_LOG'
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 : 'WO No' : @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] : ' Delete Attempt Log.csv'
Headers      = 'Logging DTM' : @FM : 'WO No' : @FM : 'Notes'
objDeleteLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)

LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WO_HOLD Log.csv'
Headers     = 'Logging DTM' : @FM : 'WO No' : @FM : 'User'
objHoldLog  = 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 'GAN_COST_TYPE'              ; GoSub GAN_COST_TYPE
        Case CalcColName EQ 'SAP_YIELD_QTY'              ; GoSub SAP_YIELD_QTY

    End Case

return


GAN_COST_TYPE:
    
    EpiStruct = {EPI_STRUCTURE}
    Begin Case
        Case ( (EpiStruct EQ 'HV') or (IndexC(EpiStruct, 'HEKLA', 1) GT 0) )
            ActionFlow = 'High Voltage'
        Case EpiStruct EQ 'MV'
            ActionFlow = 'Mid Voltage'
        Case Otherwise$
            ActionFlow = ''
    End Case
    
return


SAP_YIELD_QTY:

    If {REACTOR_TYPE} NE 'GAN' then
        ActionFlow = SUM({WO_MAT_SAP_YIELD})
    end else
        WOStepRec = Database_Services('ReadDataRow', 'WO_STEP', {WO_STEP_KEY})
        WOYield   = 0
        
        RDSKeys = WOStepRec<WO_STEP_RDS_KEY$>
        For each RDSKey in RDSKeys using @VM
            RDSYieldInfo = GaN_Services('GetYieldInfo', RDSKey)
            GRWfrQty  = RDSYieldInfo<1>
            ScrapQty  = RDSYieldInfo<2>
            ProdTWQty = RDSYieldInfo<3>
            DummyQty  = RDSYieldInfo<4>
            RDSYield  = GRWfrQty - ScrapQty - ProdTWQty - DummyQty
            WOYield   += RDSYield
        Next RDSKey
    end
    ActionFlow = WOYield
    
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:

    OrigQty      = OrigRecord<WO_LOG_QTY$>
    NewQty       = Record<WO_LOG_QTY$>
    ModifyQty    = NewQty - OrigQty    
    OrigCassList = OrigRecord<WO_LOG_WO_MAT_KEY$>
    NewCassList  = Record<WO_LOG_WO_MAT_KEY$>
    If ( (OrigQty NE NewQty) or (OrigCassList NE NewCassList) ) then
        // Update unreleased, open (i.e., not received) quantities
        RelQty = OrigRecord<WO_LOG_REL_QTY_STATIC$>
        If RelQty GT NewQty then
            UnRelQty = 0
        end else
            UnRelQty = NewQty - RelQty
        end
        Record<WO_LOG_UNREL_QTY_STATIC$> = UnRelQty
        
        RxQty = OrigRecord<WO_LOG_RX_QTY_STATIC$>
        If RxQty GT NewQty then
            OpenQty = 0
        end else
            OpenQty = NewQty - RxQty
        end
        Record<WO_LOG_OPEN_QTY_STATIC$> = OpenQty
        SaveRecord                      = Record
    end

	// Check if we need to auto-close the work order
    EntryDate    = Record<WO_LOG_ENTRY_DATE$>
    Today        = Date()
    YearsOpen    = SRP_Date('YearSpan', EntryDate, Today, True$)
    ScrapQty     = Record<WO_LOG_SCRAP_QTY_STATIC$>
    ShipQty      = Record<WO_LOG_SHIP_QTY_STATIC$>
    CurrStatus   = Record<WO_LOG_CURR_STATUS_STATIC$>
    CloseDate    = Record<WO_LOG_CLOSE_DATE$>
    LegacyStatus = Record<WO_LOG_STATUS$>
    If ( ( (CurrStatus NE 'CL') or (CloseDate EQ '') or (LegacyStatus NE 'C') ) and ( ( (ScrapQty + ShipQty) GE NewQty ) or (YearsOpen GE 1) ) ) then
    	If (CloseDate EQ '')	 then Record<WO_LOG_CLOSE_DATE$>   		 = Date()
    	If (CurrStatus NE 'CL')  then Record<WO_LOG_CURR_STATUS_STATIC$> = 'CL'
    	If (LegacyStatus NE 'C') then Record<WO_LOG_STATUS$>			 = 'C'
    	SaveRecord                         = Record
    end
    
    // For work orders already closed, ensure CurrStatus, LegacyStatus, and Close date are consistent
    If ( (CurrStatus EQ 'CL') or (CloseDate NE '') or (LegacyStatus EQ 'C') ) then
    	If (CloseDate EQ '')	 then Record<WO_LOG_CLOSE_DATE$>   		 = Date()
    	If (CurrStatus NE 'CL')  then Record<WO_LOG_CURR_STATUS_STATIC$> = 'CL'
    	If (LegacyStatus NE 'C') then Record<WO_LOG_STATUS$>			 = 'C'
    	SaveRecord                         = Record
    end
    
return

WRITE_RECORD:

    Machine = Environment_Services('GetServer')
    
    If OrigRecord<WO_LOG_WO_HOLD$> NE Record<WO_LOG_WO_HOLD$> then
        // Log the user changing this flag.
        LogData    = ''
        LogData<1> = LoggingDTM
        LogData<2> = Name
        LogData<3> = @User4
        Message    = @User4:' changed WO_HOLD flag for work order ':Name
        Logging_Services('AppendLog', objHoldLog, LogData, @RM, @FM)
    end

    If ( (OrigRecord<WO_LOG_LAST_CHAR_RUN$> NE '') and (Record<WO_LOG_LAST_CHAR_RUN$> EQ '') and (Machine _NEC 'MESSA01EC') ) then
        Stack = RetStack()
        LogData = ''
        LogData<1> = LoggingDTM
        LogData<2> = Name
        LogData<3> = Stack
        Convert @FM to CRLF$ in Stack
        Message = 'Last char run erased on work order ':Name:'.':CRLF$:CRLF$:'Call Stack':CRLF$:Stack
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM, '', '', '')
    end

    OrigQty       = OrigRecord<WO_LOG_QTY$>
    NewQty        = Record<WO_LOG_QTY$>
    ModifyQty     = NewQty - OrigQty
    WONo          = Name
    If ModifyQty NE 0 then Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'AdjustWorkOrderScheduleQty':SD$:WONo:SD$:ModifyQty)
    
return

DELETE_RECORD_PRE:

	// Log which user and computer station attempted to delete the record
	LogData    = ''
	LogData<1> = LoggingDTM
	LogData<2> = Name
	LogData<3> = @User4
	Logging_Services('AppendLog', objDeleteLog, LogData, @RM, @FM)
	
	// Send an LSL message to FI admins to alert them
	Recipients   = Xlate('SEC_GROUPS', 'OI_ADMIN', 'USER', 'X')
	SentFrom     = 'SYSTEM'
	Subject      = 'WO_LOG Delete Attempt'
	Message      = 'An attempt to delete WO_LOG record ':Name:' was made by ':@User4:'.'
	AttachWindow = 'NDW_WO_LOG'
	AttachKey    = Name
	SendToGroup  = ''

	Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
	obj_Notes('Create',Parms)
	
	// Stop the system from deleting the record
	ActionFlow = ACTION_STOP$
	
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

ClearCursors:
    For counter = 0 to 8
        ClearSelect counter
    Next counter
return

