Add support for multiple functions per field, add ADDRESS function

This commit is contained in:
Jonathan Jenne 2023-06-26 11:27:51 +02:00
parent 7846e660b9
commit 68e4c59e63
9 changed files with 274 additions and 154 deletions

View File

@ -9,6 +9,7 @@
Public Const FUNCTION_SQL = "SQL"
Public Const FUNCTION_FIELD = "FIELD"
Public Const FUNCTION_RUNNINGNUMBER = "RUNNINGNUMBER"
Public Const FUNCTION_ADDRESS = "ADDRESS"
Public Const PLACEHOLDER_CONST = "CONST"
Public Const PLACEHOLDER_FIELD = "FIELD"
@ -65,6 +66,8 @@
MissingValue
AccountNotFound
ArticleNotFound
PriceNotCalculated
MissingParameter
End Enum
Public Class FieldError

View File

@ -8,6 +8,7 @@ Imports MultiTool.Common.Winline
Imports MultiTool.Common.Winline.Entities
Imports MultiTool.Common.Constants
Imports DigitalData.Modules.Database
Imports DevExpress.Utils.CommonDialogs
Namespace Documents
Public Class DocumentLoader
@ -88,7 +89,7 @@ Namespace Documents
Public Async Function LoadFile(pFileInfo As FileInfo, pTemplate As Template, pMandator As Mandator) As Task(Of Document)
Logger.Debug("Creating new Document object for file [{0}]", pFileInfo.Name)
Dim oDocument As Document = New Document With {
Dim oDocument As New Document With {
.File = pFileInfo,
.Schema = pTemplate
}
@ -349,6 +350,12 @@ Namespace Documents
Private Function ApplySQLFunctionForImport(pDocument As Document, pSQLConfig As List(Of FieldConfig)) As Document
For Each oSQLConfigItem In pSQLConfig
For Each oFunction In oSQLConfigItem.Functions
If Not oFunction.Name = FUNCTION_SQL Then
Continue For
End If
' FieldList is a list of fields that will be changed
' Example: Setting SQL for Article StorageLocation will invoke the sql for each row
Dim oRowList = pDocument.Rows.
@ -356,7 +363,8 @@ Namespace Documents
ToList()
For Each oRow As DocumentRow In oRowList
Dim oSQL = oSQLConfigItem.Function.Params
Dim oSQL = oFunction.Params
Dim oField = oRow.Fields.
Where(Function(field) field.Key = oSQLConfigItem.Name).
SingleOrDefault()
@ -368,7 +376,11 @@ Namespace Documents
If oValue IsNot Nothing Then
oField.Value.SetExternalValue(oValue)
End If
Next
Next
Next
Return pDocument
@ -400,8 +412,12 @@ Namespace Documents
Continue For
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
For Each oFunction As FieldConfig.ColumnFunction In oColumn.Config.Functions
Dim oFunctionName = oFunction.Name
Dim oFunctionParams = oFunction.Params
If oFunctionName = String.Empty Then
Continue For
@ -418,6 +434,7 @@ Namespace Documents
End If
Next
Next
Next
Return pDocument
End Function
@ -431,14 +448,17 @@ Namespace Documents
Exit For
End If
Dim oColumn = oTable.Columns.Where(Function(c) c.Name = oField.Key).SingleOrDefault()
Dim oItemName As String = oField.Key
Dim oColumn = oTable.Columns.Where(Function(c) c.Name = oItemName).SingleOrDefault()
If oColumn Is Nothing Then
Continue For
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
For Each oFunction As FieldConfig.ColumnFunction In oColumn.Config.Functions
Dim oFunctionName = oFunction.Name
Dim oFunctionParams = oFunction.Params
' The code below needs a defined function
If oFunctionName = String.Empty Then
@ -449,22 +469,28 @@ Namespace Documents
' The main identifier will be checked for String.empty and not required.
' This makes sure that optional fields do not generate errors.
Dim oIdentifier As DocumentRow.FieldValue = oRow.Fields.GetOrDefault(oField.Key)
Dim oIdentifier As DocumentRow.FieldValue = oRow.Fields.GetOrDefault(oItemName)
If oIdentifier.Original = String.Empty And oIdentifier.IsRequired = False Then
Continue For
End If
Select Case oFunctionName
Case FUNCTION_GLN
SetAccountByGLN(oRow, pMandator, oField.Key, Nothing, oParamsDict)
SetAccountByGLN(oRow, pMandator, oItemName, Nothing, oParamsDict)
Case FUNCTION_EAN
SetArticleByEAN(oRow, pMandator, oField.Key)
SetArticleByEAN(oRow, pMandator, oItemName)
Case FUNCTION_RUNNINGNUMBER
Await SetVersionedRunningNumber(pDocument, oRow, pMandator, oField.Key, oParamsDict)
Await SetVersionedRunningNumber(pDocument, oRow, pMandator, oItemName, oParamsDict)
Case FUNCTION_ADDRESS
Await SetAddressByAccountNumber(pDocument, oRow, pMandator, oItemName, oParamsDict)
End Select
Next
Next
Next
@ -489,11 +515,13 @@ Namespace Documents
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
For Each oFunction As FieldConfig.ColumnFunction In oColumn.Config.Functions
Dim oFunctionName = oFunction.Name
Dim oFunctionParams = oFunction.Params
Dim oParamsDict = Parameters.Parse(oFunctionParams)
If oFunctionName = Constants.FUNCTION_FIELD Then
If oFunctionName = FUNCTION_FIELD Then
Try
Logger.Debug("Applying function FIELD to field [{0}]", oField.Key)
@ -532,6 +560,9 @@ Namespace Documents
End Try
End If
Next
Next
Next
Return pDocument
@ -629,6 +660,7 @@ Namespace Documents
Logger.Info("Price for Item [{0}] set to [{1}]", pPriceField, oArticlePrice)
Else
Logger.Warn("Price for Item [{0}] could not be found!", pPriceField)
oPriceItem.AddFieldError(FieldErrorType.PriceNotCalculated, "Der Preis für diese Position konnte nicht ermittelt werden.")
End If
End Function
@ -662,8 +694,8 @@ Namespace Documents
End If
' Try to find an account that matches the GLN
Dim oAlternateField = pParams.GetOrDefault("AltField", String.Empty)
Dim oAccount = Winline.TryGetAccount(oNumberItem.Original, pMandator, "c260", oAlternateField)
Dim oAlternateField As String = pParams.GetOrDefault("AltField", String.Empty)
Dim oAccount As Account = Winline.TryGetAccount(oNumberItem.Original, pMandator, "c260", oAlternateField)
' If an account was found, set it for External and Final value
If oAccount IsNot Nothing Then
@ -715,6 +747,68 @@ Namespace Documents
Throw ex
End Try
End Function
Public Function SetAddressByAccountNumber(pDocument As Document, pRow As DocumentRow, pMandator As Mandator, pAccountField As String, pParams As Dictionary(Of String, String)) As Task
Try
Const PARAMETER_NAME = "Name"
Const PARAMETER_STREET = "Street"
Const PARAMETER_ZIP = "Zip"
Const PARAMETER_CITY = "City"
Dim oAccountNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pAccountField)
Dim oAccountNumber = oAccountNumberItem.Final
Dim oNameField As String = pParams.GetOrDefault(PARAMETER_NAME, Nothing)
Dim oNameFieldItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oNameField)
If oNameField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function ADDRESS", PARAMETER_NAME)
oAccountNumberItem.AddFieldError(FieldErrorType.MissingParameter, $"Parameter '{PARAMETER_NAME}' wurde nicht gefüllt.")
End If
Dim oStreetField As String = pParams.GetOrDefault(PARAMETER_STREET, Nothing)
Dim oStreetFieldItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oStreetField)
If oStreetField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function ADDRESS", PARAMETER_STREET)
oAccountNumberItem.AddFieldError(FieldErrorType.MissingParameter, $"Parameter '{PARAMETER_STREET}' wurde nicht gefüllt.")
End If
Dim oZipField As String = pParams.GetOrDefault(PARAMETER_ZIP, Nothing)
Dim oZipFieldItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oZipField)
If oZipField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function ADDRESS", PARAMETER_ZIP)
oAccountNumberItem.AddFieldError(FieldErrorType.MissingParameter, $"Parameter '{PARAMETER_ZIP}' wurde nicht gefüllt.")
End If
Dim oCityField As String = pParams.GetOrDefault(PARAMETER_CITY, Nothing)
Dim oCityFieldItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oCityField)
If oCityField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function ADDRESS", PARAMETER_CITY)
oAccountNumberItem.AddFieldError(FieldErrorType.MissingParameter, $"Parameter '{PARAMETER_CITY}' wurde nicht gefüllt.")
End If
Dim oAccount = Winline.Accounts.Where(Function(a) a.Id = oAccountNumber And a.Mandator.Equals(pMandator)).SingleOrDefault()
If oAccount Is Nothing Then
Logger.Warn("Account with Id [{0}] in Mandator [{1}] could not be found.", oAccountNumber, pMandator.Id)
End If
oNameFieldItem.SetExternalValue(oAccount.Name)
oStreetFieldItem.SetExternalValue(oAccount.StreetName)
oZipFieldItem.SetExternalValue(oAccount.ZipCode)
oCityFieldItem.SetExternalValue(oAccount.CityName)
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
Return Task.CompletedTask
End Function
End Class
End Namespace

