diff --git a/MultiTool.Common/Constants.vb b/MultiTool.Common/Constants.vb index 322950c..f533c84 100644 --- a/MultiTool.Common/Constants.vb +++ b/MultiTool.Common/Constants.vb @@ -8,6 +8,7 @@ Public Const FUNCTION_PRICE = "PRICE" Public Const FUNCTION_SQL = "SQL" Public Const FUNCTION_FIELD = "FIELD" + Public Const FUNCTION_RUNNINGNUMBER = "RUNNINGNUMBER" Public Const TEMPLATE_TYPE_DATE = "xs:date" Public Const TEMPLATE_TYPE_INTEGER = "xs:integer" @@ -56,17 +57,38 @@ [Decimal] End Enum - Public Enum FieldError + Public Enum FieldErrorType None MissingValue AccountNotFound ArticleNotFound End Enum - Public Enum DocumentError + Public Class FieldError + Public Type As FieldErrorType + Public Message As String + + Public Overrides Function ToString() As String + Return $"{Message} ({Type})" + End Function + End Class + + + Public Enum DocumentErrorType MandatorNotFound + MissingXmlAttribute + AttributeValidationFailed End Enum + Public Class DocumentError + Public Type As DocumentErrorType + Public Message As String + + Public Overrides Function ToString() As String + Return $"{Message} ({Type})" + End Function + End Class + Public Enum XmlFunction None = 0 GLN = 1 diff --git a/MultiTool.Common/Documents/Document.vb b/MultiTool.Common/Documents/Document.vb index 5a86fae..11af63e 100644 --- a/MultiTool.Common/Documents/Document.vb +++ b/MultiTool.Common/Documents/Document.vb @@ -26,6 +26,8 @@ Namespace Documents ''' Public Property Selected As Boolean = False + Private DocumentErrors As New List(Of DocumentError) + Public ReadOnly Property HasErrors As Boolean Get Return Errors.Count > 0 @@ -34,8 +36,11 @@ Namespace Documents Public ReadOnly Property Errors As List(Of String) Get - Dim oRowErrors = Rows.SelectMany(Function(row) row.Errors).ToList() - Dim oDocumentErrors As List(Of String) = GetDocumentErrors(). + Dim oRowErrors = Rows. + SelectMany(Function(row) row.Errors, Function(row, err) err.ToString). + ToList() + + Dim oDocumentErrors As List(Of String) = DocumentErrors. Select(Function(err) err.ToString()). ToList() Return oDocumentErrors. @@ -44,6 +49,13 @@ Namespace Documents End Get End Property + Public Sub AddDocumentError(pDocumentError As DocumentErrorType, pMessage As String) + DocumentErrors.Add(New DocumentError With { + .Type = pDocumentError, + .Message = pMessage + }) + End Sub + Public ReadOnly Property MandatorId As String Get Return Mandator?.Id @@ -84,19 +96,12 @@ Namespace Documents End Function Public Overrides Function Equals(obj As Object) As Boolean - Return FullName = DirectCast(obj, Document).FullName - End Function - - Private Function GetDocumentErrors() As List(Of DocumentError) - Dim oErrors As New List(Of DocumentError) - - If Mandator Is Nothing Then - oErrors.Add(DocumentError.MandatorNotFound) + If obj Is Nothing Then + Return False End If - Return oErrors + Return FullName = DirectCast(obj, Document).FullName End Function - End Class End Namespace \ No newline at end of file diff --git a/MultiTool.Common/Documents/DocumentLoader.vb b/MultiTool.Common/Documents/DocumentLoader.vb index 1643a79..b826524 100644 --- a/MultiTool.Common/Documents/DocumentLoader.vb +++ b/MultiTool.Common/Documents/DocumentLoader.vb @@ -65,22 +65,13 @@ Namespace Documents Logger.Debug("Found [{0}] files in directory [{1}]", oFiles.Count, oDirectory) For Each oFile In oFiles - Try - Dim oDocument = Await LoadFile(oFile, pTemplate, pMandator) - Files.Add(oDocument) - FilesLoaded = Files.Count + Logger.Info("Loading file [{0}]", oFile.Name) + Dim oDocument = Await LoadFile(oFile, pTemplate, pMandator) + Files.Add(oDocument) + FilesLoaded = Files.Count - Dim oInfo As New FileLoadInfo(FilesTotal, FilesLoaded) - RaiseEvent FileLoadComplete(Me, oInfo) - - Catch ex As MissingAttributeException - Logger.Error(ex) - Throw New DocumentLoaderException($"Missing Attribute '{ex.Message}' in File '{oFile.Name}'") - - Catch ex As Exception - Logger.Error(ex) - Throw ex - End Try + Dim oInfo As New FileLoadInfo(FilesTotal, FilesLoaded) + RaiseEvent FileLoadComplete(Me, oInfo) Next Return True @@ -93,20 +84,52 @@ Namespace Documents End Function Public Async Function LoadFile(pFileInfo As FileInfo, pTemplate As Template, pMandator As Mandator) As Task(Of Document) - Dim oFileList As New List(Of FileInfo) From {pFileInfo} - Logger.Info("Loading file [{0}]", pFileInfo.Name) + Logger.Debug("Creating new Document object for file [{0}]", pFileInfo.Name) + Dim oDocument As Document = New Document With { + .File = pFileInfo, + .Schema = pTemplate + } Try - Return Await oFileList. - Select(AddressOf WrapFileInfo). - Select(Function(d) IncludeSchema(d, pTemplate)). - Select(Function(d) LoadDocumentData(d, pTemplate, TemplateConfig)). - Select(Async Function(d) Await MatchDataFromWinLine(d, Winline.Mandators, pMandator, pTemplate)). - SingleOrDefault() + oDocument = LoadDocumentData(oDocument, pTemplate, TemplateConfig) + Catch ex As Exception - Logger.Error(ex) Throw ex + Logger.Error(ex) + End Try + + Try + oDocument = Await MatchDataFromWinLine(oDocument, Winline.Mandators, pMandator, pTemplate) + + Catch ex As Exception + Throw ex + Logger.Error(ex) + + End Try + + Try + oDocument = MarkRequiredFields(oDocument) + + Catch ex As Exception + Throw ex + Logger.Error(ex) + + End Try + + Return oDocument + End Function + + Public Function MarkRequiredFields(pDocument As Document) As Document + For Each oRow In pDocument.Rows + For Each oField In oRow.Fields + If oField.Value.Final = String.Empty And oField.Value.IsRequired Then + oField.Value.AddFieldError(FieldErrorType.MissingValue, $"Attribut '{oField.Key}' ist ein Pflichtfeld, wurde aber nicht gefüllt.") + End If + Next + Next + + Return pDocument End Function Public Sub ReplaceDocument(pDocument As Document) @@ -154,27 +177,27 @@ Namespace Documents Dim oRootElement As XElement = XmlData.GetElement(oDoc, "MESOWebService") If oRootElement Is Nothing Then - Throw New MalformedXmlException("Datei enthält kein MESOWebService-Element") + pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein MESOWebService-Attribut") End If Dim oTemplateName = XmlData.GetElementAttribute(oRootElement, "Template") If oTemplateName Is Nothing Then - Throw New MalformedXmlException("Datei enthält kein Template-Attribut") + pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein Template-Attribut") End If Dim oTemplateType = XmlData.GetElementAttribute(oRootElement, "TemplateType") If oTemplateType Is Nothing Then - Throw New MalformedXmlException("Datei enthält kein TemplateType-Attribut") + pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein TemplateType-Attribut") End If Dim oOption = XmlData.GetElementAttribute(oRootElement, "option") If oOption Is Nothing Then - Throw New MalformedXmlException("Datei enthält kein option-Attribut") + pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein option-Attribut") End If Dim oPrintVoucher = XmlData.GetElementAttribute(oRootElement, "printVoucher") If oPrintVoucher Is Nothing Then - Throw New MalformedXmlException("Datei enthält kein printVoucher-Attribut") + pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein printVoucher-Attribut") End If ' The first level of Elements are the document Rows @@ -227,16 +250,18 @@ Namespace Documents Else Logger.Debug("Creating new field from Configuration: [{0}]", oColumn.Name) - Dim oColumnError = FieldError.None - If oColumn.Config?.IsRequired Then - oColumnError = FieldError.MissingValue - End If - - oFields.Add(oColumn.Name, New DocumentRow.FieldValue With { - .[Error] = oColumnError, + Dim oValue = New DocumentRow.FieldValue With { .SortKey = oColumnSortKey, .IsVirtual = oColumn.Config.IsVirtual - }) + } + + 'oValue.Error = FieldErrorType.None + If oColumn.Config?.IsRequired Then + 'oValue.Error = FieldErrorType.MissingValue + oValue.AddFieldError(FieldErrorType.MissingValue, $"Attribut {oSubElement.Name} wird benötigt, ist aber nicht gefüllt.") + End If + + oFields.Add(oColumn.Name, oValue) End If oColumnSortKey += 1 @@ -282,6 +307,9 @@ Namespace Documents If oMandator Is Nothing Then Logger.Warn("Mandator not found for File [{0}]", pDocument.File.Name) + + ' Without mandator, we just exit, life is meaningless. + pDocument.AddDocumentError(DocumentErrorType.MandatorNotFound, "Mandant nicht gefunden. Verarbeitung wurde abgebrochen.") Else ' Set mandator befor applying any functions that depend on a valid mandator pDocument.Mandator = oMandator @@ -290,7 +318,7 @@ Namespace Documents .RunningFunction = "Winline-Funktionen" }) - pDocument = ApplyDefinedItemFunctionsForImport(pDocument, oMandator, pTemplate) + pDocument = Await ApplyDefinedItemFunctionsForImportAsync(pDocument, oMandator, pTemplate) pDocument = ApplyDynamicItemFunctionsForImport(pDocument, oMandator) RaiseEvent FileLoadProgress(Me, New FileLoadProgressInfo(FilesTotal, FilesLoaded) With { @@ -355,7 +383,7 @@ Namespace Documents Return pDocument End Function - Private Function ApplyDefinedItemFunctionsForImport(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Document + Private Async Function ApplyDefinedItemFunctionsForImportAsync(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task(Of Document) For Each oRow As DocumentRow In pDocument.Rows Dim oTable = pTemplate.Tables.Where(Function(table) table.Name = oRow.TableName).SingleOrDefault() @@ -373,14 +401,17 @@ Namespace Documents Dim oFunctionParams = oColumn.Config.FunctionParams Dim oParamsDict = ParseFunctionParamsAsDict(oFunctionParams) - If oFunctionName = Constants.FUNCTION_GLN Then + If oFunctionName = FUNCTION_GLN Then SetAccountByGLN(oRow, pMandator, oField.Key, Nothing, oParamsDict) End If - If oFunctionName = Constants.FUNCTION_EAN Then + If oFunctionName = FUNCTION_EAN Then SetArticleByEAN(oRow, pMandator, oField.Key) End If + If oFunctionName = FUNCTION_RUNNINGNUMBER Then + Await SetVersionedRunningNumber(pDocument, oRow, pMandator, oField.Key, oParamsDict) + End If Next Next @@ -481,9 +512,7 @@ Namespace Documents pDocument.Rows. SelectMany(Function(row) row.Fields). Where(Function(field) field.Key = oMapping.DestinationItem). - SetValue(Sub(field) - field.Value.Final = oMapping.DestinationValue - End Sub) + SetValue(Sub(field) field.Value.Final = oMapping.DestinationValue) Else ' don't do anything @@ -494,12 +523,12 @@ Namespace Documents Return pDocument End Function - Private Async Function SetPrice(pRow As DocumentRow, pPriceField As String, oFieldMap As Dictionary(Of String, String), pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task + Private Async Function SetPrice(pRow As DocumentRow, pPriceField As String, pParamMap As Dictionary(Of String, String), pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task Dim oPriceItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pPriceField) ' These fields are fetched from the current row Const PARAMETER_ARTICLE = "Article" - Dim oArticleNumberField As String = oFieldMap.GetOrDefault(PARAMETER_ARTICLE, Nothing) + Dim oArticleNumberField As String = pParamMap.GetOrDefault(PARAMETER_ARTICLE, Nothing) If oArticleNumberField Is Nothing Then Logger.Warn("Parameter '{0}' not found for Function PRICE", PARAMETER_ARTICLE) End If @@ -510,7 +539,7 @@ Namespace Documents Dim oArticleNumber As String = pRow.Fields.Item(oArticleNumberField).Final Const PARAMETER_QUANTITY = "Quantity" - Dim oQuantityField As String = oFieldMap.GetOrDefault(PARAMETER_QUANTITY, Nothing) + Dim oQuantityField As String = pParamMap.GetOrDefault(PARAMETER_QUANTITY, Nothing) If oQuantityField Is Nothing Then Logger.Warn("Parameter '{0}' not found for Function PRICE", PARAMETER_QUANTITY) End If @@ -521,13 +550,13 @@ Namespace Documents End If ' These fields a fetched from the head row, ie. the first row - Dim oAccountNumberField As String = oFieldMap.GetOrDefault("Account", Nothing) + Dim oAccountNumberField As String = pParamMap.GetOrDefault("Account", Nothing) Dim oAccountNumber = pDocument.GetFieldValue(oAccountNumberField) - Dim oDocumentDateField As String = oFieldMap.GetOrDefault("DocumentDate", Nothing) + Dim oDocumentDateField As String = pParamMap.GetOrDefault("DocumentDate", Nothing) Dim oDocumentDate = pDocument.GetFieldValue(oDocumentDateField) - Dim oDocumentKindField As String = oFieldMap.GetOrDefault("DocumentKind", Nothing) + Dim oDocumentKindField As String = pParamMap.GetOrDefault("DocumentKind", Nothing) Dim oDocumentKind As Integer = 0 If Integer.TryParse(pDocument.GetFieldValue(oDocumentKindField), oDocumentKind) = False Then Logger.Warn("Value for parameter DocumentKind could not be parsed. Setting to 0.") @@ -538,10 +567,10 @@ Namespace Documents ' TODO: This function should not be hardcoded, but be replaced with virtual field or something.. ' It is related to customer SCHAUM and nothing general - Dim oWaitingDays As Integer = Await Winline.TryGetWaitingDays(oDocumentKind, pMandator) + Dim oWaitingDays As Integer = Await Winline.TryGetWaitingDaysAsync(oDocumentKind, pMandator) ' END TODO - Dim oArticlePrice As Double = Await Winline.TryGetArticlePrice(oArticleNumber, oAccountNumber, oQuantity, oDocumentDate, pMandator, pTemplate, oWaitingDays) + Dim oArticlePrice As Double = Await Winline.TryGetArticlePriceAsync(oArticleNumber, oAccountNumber, oQuantity, oDocumentDate, pMandator, pTemplate, oWaitingDays) If oArticlePrice > 0 Then oPriceItem.External = oArticlePrice @@ -559,7 +588,8 @@ Namespace Documents oNumberItem.External = oArticleNumber oNumberItem.Final = oArticleNumber Else - oNumberItem.Error = FieldError.ArticleNotFound + 'oNumberItem.Error = FieldErrorType.ArticleNotFound + oNumberItem.AddFieldError(FieldErrorType.ArticleNotFound, $"EAN in Attribut '{pArticleField}' konnte nicht aufgelöst werden.") End If End Sub @@ -597,7 +627,8 @@ Namespace Documents ' If no account was found and the field is required, ' mark it as error. Otherwise, do nothing. If oNumberItem.IsRequired Then - oNumberItem.Error = FieldError.AccountNotFound + 'oNumberItem.Error = FieldErrorType.AccountNotFound + oNumberItem.AddFieldError(FieldErrorType.AccountNotFound, $"GLN in Attribut '{pNumberField}' konnte nicht aufgelöst werden.") End If End If Catch ex As Exception @@ -606,9 +637,31 @@ Namespace Documents End Try End Sub - Private Function WrapFileInfo(pFileInfo As FileInfo) As Document - Logger.Debug("Creating new Document object for file [{0}]", pFileInfo.Name) - Return New Document With {.File = pFileInfo} + Public Async Function SetVersionedRunningNumber(pDocument As Document, pRow As DocumentRow, pMandator As Mandator, pRunningNumberField As String, pParams As Dictionary(Of String, String)) As Task + Try + Const PARAMETER_ACCOUNT = "Account" + Dim oAccountField As String = pParams.GetOrDefault(PARAMETER_ACCOUNT, Nothing) + If oAccountField Is Nothing Then + Logger.Warn("Parameter '{0}' not found for Function RUNNINGNUMBER", PARAMETER_ACCOUNT) + End If + + Dim oRunningNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pRunningNumberField) + Dim oRunningNumber = oRunningNumberItem.Final + + Dim oAccountNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oAccountField) + Dim oAccountNumber = oAccountNumberItem.Final + + Dim oVersionedNumber = Await Winline.GetVersionedRunningNumberAsync(pDocument, pMandator, oAccountNumber, oRunningNumber) + + If oVersionedNumber <> oRunningNumber Then + oRunningNumberItem.External = oVersionedNumber + oRunningNumberItem.Final = oVersionedNumber + End If + + Catch ex As Exception + Logger.Error(ex) + Throw ex + End Try End Function Private Function ParseFunctionParamsAsDict(pParams As String) As Dictionary(Of String, String) diff --git a/MultiTool.Common/Documents/DocumentRow.vb b/MultiTool.Common/Documents/DocumentRow.vb index 15e6e6e..1f334fe 100644 --- a/MultiTool.Common/Documents/DocumentRow.vb +++ b/MultiTool.Common/Documents/DocumentRow.vb @@ -35,11 +35,11 @@ Namespace Documents End Get End Property - Public ReadOnly Property Errors As List(Of String) + Public ReadOnly Property Errors As List(Of FieldError) Get Return Fields. Where(Function(f) f.Value.HasError). - Select(Function(f) $"{f.Key} has Error: {f.Value.Error}").ToList() + SelectMany(Function(f) f.Value.Errors).ToList() End Get End Property @@ -57,11 +57,8 @@ Namespace Documents Private _Original As String = "" Public Property DataType As ColumnType = ColumnType.String - Public Property [Error] As FieldError = FieldError.None - Public Sub New() - - End Sub + Public Property Errors As New List(Of FieldError) Public Property Original As String Get @@ -107,9 +104,17 @@ Namespace Documents End Select End Function + Public Sub AddFieldError(pType As FieldErrorType, pMessage As String) + Errors.Add(New FieldError() With { + .Type = pType, + .Message = pMessage + }) + End Sub + Public ReadOnly Property HasError As Boolean Get - Return [Error] <> FieldError.None Or (IsRequired And Final = String.Empty) + ' Required check was moved to DocumentLoader + Return Errors.Count > 0 'Or (IsRequired And Final = String.Empty) End Get End Property diff --git a/MultiTool.Common/Exceptions.vb b/MultiTool.Common/Exceptions.vb index cc5dd75..784fedc 100644 --- a/MultiTool.Common/Exceptions.vb +++ b/MultiTool.Common/Exceptions.vb @@ -57,18 +57,12 @@ MyBase.New(message) End Sub End Class - Public Class NoMandatorException + + Public Class LengthExceededException Inherits MultiToolException - Public Sub New(message As String) - MyBase.New(message) - End Sub - End Class - Public Class MalformedXmlException - Inherits MultiToolException - - Public Sub New(message As String) - MyBase.New(message) + Public Sub New(attribute As String) + MyBase.New(attribute) End Sub End Class diff --git a/MultiTool.Common/Winline/WinlineData.vb b/MultiTool.Common/Winline/WinlineData.vb index 79108df..8086969 100644 --- a/MultiTool.Common/Winline/WinlineData.vb +++ b/MultiTool.Common/Winline/WinlineData.vb @@ -1,10 +1,13 @@ -Imports DigitalData.Modules.Logging +Imports System.Text.RegularExpressions +Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Database -Imports MultiTool.Common.Winline.Entities -Imports System.Text.RegularExpressions -Imports MultiTool.Common.Templates -Imports MultiTool.Common.Constants Imports DigitalData.Modules.Language +Imports DigitalData.Modules.Filesystem +Imports MultiTool.Common.Winline.Entities +Imports MultiTool.Common.Constants +Imports MultiTool.Common.Templates +Imports MultiTool.Common.Exceptions +Imports MultiTool.Common.Documents Namespace Winline Public Class WinlineData @@ -14,6 +17,7 @@ Namespace Winline Private ReadOnly Property MandatorConfig As MandatorConfig Private ReadOnly Property MappingConfig As MappingConfig Private ReadOnly Property Patterns As Patterns + Private ReadOnly Property FileEx As File Public Property Articles As New List(Of Article) Public Property Accounts As New List(Of Account) @@ -29,6 +33,8 @@ Namespace Winline Config = pConfig MandatorConfig = pMandatorConfig MappingConfig = pMappingConfig + FileEx = New File(pLogConfig) + Years = LoadEconomicYears() End Sub ''' @@ -65,8 +71,14 @@ Namespace Winline Public Property Year As Integer End Class + Private Function LoadEconomicYears() As IEnumerable(Of Integer) + Dim oCurrentYear = Now.Year + Dim oRange As IEnumerable(Of Integer) = Enumerable.Range(oCurrentYear - 10, 12).ToList() + Return oRange + End Function - Public Async Function LoadArticles(pMandator As Mandator) As Task + + Public Async Function LoadArticlesAsync(pMandator As Mandator) As Task Logger.Info("Loading Articles for Mandator [{0}]", pMandator) Dim oYear = Config.GetWinLineYear() @@ -104,7 +116,7 @@ Namespace Winline End Try End Function - Public Async Function LoadPackingUnits(pMandator As Mandator) As Task + Public Async Function LoadPackingUnitsAsync(pMandator As Mandator) As Task Logger.Info("Loading Packing Units for Mandator [{0}]", pMandator) Dim oYear = Config.GetWinLineYear() @@ -155,7 +167,7 @@ Namespace Winline End Try End Function - Public Async Function LoadAccounts(pMandator As Mandator) As Task + Public Async Function LoadAccountsAsync(pMandator As Mandator) As Task Logger.Info("Loading Accounts for Mandator [{0}]", pMandator) Dim oYear = Config.GetWinLineYear() @@ -207,7 +219,7 @@ Namespace Winline End Try End Function - Public Async Function LoadMandators() As Task + Public Async Function LoadMandatorsAsync() As Task Try Dim oSQL = "SELECT [c000], [c003], [c004] FROM [cwlsystem].[dbo].[T001SRV] (NOLOCK)" Dim oTable = Await Database.GetDatatableAsync(oSQL) @@ -241,13 +253,9 @@ Namespace Winline End Try End Function - Public Sub LoadEconomicYears() - Dim oCurrentYear = Now.Year - Dim oRange As IEnumerable(Of Integer) = Enumerable.Range(oCurrentYear - 10, 12).ToList() - Years = oRange - End Sub - Public Async Function LoadDocumentKinds(pMandator As Mandator) As Task + + Public Async Function LoadDocumentKindsAsync(pMandator As Mandator) As Task Dim oYear As Integer = Config.GetWinLineYear() Try @@ -388,11 +396,11 @@ Namespace Winline End Try End Function - Public Async Function TryGetArticlePrice(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template) As Task(Of Double) - Return Await TryGetArticlePrice(pArticle, pAccountNumber, pQuantity, pDocumentDate, pMandator, pTemplate, 0) + Public Async Function TryGetArticlePriceAsync(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template) As Task(Of Double) + Return Await TryGetArticlePriceAsync(pArticle, pAccountNumber, pQuantity, pDocumentDate, pMandator, pTemplate, 0) End Function - Public Async Function TryGetArticlePrice(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template, pWaitingDays As Integer) As Task(Of Double) + Public Async Function TryGetArticlePriceAsync(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template, pWaitingDays As Integer) As Task(Of Double) Try Dim oUserName = Environment.UserName Dim oYear As Integer = Config.GetWinLineYear() @@ -475,7 +483,7 @@ Namespace Winline ''' ''' This function is completely SCHAUM related. ''' - Public Async Function TryGetWaitingDays(pDocumentKind As Integer, pMandator As Mandator) As Task(Of Integer) + Public Async Function TryGetWaitingDaysAsync(pDocumentKind As Integer, pMandator As Mandator) As Task(Of Integer) Try Dim oSql = $" SELECT [Karenztage].[u012] FROM [{pMandator.Database}].[dbo].[t670] As [Werksdefinition] @@ -894,6 +902,69 @@ Namespace Winline End Try End Function + Private ReadOnly RunningNumberVersionRegex As Regex = New Regex("~\d{1,3}$") + Private ReadOnly RunningNumberMaximumLength As Integer = 20 + + Public Async Function GetVersionedRunningNumberAsync(pDocument As Document, pMandator As Mandator, pAccountNumber As String, pRunningNumber As String) As Task(Of String) + Try + Dim oYear As Integer = Config.GetWinLineYear() + Dim oSql As String = $" + SELECT COUNT(*) FROM [{pMandator.Database}].[dbo].[v250] + WHERE + [c021] = '{pAccountNumber}' AND -- Account ' + [c022] = '{pRunningNumber}' AND -- Running Number ' + --[c035] = '4711' -- Belegart, needed? + [c144] IS NULL AND -- Stornonummer Angebot + [c145] IS NULL AND -- Stornonummer Auftrag + [c146] IS NULL AND -- Stornonummer Lieferschein + [c147] IS NULL AND -- Stornonummer Faktura + [mesocomp] = '{pMandator.Id}' --AND [mesoyear] = {oYear} + " + + Dim oExistingCount = Await Database.GetScalarValueAsync(oSql) + + If oExistingCount = 0 Then + Logger.Debug("Running number [{0}] does not exist yet. Returning.") + Return pRunningNumber + Else + Logger.Debug("Running number [{0}] already exists. Checking again.") + Dim oVersionResult = FileEx.GetVersionedString(pRunningNumber, "~"c) + + Dim oFinalLength As Integer = oVersionResult.Item1.Count + oVersionResult.Item2.ToString.Count + 1 + + If oFinalLength > RunningNumberMaximumLength Then + Logger.Warn("Running number is too long ({0} chars total) and cannot be versioned. Versioning needs at least 2 characters.", oFinalLength) + pDocument.AddDocumentError(DocumentErrorType.AttributeValidationFailed, "Das Feld Laufnummer hat die zulässige Länge überschritten.") + Return pRunningNumber + End If + + Return Await GetVersionedRunningNumberAsync(pDocument, pMandator, pAccountNumber, $"{oVersionResult.Item1}~{oVersionResult.Item2}") + End If + + Catch ex As MultiToolException + Logger.Error(ex) + Throw ex + + Catch ex As Exception + Logger.Warn("Error while getting versioned running number for mandator [{0}] and running number [{1}]", pMandator, pRunningNumber) + Logger.Error(ex) + Return Nothing + End Try + End Function + + Public Function VersionNumber(pNumber As String) As String + Dim oRunningNumberBase As String + + If RunningNumberVersionRegex.IsMatch(pNumber) Then + Dim oSplitNumber = pNumber.Split("~") + oRunningNumberBase = oSplitNumber.First() + Dim oRunningNumberVersion As Integer = Integer.Parse(oSplitNumber.Last()) + Return $"{oRunningNumberBase}~{oRunningNumberVersion + 1}" + Else + Return $"{pNumber}~2" + End If + End Function + Public Async Function ExecuteFinalSQL(pDocument As ExportDocument, pTemplate As Template, pMandator As Mandator) As Task(Of Boolean) Try Dim oSql As String = Patterns.ReplaceForExport(pDocument, pMandator, pTemplate.FinalSQL) diff --git a/MultiTool.Form/ApplicationEvents.vb b/MultiTool.Form/ApplicationEvents.vb new file mode 100644 index 0000000..13dfb37 --- /dev/null +++ b/MultiTool.Form/ApplicationEvents.vb @@ -0,0 +1,15 @@ +Imports Microsoft.VisualBasic.ApplicationServices + +Namespace My + ' Für MyApplication sind folgende Ereignisse verfügbar: + ' Startup: Wird beim Starten der Anwendung noch vor dem Erstellen des Startformulars ausgelöst. + ' Shutdown: Wird nach dem Schließen aller Anwendungsformulare ausgelöst. Dieses Ereignis wird nicht ausgelöst, wenn die Anwendung mit einem Fehler beendet wird. + ' UnhandledException: Wird bei einem Ausnahmefehler ausgelöst. + ' StartupNextInstance: Wird beim Starten einer Einzelinstanzanwendung ausgelöst, wenn die Anwendung bereits aktiv ist. + ' NetworkAvailabilityChanged: Wird beim Herstellen oder Trennen der Netzwerkverbindung ausgelöst. + Partial Friend Class MyApplication + Protected Overrides Function OnUnhandledException(e As UnhandledExceptionEventArgs) As Boolean + Return MyBase.OnUnhandledException(e) + End Function + End Class +End Namespace diff --git a/MultiTool.Form/MultiTool.Form.vbproj b/MultiTool.Form/MultiTool.Form.vbproj index 690dccc..0744a6a 100644 --- a/MultiTool.Form/MultiTool.Form.vbproj +++ b/MultiTool.Form/MultiTool.Form.vbproj @@ -158,6 +158,7 @@ + True True @@ -338,6 +339,7 @@ + diff --git a/MultiTool.Form/My Project/Resources.Designer.vb b/MultiTool.Form/My Project/Resources.Designer.vb index d2268c6..64be315 100644 --- a/MultiTool.Form/My Project/Resources.Designer.vb +++ b/MultiTool.Form/My Project/Resources.Designer.vb @@ -370,6 +370,16 @@ Namespace My.Resources End Get End Property + ''' + ''' Sucht eine lokalisierte Ressource vom Typ DevExpress.Utils.Svg.SvgImage. + ''' + Friend ReadOnly Property highimportance1() As DevExpress.Utils.Svg.SvgImage + Get + Dim obj As Object = ResourceManager.GetObject("highimportance1", resourceCulture) + Return CType(obj,DevExpress.Utils.Svg.SvgImage) + End Get + End Property + ''' ''' Sucht eine lokalisierte Ressource vom Typ DevExpress.Utils.Svg.SvgImage. ''' diff --git a/MultiTool.Form/My Project/Resources.resx b/MultiTool.Form/My Project/Resources.resx index c6d7b3f..03f04be 100644 --- a/MultiTool.Form/My Project/Resources.resx +++ b/MultiTool.Form/My Project/Resources.resx @@ -187,9 +187,6 @@ ..\Resources\actions_arrow4down.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\open1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - ..\Resources\bo_unknown1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -199,6 +196,9 @@ ..\Resources\open3.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\bo_sale.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + ..\Resources\actions_checkcircled.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -220,9 +220,6 @@ ..\Resources\actions_send1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\actions_send4.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - ..\Resources\actions_send2.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -238,9 +235,6 @@ ..\Resources\open23.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\insertpagecount.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - ..\Resources\actions_reload1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -274,6 +268,9 @@ ..\Resources\paymentrefund.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\squarified.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + ..\Resources\support.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -289,8 +286,8 @@ ..\Resources\preview.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\bo_sale.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\insertpagecount.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a ..\Resources\exporttopdf.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -310,14 +307,20 @@ ..\Resources\showallfieldcodes.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\actions_delete.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\open1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + + ..\Resources\highimportance.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a ..\Resources\actions_addcircled.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\squarified.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\actions_delete.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + + ..\Resources\actions_send4.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a ..\Resources\logical2.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a @@ -334,7 +337,7 @@ ..\Resources\actions_checkcircled2.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a - - ..\Resources\highimportance.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + ..\Resources\highimportance1.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a \ No newline at end of file diff --git a/MultiTool.Form/Resources/highimportance1.svg b/MultiTool.Form/Resources/highimportance1.svg new file mode 100644 index 0000000..7f7764c --- /dev/null +++ b/MultiTool.Form/Resources/highimportance1.svg @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/MultiTool.Form/frmImportMain.Designer.vb b/MultiTool.Form/frmImportMain.Designer.vb index b625c4e..bcfc974 100644 --- a/MultiTool.Form/frmImportMain.Designer.vb +++ b/MultiTool.Form/frmImportMain.Designer.vb @@ -58,6 +58,7 @@ Partial Class frmImportMain Me.btnCalculatePrices = New DevExpress.XtraBars.BarButtonItem() Me.btnOpenLogDirectory2 = New DevExpress.XtraBars.BarButtonItem() Me.txtErrors = New DevExpress.XtraBars.BarStaticItem() + Me.btnShowErrors = New DevExpress.XtraBars.BarButtonItem() Me.RibbonPage1 = New DevExpress.XtraBars.Ribbon.RibbonPage() Me.RibbonPageGroupLoad = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() Me.RibbonPageGroupReport = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() @@ -223,9 +224,9 @@ Partial Class frmImportMain 'RibbonControl ' Me.RibbonControl.ExpandCollapseItem.Id = 0 - Me.RibbonControl.Items.AddRange(New DevExpress.XtraBars.BarItem() {Me.RibbonControl.ExpandCollapseItem, Me.RibbonControl.SearchEditItem, Me.txtFilesLoaded, Me.btnLoadFiles, Me.btnTransferFile, Me.btnOpenInputDirectory, Me.btnOpenOutputDirectory, Me.btnOpenSchemaDirectory, Me.btnReloadFile, Me.btnTransferAllFiles, Me.btnOpenReport, Me.btnShowXml, Me.btnOpenLogDirectory, Me.btnOpenConfigDirectory, Me.txtCurrentFile, Me.btnConfig, Me.btnRemoveRow, Me.btnTestTransferFile, Me.BarButtonItem1, Me.btnDebugExportReport, Me.btnEditRow, Me.btnCalculatePrices, Me.btnOpenLogDirectory2, Me.txtErrors}) + Me.RibbonControl.Items.AddRange(New DevExpress.XtraBars.BarItem() {Me.RibbonControl.ExpandCollapseItem, Me.RibbonControl.SearchEditItem, Me.txtFilesLoaded, Me.btnLoadFiles, Me.btnTransferFile, Me.btnOpenInputDirectory, Me.btnOpenOutputDirectory, Me.btnOpenSchemaDirectory, Me.btnReloadFile, Me.btnTransferAllFiles, Me.btnOpenReport, Me.btnShowXml, Me.btnOpenLogDirectory, Me.btnOpenConfigDirectory, Me.txtCurrentFile, Me.btnConfig, Me.btnRemoveRow, Me.btnTestTransferFile, Me.BarButtonItem1, Me.btnDebugExportReport, Me.btnEditRow, Me.btnCalculatePrices, Me.btnOpenLogDirectory2, Me.txtErrors, Me.btnShowErrors}) resources.ApplyResources(Me.RibbonControl, "RibbonControl") - Me.RibbonControl.MaxItemId = 39 + Me.RibbonControl.MaxItemId = 40 Me.RibbonControl.Name = "RibbonControl" Me.RibbonControl.Pages.AddRange(New DevExpress.XtraBars.Ribbon.RibbonPage() {Me.RibbonPage1, Me.RibbonPage2}) Me.RibbonControl.RepositoryItems.AddRange(New DevExpress.XtraEditors.Repository.RepositoryItem() {Me.RepositoryItemComboBox1, Me.RepositoryItemProgressBar1}) @@ -400,6 +401,14 @@ Partial Class frmImportMain Me.txtErrors.PaintStyle = DevExpress.XtraBars.BarItemPaintStyle.CaptionGlyph Me.txtErrors.Tag = "Fehler: {0}" ' + 'btnShowErrors + ' + resources.ApplyResources(Me.btnShowErrors, "btnShowErrors") + Me.btnShowErrors.Enabled = False + Me.btnShowErrors.Id = 39 + Me.btnShowErrors.ImageOptions.SvgImage = Global.MultiTool.Form.My.Resources.Resources.highimportance1 + Me.btnShowErrors.Name = "btnShowErrors" + ' 'RibbonPage1 ' Me.RibbonPage1.Groups.AddRange(New DevExpress.XtraBars.Ribbon.RibbonPageGroup() {Me.RibbonPageGroupLoad, Me.RibbonPageGroupReport, Me.RibbonPageGroupTransfer, Me.RibbonPageGroupEdit}) @@ -434,6 +443,7 @@ Partial Class frmImportMain Me.RibbonPageGroupEdit.ItemLinks.Add(Me.btnEditRow) Me.RibbonPageGroupEdit.ItemLinks.Add(Me.btnRemoveRow) Me.RibbonPageGroupEdit.ItemLinks.Add(Me.btnCalculatePrices) + Me.RibbonPageGroupEdit.ItemLinks.Add(Me.btnShowErrors) Me.RibbonPageGroupEdit.Name = "RibbonPageGroupEdit" resources.ApplyResources(Me.RibbonPageGroupEdit, "RibbonPageGroupEdit") ' @@ -760,4 +770,5 @@ Partial Class frmImportMain Friend WithEvents btnCalculatePrices As DevExpress.XtraBars.BarButtonItem Friend WithEvents btnOpenLogDirectory2 As DevExpress.XtraBars.BarButtonItem Friend WithEvents txtErrors As DevExpress.XtraBars.BarStaticItem + Friend WithEvents btnShowErrors As DevExpress.XtraBars.BarButtonItem End Class diff --git a/MultiTool.Form/frmImportMain.resx b/MultiTool.Form/frmImportMain.resx index 92d4451..9c1a8ba 100644 --- a/MultiTool.Form/frmImportMain.resx +++ b/MultiTool.Form/frmImportMain.resx @@ -256,6 +256,9 @@ Fehler: 0 + + Fehler anzeigen + 0, 0 @@ -962,6 +965,12 @@ DevExpress.XtraBars.BarStaticItem, DevExpress.XtraBars.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + + btnShowErrors + + + DevExpress.XtraBars.BarButtonItem, DevExpress.XtraBars.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a + RibbonPage1 diff --git a/MultiTool.Form/frmImportMain.vb b/MultiTool.Form/frmImportMain.vb index 0934b9b..f297430 100644 --- a/MultiTool.Form/frmImportMain.vb +++ b/MultiTool.Form/frmImportMain.vb @@ -457,12 +457,6 @@ Public Class frmImportMain LoadDocument(oNewDocument) End If - Catch ex As NoMandatorException - FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Neuladen_des_Dokuments, My.Resources.frmImportMainExtra.Es_konnte_kein_passender_Mandant_ermittelt_werden) - - Catch ex As MissingAttributeException - FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Neuladen_des_Dokuments, "Ein benötigtes Attribut wurde nicht gefunden.") - Catch ex As Exception FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Neuladen_des_Dokuments) @@ -621,8 +615,10 @@ Public Class frmImportMain If pDocument.HasErrors = True Then btnCalculatePrices.Enabled = False + btnShowErrors.Enabled = True Else btnCalculatePrices.Enabled = True + btnShowErrors.Enabled = False End If If pDocument.Mandator Is Nothing Then @@ -683,8 +679,6 @@ Public Class frmImportMain txtFilesLoaded.Caption = String.Format(My.Resources.frmImportMainExtra._0__Dateien_geladen, DocumentLoader.Files.Count) End If - Catch ex As NoMandatorException - MsgBox(My.Resources.frmImportMainExtra.Es_konnte_kein_passender_Mandant_ermittelt_werden, MsgBoxStyle.Information, Text) Catch ex As Exception FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Laden_der_Dokumente) @@ -876,6 +870,16 @@ Public Class frmImportMain End If End Sub + Private Sub btnShowErrors_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnShowErrors.ItemClick + If CurrentDocument IsNot Nothing Then + Dim oErrors = CurrentDocument.Errors. + Select(Function(s) " - " & s). + ToList() + Dim oMessage = String.Join(vbNewLine, oErrors) + MsgBox($"Datei enthält {oErrors.Count} Fehler:{vbNewLine}{vbNewLine}{oMessage}", MsgBoxStyle.Exclamation, Text) + End If + End Sub + #End Region diff --git a/MultiTool.Form/frmMain.vb b/MultiTool.Form/frmMain.vb index 3c07838..af18aa4 100644 --- a/MultiTool.Form/frmMain.vb +++ b/MultiTool.Form/frmMain.vb @@ -90,18 +90,17 @@ Public Class frmMain Private Async Function LoadWinlineData(Winline As WinlineData) As Task Winline.Mandators.Clear() - Winline.LoadEconomicYears() - Await Winline.LoadMandators() + Await Winline.LoadMandatorsAsync() For Each oMandator As Mandator In Winline.Mandators SplashScreenManager.SetWaitFormDescription(String.Format(My.Resources.frmImportMainExtra.Lade__0__Konten, oMandator.Id)) - Await Winline.LoadAccounts(oMandator) + Await Winline.LoadAccountsAsync(oMandator) SplashScreenManager.SetWaitFormDescription(String.Format(My.Resources.frmImportMainExtra.Lade__0__Artikel, oMandator.Id)) - Await Winline.LoadArticles(oMandator) + Await Winline.LoadArticlesAsync(oMandator) SplashScreenManager.SetWaitFormDescription(String.Format(My.Resources.frmImportMainExtra.Lade__0__Belegarten, oMandator.Id)) - Await Winline.LoadDocumentKinds(oMandator) + Await Winline.LoadDocumentKindsAsync(oMandator) SplashScreenManager.SetWaitFormDescription(String.Format("Lade {0}/Colli", oMandator.Id)) - Await Winline.LoadPackingUnits(oMandator) + Await Winline.LoadPackingUnitsAsync(oMandator) Next My.Winline = Winline diff --git a/MultiTool.Form/frmRowEditor.vb b/MultiTool.Form/frmRowEditor.vb index f670fb0..2ecc5a3 100644 --- a/MultiTool.Form/frmRowEditor.vb +++ b/MultiTool.Form/frmRowEditor.vb @@ -184,7 +184,8 @@ Public Class frmRowEditor 'End If ' 03.12.21: For now we always remove the error if ANYTHING changed about the field - oFieldValue.Error = FieldError.None + 'oFieldValue.Error = FieldErrorType.None + oFieldValue.Errors.Clear() ' Save the grid value to the Field oFieldValue.Final = oValueFromGrid.Trim() diff --git a/MultiTool.Test/MultiTool.Test.csproj b/MultiTool.Test/MultiTool.Test.csproj new file mode 100644 index 0000000..d918759 --- /dev/null +++ b/MultiTool.Test/MultiTool.Test.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + diff --git a/MultiTool.Test/WinlineDataTest.cs b/MultiTool.Test/WinlineDataTest.cs new file mode 100644 index 0000000..d70fab2 --- /dev/null +++ b/MultiTool.Test/WinlineDataTest.cs @@ -0,0 +1,13 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MultiTool.Test +{ + [TestClass] + public class WinlineDataTest + { + [TestMethod] + public void Test_VersionNumber() + { + } + } +} diff --git a/MultiTool.sln b/MultiTool.sln index 803601c..13dff8e 100644 --- a/MultiTool.sln +++ b/MultiTool.sln @@ -9,6 +9,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "MultiTool.Common", "MultiTo EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Multitool.Form.Setup", "Multitool.Form.Setup\Multitool.Form.Setup.wixproj", "{A03D1911-C6D6-4AD0-9601-4D277B35E91D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiTool.Test", "MultiTool.Test\MultiTool.Test.csproj", "{2FCD4E08-F750-49D5-854D-719A55074D30}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,14 @@ Global {A03D1911-C6D6-4AD0-9601-4D277B35E91D}.Release|Any CPU.ActiveCfg = Release|x86 {A03D1911-C6D6-4AD0-9601-4D277B35E91D}.Release|x86.ActiveCfg = Release|x86 {A03D1911-C6D6-4AD0-9601-4D277B35E91D}.Release|x86.Build.0 = Release|x86 + {2FCD4E08-F750-49D5-854D-719A55074D30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Debug|x86.ActiveCfg = Debug|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Debug|x86.Build.0 = Debug|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Release|Any CPU.Build.0 = Release|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Release|x86.ActiveCfg = Release|Any CPU + {2FCD4E08-F750-49D5-854D-719A55074D30}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE