Compile function WM_Out_Services(@Service, @Params)
/***********************************************************************************************************************

    Name        :   WM_Out_Services

    Description :   Handler program for all WM_OUT services.

    Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
                    assumptions built into way errors are managed which are important to understand in order to properly
                    work with Error Services:

                    - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
                      the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
                      this will appear backwards since the originating procedure always appears at the bottom of the
                      list and the current routine appears at the top of the list. We are using this orientation because
                      it is common to refer to the process of calling other procedures as 'drilling down'.

                    - The reason for defining the orientation of the call stack is because Error_Services allows for
                      multiple error conditions to be appended to an original error. In most cases this will happen when
                      a procedure at the bottom of the stack generates an error condition and then returns to its
                      calling procedure. This higher level procedure can optionally add more information relevant to
                      itself. This continues as the call stack 'bubbles' its way back to the top to where the
                      originating procedure is waiting.

                    - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
                      preserve their error state until explicitly cleared. This can hinder the normal execution of code
                      since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
                      Our philosophy is that error conditions should automatically be cleared before a new procedure
                      is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
                      automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
                      philosophy then it should include a call into the 'Clear' service request at the top of the
                      program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)

                    - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
                      error conditions that were set before.

    Parameters  :
        Service         [in] -- Name of the service being requested
        Param1-10   [in/out] -- Additional request parameter holders
        Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure

    Metadata    :

    History     :   (Date, Initials, Notes)
        11/16/22    djs     Original programmer.
        08/31/23	djm		Added view/add comment functions.

***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler

$Insert SERVICE_SETUP
$Insert LOGICAL
$Insert MSG_EQUATES
$Insert DICT_EQUATES
$Insert WM_OUT_EQUATES
$Insert WO_MAT_EQUATES
$Insert WO_LOG_EQUATES
$Insert COMPANY_EQUATES
$Insert RETURN_TO_FAB_LOTS_EQUATES

Declare function   Database_Services, SRP_JSON, Error_Services, Clean_Insp_Services, WO_Mat_QA_Services
Declare function   PSN_Services, SRP_Rotate_Array, Datetime, Return_To_Fab_Services
Declare subroutine Database_Services, SRP_JSON, Error_Services, Extract_Si_Keys, Set_Status, obj_wo_mat_log

GoToService

Return Response or ""

//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------


//----------------------------------------------------------------------------------------------------------------------
// GetComments
//
// WMOutNo - [Required]
//
// Returns a delimited array of all EPP_COMMENT_NOTE, EPP_COMMENT_USER, and EPP_COMMENT_DATE
// associated with a WM_OUT record. Note: Dates are returned Oconv'd.
//----------------------------------------------------------------------------------------------------------------------
Service GetComments(WMOutNo)
    
    CommentArray = ''
    WMOutRow          = Database_Services('ReadDataRow', 'WM_OUT', WMOutNo)

	CommentDates = Oconv(WMOutRow<WM_OUT_EPP_COMMENT_DATE$>, 'DT')
    CommentUsers = WMOutRow<WM_OUT_EPP_COMMENT_USER$>
    Comments = WMOutRow<WM_OUT_EPP_COMMENT_NOTE$>

    CommentList = CommentDates :@FM: CommentUsers :@FM: Comments
    CommentArray = SRP_Rotate_Array(CommentList)
    Response = CommentArray

End Service


//----------------------------------------------------------------------------------------------------------------------
// AddComment
//
// WMOutNo - [Required]
// Comment - [Required]
//
// Adds  an EPP_COMMENT_NOTE, EPP_COMMENT_USER, and EPP_COMMENT_DATE
// to a WM_OUT record.
//----------------------------------------------------------------------------------------------------------------------
Service AddComment(WMOutNo, Comment, UsernameOpt)
    
    WMOutRow          = Database_Services('ReadDataRow', 'WM_OUT', WMOutNo)
    UserName		= @USER4
    If Assigned(UsernameOpt) then
		If UsernameOpt NE '' then
			Username = UsernameOpt
		end
	end
    CommentTime		= Datetime()

	OldDates = WMOutRow<WM_OUT_EPP_COMMENT_DATE$>
	OldUsers = WMOutRow<WM_OUT_EPP_COMMENT_USER$>
    OldComments = WMOutRow<WM_OUT_EPP_COMMENT_NOTE$>
       If (OldDates EQ '' AND OldUsers EQ '' AND OldComments EQ '') then
			WMOutRow<WM_OUT_EPP_COMMENT_DATE$> = CommentTime
			WMOutRow<WM_OUT_EPP_COMMENT_USER$> = UserName
			WMOutRow<WM_OUT_EPP_COMMENT_NOTE$> = Comment
       end else
       		WMOutRow<WM_OUT_EPP_COMMENT_DATE$> = CommentTime  :@VM: OldDates
			WMOutRow<WM_OUT_EPP_COMMENT_USER$> = UserName :@VM: OldUsers
			WMOutRow<WM_OUT_EPP_COMMENT_NOTE$> = Comment :@VM: OldComments
       end
	Database_Services('WriteDataRow', 'WM_OUT', WMOutNo, WMOutRow, 1, 0, 0)
	
End Service


Service ConvertRecordToJSON(KeyID, Record, ItemURL)
    
    jsonRecord    = ''

    If KeyID NE '' then

        If Record EQ '' then Record = Database_Services('ReadDataRow', 'WM_OUT', KeyID)
        If Error_Services('NoError') then
            @DICT   = Database_Services('GetTableHandle', 'DICT.WM_OUT')
            @ID     = KeyID
            @RECORD = Record
            objJSON = ''
            If SRP_JSON(objJSON, 'New', 'Object') then
                objWMOut = ''
                If SRP_JSON(objWMOut, 'New', 'Object') then 
                    SRP_JSON(objWMOut, 'SetValue', 'keyId', @ID)
                    SRP_JSON(objWMOut, 'SetValue', 'workOrder', {WO_NO})
                    SRP_JSON(objWMOut, 'SetValue', 'outCassNo', {OUT_CASS_NO})
                    WoMatKey            = {WO_NO} : '*' : {OUT_CASS_NO}
                    SAPBatchNo          = Database_Services('ReadDataColumn', 'WO_MAT', WoMatKey, WO_MAT_SAP_BATCH_NO$, True$, 0, False$)
                    SRP_JSON(objWMOut, 'SetValue', 'SapBatchNo', SAPBatchNo, 'String')
                    CurrWfrQty          = XLATE('WO_MAT', WoMatKey, 'CURR_WFR_CNT', 'X')
                    SRP_JSON(objWMOut, 'SetValue', 'CURR_WFR_CNT', CurrWfrQty)
                    CustNo              = Database_Services('ReadDataColumn', 'WO_LOG', {WO_NO}, WO_LOG_CUST_NO$, True$, 0, False$)
                    CustReshipNo = Database_Services('ReadDataColumn', 'WO_MAT', WoMatKey, WO_MAT_RESHIP_CUST_NO$, True$, 0, False$)
					If CustReshipNo NE '' then
					    CustNo = CustReshipNo
					end
                    CustName            = Database_Services('ReadDataColumn', 'COMPANY', CustNo, COMPANY_CO_NAME$, True$, 0, False$)
                    CustAbbrev          = Database_Services('ReadDataColumn', 'COMPANY', CustNo, COMPANY_ABBREV$, True$, 0, False$)
                    SRP_JSON(objWMOut, 'SetValue', 'CustNo', CustNo)
                    SRP_JSON(objWMOut, 'SetValue', 'CustName', CustName)
                    SRP_JSON(objWMOut, 'SetValue', 'CustAbbrev', CustAbbrev)
                    SRP_JSON(objWMOut, 'SetValue', 'PSN', {PS_NO})
                    SRP_JSON(objWMOut, 'SetValue', 'partNo', {PART_NO})
                    SRP_JSON(objWMOut, 'SetValue', 'postEpiSig', {POST_EPI_SIG})
                    SRP_JSON(objWMOut, 'SetValue', 'postEpiSigDtm', OConv({POST_EPI_SIG_DTM}, 'DT/^1HS'))
                    SRP_JSON(objWMOut, 'SetValue', 'supVerSig', {SUP_VER_SIG})
                    SRP_JSON(objWMOut, 'SetValue', 'supVerSigDtm', OConv({SUP_VER_SIG_DTM}, 'DT/^1HS'))
                    CINos               = {EPO_CI_NO}
                    // Add a PSN object
                    ProdSpecJSON        = PSN_Services('ConvertRecordToJSON', {PS_NO})
                    objProdSpecResponse = ''
                    If SRP_JSON(objProdSpecResponse, 'Parse', ProdSpecJSON) EQ '' then
                        objProdSpec = SRP_JSON(objProdSpecResponse, 'Get', 'prodSpec')
                        SRP_JSON(objWMOut, 'Set', 'prodSpec', objProdSpec)
                        SRP_JSON(objProdSpec, 'Release')
                        SRP_JSON(objProdSpecResponse, 'Release')
                    end
                    // Add CLEAN_INSP object(s)
                    If CINos NE '' then
                        objCleanInspArray = ''
                        If SRP_JSON(objCleanInspArray, 'New', 'Array') then
                            For each CINo in CINos using @VM setting vPos
                                If CINo NE '' then
                                    CleanInspJSON = Clean_Insp_Services('ConvertRecordToJSON', CINo)
                                    objCleanInsp  = ''
                                    If SRP_JSON(objCleanInsp, 'Parse', CleanInspJSON) EQ '' then
                                        objTemp = SRP_JSON(objCleanInsp, 'Get', 'cleanInsp')
                                        SRP_JSON(objCleanInspArray, 'Add', objTemp)
                                        SRP_JSON(objTemp, 'Release')
                                        SRP_JSON(objCleanInsp, 'Release')
                                    end
                                end
                            Next CINo
                            SRP_JSON(objWMOut, 'Set', 'cleanInsp', objCleanInspArray)
                            SRP_JSON(objCleanInspArray, 'Release')
                        end
                    end
                    
                    // Add WO_MAT_QA object
                    WOMatQAKey  = Field(KeyID, '*', 1):'*':Field(KeyID, '*', 3)
                    WOMatQAJSON = WO_Mat_QA_Services('ConvertRecordToJSON', WOMatQAKey)
                    objWOMatQA  = ''
                    If SRP_JSON(objWOMatQA, 'Parse', WOMatQAJSON) EQ '' then
                        objTemp = SRP_JSON(objWOMatQA, 'Get', 'woMatQa')
                        SRP_JSON(objWMOut, 'Set', 'woMatQA', objTemp)
                        SRP_JSON(objTemp, 'Release')
                        SRP_JSON(objWOMatQA, 'Release')
                    end
                    AllRTFRecords = Return_To_Fab_Services('GetReturnToFabRecordIdByCassId', KeyID)
                    If AllRTFRecords NE '' then
                        objRTFRecords = ''
                        If SRP_JSON(objRTFRecords, 'New', 'Array') then
                            For each RTFRecordId in AllRTFRecords using @VM setting vPos
                                objRTF = ''
                                If SRP_JSON(objRTF, 'New', 'Object') then
                                   RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFRecordId, True$, 0, False$)
                                   SRP_JSON(objRTF, 'SetValue', 'ReturnToFabLotsId', RTFRecordId)
                                   SRP_JSON(objRTF, 'SetValue', 'StartDtm', OConv(RTFRecord<RETURN_TO_FAB_LOTS_MH_INIT_DTM$>, 'DT'))
                                   SRP_JSON(objRTF, 'SetValue', 'Completed', RTFRecord<RETURN_TO_FAB_LOTS_COMPLETED$>, 'Boolean')
                                   SRP_JSON(objRTFRecords, 'Set', 'ReturnToFabRecord', objRTF)
                                   SRP_JSON(objRTFRecords, 'Add', objRTF)
					               SRP_JSON(objRTF, 'Release')
                                end
                            Next RTFRecordId
                                
                            SRP_JSON(objWMOut, 'Set', 'ReturnToFabRecords', objRTFRecords)
                            SRP_JSON(objRTFRecords, 'Release')
                        end
                    end else
                        SRP_JSON(objWMOut, 'SetValue', 'ReturnToFabRecords', '')
                    end
                    SRP_JSON(objJSON, 'Set', 'wmOut', objWMOut)
                    SRP_JSON(objWMOut, 'Release')
                end
                
                If itemURL NE '' then
                    // The itemURL was passed in so add HAL+JSON properties.
                    // Create the _links property and then all link objects needed for this resource.
                    objLinks = ''
                    If SRP_JSON(objLinks, 'New', 'Object') then
                        // Create a self link.
                        objLink = ''
                        If SRP_JSON(objLink, 'New', 'Object') then
                            SRP_JSON(objLink, 'SetValue', 'href', ItemURL, 'String')
                            SRP_JSON(objLink, 'SetValue', 'title', 'Self', 'String')
                            SRP_JSON(objLinks, 'Set', 'self', objLink)
                            SRP_JSON(objLink, 'Release')
                        end
                        SRP_JSON(objJSON, 'Set', '_links', objLinks)
                        SRP_JSON(objLinks, 'Release')
                    end
                    // Create the _class property for this resource.
                    SRP_JSON(objJSON, 'SetValue', '_class', 'resource')
                end
                jsonRecord = SRP_JSON(objJSON, 'Stringify', 'Styled')
                SRP_JSON(objJSON, 'Release')
            end else
                Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
            end
        end
    end else
        Error_Services('Add', 'KeyID argument was missing in the ' : Service : ' service.')
    end

    Response    = jsonRecord
    
End Service


//----------------------------------------------------------------------------------------------------------------------
// GetWMOData
//
// WorkOrderNo. - [Required]
// KeysOnly.    - [Optional]
//
// Returns a list of WMO records within a supplied Work Order.
// Rows are @FM delimted while columns are @VM delimited.
//----------------------------------------------------------------------------------------------------------------------
Service GetWMOData(WorkOrderNo, Columns, ShowGasGauge, WMOOverrideList)

    WMOList   = ''

    If ( (WorkOrderNo NE '') or (WMOOverrideList NE '') ) then
        If ShowGasGauge NE True$ then ShowGasGauge = False$
        rv              = Set_Status(0)
        WMOKeys         = ''
        
        If WorkOrderNo NE '' then
            Extract_Si_Keys('WM_OUT', 'WO_NO', WorkOrderNo, WMOKeys)
        end else
            Swap @FM with @VM in WMOOverrideList
            WMOKeys = WMOOverrideList
        end
        StatusCode      = ''
        If Get_Status(StatusCode) then
            Error_Services('Add', 'Error calling Extract_SI_Keys in the ' : Service : ' service. StatusCode: ' : StatusCode)
        end else
            NumWMO = DCount(WMOKeys, @VM)
            
            If ShowGasGauge then
                Def = ""
                Def<MCAPTION$>   = "Loading Outbound Cassettes..."
                Def<MTYPE$>      = "G"
                Def<MEXTENT$>    = NumWMO
                Def<MTEXTWIDTH$> = 400
                Def<MCOL$>       = -2        ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
                Def<MROW$>       = -2        ;* message v-pos in pixels
                MsgUp  = Msg(@Window, Def)
            end
            
            @DICT  = Database_Services('GetTableHandle', 'DICT.' : 'WM_OUT')
            If Error_Services('NoError') then
                For each @ID in WMOKeys using @VM setting fPos
                    @RECORD = Database_Services('ReadDataRow', 'WM_OUT', @ID)
                    If Error_Services('NoError') then
                        For each Column in Columns using @VM setting vPos
                            Begin Case
                        		Case Column EQ 'HOLD'
									HoldStatus          = Calculate(Column)
									If HoldStatus EQ True$ then
										HoldStatus = 'On Hold'
									end else
										HoldStatus = 'Off Hold'
									end
									WMOList<fPos, vPos> = HoldStatus
                        		Case Otherwise$
									Val  = Calculate(Column)
									Conv = Xlate('DICT.WM_OUT', Column, DICT_CONV$, 'X')
									If Conv NE '' then
										Val  = OConv(Val, Conv)
									end
									WMOList<fPos, vPos> = Val
                            End Case
                        Next Column
                    end else
                        Error_Services('Add', 'Error reading WM_OUT Record ' : @ID : ' in the ' : Service : ' service.')
                    end
                    * update the gauge
                If ShowGasGauge then Msg(@Window, MsgUp, fPos, MSGINSTUPDATE$)
                Next @ID
            end else
                Error_Services('Add', 'Error opening WM_OUT dictionary in the ' : Service : ' service.')
            end
        end
    end else
        Error_Services('Add', 'WorkOrderNo or WMOOverrideList argument was missing from the ' : Service : ' service.')
    end
    If ShowGasGauge then Msg(@Window, MsgUp)         ;* take down the gauge
    Response    = WMOList

end service


//----------------------------------------------------------------------------------------------------------------------
// GetWaferMap
//
// Returns a @VM delimited array of boolean values, which represents which slots are filled.
// Note: The response is in the slot order 25, 24, ..., 2, 1.
//----------------------------------------------------------------------------------------------------------------------
Service GetWaferMap(WMOKey)
    
    WaferMap = ''
    ErrorMsg = ''
    If WMOKey NE '' then
        If RowExists('WM_OUT', WMOKey) then
            WOMatKey  = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X')
            ReactType = Xlate('WO_MAT', WOMatKey, 'REACTOR_TYPE', 'X')
            If ReactType EQ 'EPP' then 
                RDSNos   = Xlate('WM_OUT', WMOKey, 'RDS', 'X')
                WaferMap = ''
                For SlotIndex = 1 to 25
                    RDSNo    = RDSNos<0, SlotIndex>
                    WaferMap = Insert(WaferMap, 0, 1, 0, (RDSNo NE '') )
                Next SlotIndex
            end else
                ErrorMsg = 'Error in ':Service:' service. Non-EpiPro is not supported by this service. Use WO_MAT_SERVICES instead.'
            end
        end else
            ErrorMsg = 'Error in ':Service:' service. WM_OUT record ':WMOKey:' does not exist.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WMOKey passed in.'
    end
    
    If ErrorMsg EQ '' then
        Response = WaferMap
    end else
        Error_Services('Add', ErrorMsg)
        Response = False$
    end
    
end service

Service SetVoidFlag(WMOutKey, Username)
	ErrorMessage = ''
	If RowExists('WM_OUT', WMOutKey) then
			WMOutRec = Database_Services('ReadDataRow', 'WM_OUT', WMOutKey, True$, 0, False$)
			If Error_Services('NoError') then
				WMOutRec<WM_OUT_VOID$> = True$
				Database_Services('WriteDataRow', 'WM_OUT', WMOutKey, WMOutRec, True$, False, False$)
				If Error_Services('NoError') then    
				    Set_Status(0)
					WONo = Field(WMOutKey, '*', 1)
                    CassNo = Field(WMOutKey, '*', 3)
                    WOMLParms = ''
                    LogFile	= 'WO_MAT'					; WOMLParms  = LogFile:@RM
                    LogDTM	= OConv(Datetime(), 'DT')	; WOMLParms := LogDTM:@RM
                    Action	= 'WM_OUT_VOID'				; WOMLParms := Action:@RM
                    WhCd	= 'CR'						; WOMLParms := WhCd:@RM
                    LocCd	= 'VOID'					; WOMLParms := LocCd:@RM
                    WONos	= WONo						; WOMLParms := WONos:@RM
                    CassNos	= CassNo					; WOMLParms := CassNos:@RM
                    UserID	= Username					; WOMLParms := UserID:@RM
                    Tags	= ''						; WOMLParms := Tags:@RM
                    ToolID	= ''						; WOMLParms := ToolID:@RM
                    WOMLParms := ''
                    obj_WO_Mat_Log('Create',WOMLParms)
                    IF Get_Status(errCode) THEN
                        ErrorMessage = 'Error writing inventory transactions'
                    end
				end else
				    ErrorMessage = 'Failed to write to the WM_OUT record ' : WMOutKey : ' while attempting to set void                     status.'
				end
			end else
				ErrorMessage = 'Failed to read WM_OUT record ' : WMOutKey : ' while attempting to set void status.'
			end
	end else
		ErrorMessage = 'Invalid WM_OUT Key ' : WMOutKey : ' passed to SetVoidFlag routine.'
	end
	If ErrorMessage NE '' then
		Error_Services('Add', ErrorMessage)
	end
end service