View File

@ -112,7 +112,8 @@ Public Class ReportGenerator(Of TReport As IReport)
ToList()
For Each oRow As DocumentRow In oRowList
Dim oSQL = oSQLConfigItem.Function.Params
For Each oFunction In oSQLConfigItem.Functions
Dim oSQL = oFunction.Params
Dim oField = oRow.Fields.
Where(Function(field) field.Key = oSQLConfigItem.Name).
SingleOrDefault()
@ -126,6 +127,7 @@ Public Class ReportGenerator(Of TReport As IReport)
End If
Next
Next
Next
Return pDocument
End Function

View File

@ -3,6 +3,7 @@ Imports DigitalData.Modules.Language
Namespace Templates
Public Class FieldConfig
Public Property Id As Integer
Public Property Name As String
Public Property Table As String
Public Property Type As ColumnType
@ -16,19 +17,7 @@ Namespace Templates
Public Property IsVirtual As Boolean
Public Property PreferExternalValue As Boolean
Public Property [Function] As ColumnFunction
Public ReadOnly Property FunctionName As String
Get
Return Utils.NotNull([Function]?.Name, String.Empty)
End Get
End Property
Public ReadOnly Property FunctionParams As String
Get
Return Utils.NotNull([Function]?.Params, String.Empty)
End Get
End Property
Public Property Functions As New List(Of ColumnFunction)
Public Class ColumnFunction
Public Id As XmlFunction

