Imports ProductiePitching.configs Imports ProductiePitching.ServiceAgents Imports ProductiePitching.ServiceAgents.Implementations Module CacheMapper #Region "Help functions" Private ReadOnly _activiteitPerBatchServiceAgent As IActiviteitPerBatchServiceAgent Sub New() _activiteitPerBatchServiceAgent = New ActiviteitPerBatchServiceAgent End Sub ''' ''' Execution of a query into a data reader. ''' ''' The query Private Function ExecuteIntoDataSet(query As String) As DataSet Try Return _activiteitPerBatchServiceAgent.GeefDataSetVoorQuery(query) Catch ex As Exception Throw New Exception($"Could not get dataset from the Caché webservice.{vbNewLine}{ex.Message}") End Try End Function Private Function ExtractItemFromDataReader(Of T)(ByRef dr As DataTableReader, key As String, Optional defaultValue As T = Nothing) As T Dim value As Object Try 'Check if the column name is not present. If not present, return default value. If Not HasColumn(dr, key) Then Return defaultValue 'Extract the value with the key. value = dr.Item(key) 'Check if the value is DBNull or Nothing. If IsDBNull(value) Or value Is Nothing Then 'If so, return default value. Return defaultValue End If Catch ex As Exception Throw New Exception($"A value for a work item can't be fetched from the data reader. The key is '{key}'.") End Try Try 'Do the conversion explicitly, so exceptions can be caught. Return CType(value, T) Catch ex As Exception Throw New Exception($"A value for a work item can't be converted to the specified type. The key is '{key}', the type is {GetType(T).Name}, the value is {value}.") End Try End Function ''' ''' Check if the data reader has a column with that name. ''' ''' ''' ''' Private Function HasColumn(ByRef dr As DataTableReader, columnName As String) As Boolean 'Loop through each row. For Each row As DataRow In dr.GetSchemaTable().Rows 'Check if column name matches defined one. If row("ColumnName").ToString() = columnName Then Return True Next 'Column name was not found. Return False End Function #End Region ''' ''' Get the correct query. ''' ''' ''' Private Function FetchQuery(workPostIndex As Integer) As String 'Fetch queries from config. Dim sqlQueries = ConfigsLoader.SqlQueries() 'Check if index is valid. If workPostIndex >= sqlQueries.Count Or workPostIndex < 0 Then Throw New InternalException($"Can't fetch a Caché query with this work post index: {workPostIndex}") End If 'If so, return correct query. Return sqlQueries.Item(workPostIndex) End Function ''' ''' Fetch all the work items for a workpost. ''' The corresponding query will get fetched in here. ''' ''' The index of the workpost, 0 based ''' A list of all the work items with their activities Public Function GetData(workPostIndex As Integer, employees As List(Of IEmployee)) As List(Of IWorkItem) 'Fetch the query. Dim queryName As String = FetchQuery(workPostIndex) 'Initialise the list with work items. Dim workItems As New List(Of IWorkItem) 'Declare datareader. Dim CacheDataReader As DataTableReader = Nothing Try 'Execute query and store datareader. Dim CacheDataSet As DataSet = ExecuteIntoDataSet(queryName) CacheDataReader = CacheDataSet.CreateDataReader() 'Fetch amount of activities. Dim activityAmount = FetchNumberOfActivities(workPostIndex) 'Loop through every (result) record. While CacheDataReader.Read() 'Values of one result (line/record). Dim workItem As New WorkItem 'Fill with values. With workItem .BatchVisual = ExtractItemFromDataReader(CacheDataReader, "BatchVisual", String.Empty) .DeliverToResource = ExtractItemFromDataReader(CacheDataReader, "Naar", String.Empty) .ProductGroup = ExtractItemFromDataReader(CacheDataReader, "Productgroep", String.Empty) .Remark = ExtractItemFromDataReader(CacheDataReader, "Opmerking", String.Empty) .EndTimeStamp = ExtractItemFromDataReader(CacheDataReader, "EindTijdstip", DateTime.MinValue) .Activities = ExtractActivities(CacheDataReader, activityAmount, workItem, employees) End With 'Add to the result list. workItems.Add(workItem) End While 'Return the list. Return workItems Catch ex As Exception Throw New Exception($"An error occured while fetching the work items from Caché.{vbNewLine}{ex.Message}") Finally 'Close connection if datareader is not nothing. If Not IsNothing(CacheDataReader) Then CacheDataReader.Close() End If End Try End Function #Region "Activities" ''' ''' Extract all activities for one work item from the data reader. ''' ''' ''' Private Function ExtractActivities(dr As DataTableReader, numberOfActivities As Integer, workItem As IWorkItem, employees As List(Of IEmployee)) As List(Of IActivity) 'Declare result list. Dim activities As New List(Of IActivity) 'Loop for every activity. For i = 1 To numberOfActivities 'Initialise activity and fill with values. Dim activity As New Activity With activity .Id = ExtractItemFromDataReader(dr, $"ActiviteitID_{i}", String.Empty) .QuantityToProduce = ExtractItemFromDataReader(dr, $"Aantal_{i}", 0) .Label = ExtractItemFromDataReader(dr, $"Label_{i}", String.Empty) .IsReadOnly = ExtractItemFromDataReader(dr, $"ReadOnly_{i}", False) .StartTimeStamp = ExtractItemFromDataReader(dr, $"StartTijdstip_{i}", DateTime.MinValue) 'Subtract time when date was specified. Time is gotten from config. .StartBeforeTimestamp = If(.StartTimeStamp = DateTime.MinValue, DateTime.MinValue, .StartTimeStamp.Subtract(ConfigsLoader.StartBeforeTimeThreshold)) .StartAlmostTimeStamp = If(.StartTimeStamp = DateTime.MinValue, DateTime.MinValue, .StartTimeStamp.Subtract(ConfigsLoader.StartAlmostTimeThreshold)) 'Set parent work item. .WorkItem = workItem 'Fetch the employee if defined. Dim employeeInitials = ExtractItemFromDataReader(dr, $"Gebruiker_{i}", String.Empty) Dim employee As IEmployee = If(employeeInitials.Equals(String.Empty), Nothing, employees.FirstOrDefault(Function(employeeToCheck) employeeToCheck.Initials.Equals(employeeInitials))) 'Set the current state based on the enum value. If the quantity is 0, the status is automatically zero. Dim stateValue = ActivityStateEnum.Zero If (.QuantityToProduce > 0) Then stateValue = ActivityStateEnumMapper.GetActivityStateFromLetter(ExtractItemFromDataReader(Of Char)(dr, $"Status_{i}")) If (employee Is Nothing) Then employee = DummyEmployee() End If End If .State = ConvertEnumValueToActivityState(stateValue, activity, employee) End With 'Add to collection of activities. activities.Add(activity) Next 'Return list. Return activities End Function Private Function DummyEmployee() As Employee Dim dummy As Employee = New Employee() With dummy .FirstName = "VH" .LastName = "Automation" .PersonelNumber = 0 .Number = 0 .Initials = "" End With Return dummy End Function ''' ''' Get the correct amount of activities. ''' ''' ''' Private Function FetchNumberOfActivities(workPostIndex As Integer) As String 'Fetch queries from config. Dim activityAmounts = ConfigsLoader.NumbersOfActivities() 'Check if index is valid. If workPostIndex >= activityAmounts.Count Or workPostIndex < 0 Then Throw New InternalException($"Can't fetch the amount of activities with this work post index: {workPostIndex}") End If 'If so, return correct amount. Return activityAmounts.Item(workPostIndex) End Function ''' ''' Produces an activity state based on the state enum value. The activity becomes part of the state. ''' ''' ''' ''' Private Function ConvertEnumValueToActivityState(stateEnumValue As ActivityStateEnum, activity As IActivity, employee As IEmployee) As ActivityState 'Get employee if any. Select Case stateEnumValue Case ActivityStateEnum.Zero Return New ActivityZeroState(activity) Case ActivityStateEnum.Defaulted Return New ActivityDefaultedState(activity) Case ActivityStateEnum.Stopped Return New ActivityStoppedState(activity, employee) Case ActivityStateEnum.Started Return New ActivityStartedState(activity, employee) Case ActivityStateEnum.Finished Return New ActivityFinishedState(activity, employee) Case Else Throw New InternalException($"Activity state enum value '{stateEnumValue}' cannot be used to map to an activity state.") End Select End Function #End Region End Module