View File

@ -11,7 +11,7 @@ Namespace Templates
Public ReadOnly Property SqlItems As List(Of FieldConfig)
Get
Return Items.
Where(Function(item) item.Function.Name = Constants.FUNCTION_SQL).
Where(Function(item) item.Functions.Any(Function(f) f.Name = Constants.FUNCTION_SQL)).
ToList()
End Get
End Property

View File

@ -19,6 +19,7 @@ Namespace Templates
Private Const SQL_TBMT_FILTERS = "SELECT * FROM [DD_ECM].[dbo].[VWMT_FILTERS]"
Private Const SQL_VWMT_ITEMS = "SELECT * FROM [DD_ECM].[dbo].[VWMT_ITEMS] ORDER BY TEMPLATE_NAME, TABLE_NAME"
Private Const SQL_VWMT_FUNCTIONS = "SELECT * FROM [DD_ECM].[dbo].[VWMT_FUNCTIONS] ORDER BY ITEM_ID, SEQUENCE"
Private Const SQL_VWMT_MAPPING = "SELECT * FROM [DD_ECM].[dbo].[VWMT_MAPPING]"
Private Const SQL_TBMT_MANDATORS = "SELECT * FROM [DD_ECM].[dbo].[TBMT_MANDATORS] ORDER BY ORDER_KEY"
Private Const SQL_TBMT_CONFIG = "SELECT * FROM [DD_ECM].[dbo].[TBMT_CONFIG]"
@ -191,6 +192,7 @@ Namespace Templates
For Each oRow As DataRow In oTable.Rows
Dim oColumn As New FieldConfig() With {
.Id = oRow.ItemEx("ITEM_ID", 0),
.Template = oRow.ItemEx("TEMPLATE_NAME", String.Empty),
.Table = oRow.ItemEx("TABLE_NAME", String.Empty),
.Name = oRow.ItemEx("ITEM_NAME", String.Empty),
@ -202,11 +204,7 @@ Namespace Templates
.IsVirtual = oRow.ItemEx("IS_VIRTUAL", False),
.IsHead = oRow.ItemEx("IS_HEAD", True),
.PreferExternalValue = oRow.ItemEx("PREFER_EXTERNAL", True),
.[Function] = New FieldConfig.ColumnFunction With {
.Id = oRow.ItemEx("FUNCTION_ID", 0),
.Name = oRow.ItemEx("FUNCTION_NAME", String.Empty),
.Params = oRow.ItemEx("FUNCTION_PARAMETERS", String.Empty)
}
.Functions = New List(Of FieldConfig.ColumnFunction)
}
Logger.Debug("Creating Template Item for Table [{0}]: [{1}]", oColumn.Table, oColumn.Name)
@ -227,6 +225,37 @@ Namespace Templates
End Try
End Function
Public Async Function LoadTemplateFunctions() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_VWMT_FUNCTIONS)
Dim oItems As New List(Of FieldConfig)
For Each oRow As DataRow In oTable.Rows
Dim oTemplateItemId = oRow.ItemEx("ITEM_ID", 0)
Dim oTemplateItem = TemplateConfiguration.Items.SingleOrDefault(Function(i) i.Id = oTemplateItemId)
If oTemplateItem Is Nothing Then
Logger.Warn("Function configuration could not be assigned to an existing template item, item id was [{0}]", oTemplateItemId)
Continue For
End If
oTemplateItem.Functions.Add(New FieldConfig.ColumnFunction With {
.Id = oRow.ItemEx("FUNCTION_ID", 0),
.Name = oRow.ItemEx("FUNCTION_NAME", String.Empty),
.Params = oRow.ItemEx("FUNCTION_PARAMETERS", String.Empty)
})
Next
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Function UpdateTemplateFromFile(pTemplate As Template, pInputDirectory As String) As Template
Dim oFullPath = Path.Combine(pInputDirectory, pTemplate.FileName)

View File

@ -375,34 +375,33 @@ Namespace Winline
For Each oTable In pTemplate.Tables
Logger.Debug("Processing Table [{0}]", oTable.Name)
For Each oItem As Template.Column In oTable.Columns
For Each oColumn As Template.Column In oTable.Columns
Dim oTableName As String = oTable.Name
Dim oItemName As String = oItem.Name
Dim oItemName As String = oColumn.Name
Logger.Debug("Processing item [{0}]", oItemName)
If oItem.Config.Function Is Nothing Then
Continue For
End If
For Each oFunction As FieldConfig.ColumnFunction In oColumn.Config.Functions
Dim oFunction = oItem.Config.Function.Name
Dim oFunctionName = oFunction.Name
Dim oFunctionParams = oFunction.Params
Dim oPath = $"//MESOWebService/{oTableName}/{oItemName}"
Dim oNodes As XmlNodeList = oXMLDocument.SelectNodes(oPath)
Logger.Debug("Calling function [{0}] on node [{1}]", oFunction, oPath)
Logger.Debug("Calling function [{0}] on node [{1}]", oFunctionName, oPath)
For Each oNode As XmlNode In oNodes
If oItem.Config.Function.Name = "GLN" Then
If oFunctionName = Constants.FUNCTION_GLN Then
Dim oGLN = Winline.TryGetGLN(oNode.InnerText, pMandator)
If oGLN Is Nothing Then
Throw New MissingAttributeException("GLN")
Throw New MissingAttributeException(Constants.FUNCTION_GLN)
End If
oNode.InnerText = oGLN
ElseIf oItem.Config.Function.Name = "EAN" Then
ElseIf oFunctionName = Constants.FUNCTION_EAN Then
Dim oEAN = Winline.TryGetEAN(oNode.InnerText, pMandator)
If oEAN Is Nothing Then
@ -416,12 +415,12 @@ Namespace Winline
oNode.InnerText = oEAN
ElseIf oItem.Config.Function.Name = "SQL" Then
Dim oSQL = Patterns.ReplaceForExport(pDocument, pMandator, oItem.Config.Function.Params)
ElseIf oFunctionName = Constants.FUNCTION_SQL Then
Dim oSQL = Patterns.ReplaceForExport(pDocument, pMandator, oFunctionParams)
Dim oValue = Database.GetScalarValue(oSQL)
If oValue Is Nothing Then
Throw New MissingAttributeException("SQL")
Throw New MissingAttributeException(Constants.FUNCTION_SQL)
End If
oNode.InnerText = oValue
@ -429,6 +428,9 @@ Namespace Winline
End If
Next
Next
Next
Next
Return oXMLDocument

View File

@ -110,6 +110,7 @@ Public Class frmMain
TemplateLoader = New TemplateLoader(LogConfig, Database)
Await TemplateLoader.LoadTemplates()
Await TemplateLoader.LoadTemplateConfiguration()
Await TemplateLoader.LoadTemplateFunctions()
Await TemplateLoader.LoadGeneralConfiguration()
Await TemplateLoader.LoadMappingConfiguration()
Await TemplateLoader.LoadMandatorConfiguration()

View File

@ -272,11 +272,11 @@ Public Class frmRowEditor
Exit Sub
End If
If oColumn.Config?.Function?.Name = FUNCTION_GLN Then
If oColumn.Config?.Functions.Any(Function(f) f.Name = FUNCTION_GLN) Then
e.RepositoryItem = AccountPicker
End If
If oColumn.Config?.Function?.Name = FUNCTION_EAN Then
If oColumn.Config?.Functions.Any(Function(f) f.Name = FUNCTION_EAN) Then
e.RepositoryItem = ArticlePicker
End If