diff --git a/GUIs.Common/GridBuilder.vb b/GUIs.Common/GridBuilder.vb
index 3ab51893..9a0226f6 100644
--- a/GUIs.Common/GridBuilder.vb
+++ b/GUIs.Common/GridBuilder.vb
@@ -82,7 +82,7 @@ Public Class GridBuilder
ToList()
For Each oDateCol In oDateColumns
- SetDateTimeColumn(oDateCol)
+ SetDateTimeColumn(oDateCol, "g")
Next
End Sub
@@ -96,19 +96,61 @@ Public Class GridBuilder
ToList()
For Each oDateCol In oDateColumns
- SetDateTimeColumn(oDateCol)
+ SetDateTimeColumn(oDateCol, "g")
Next
End Sub
- Private Sub SetDateTimeColumn(pColumn As GridColumn)
+ '''
+ ''' Applies a proper datetime format string to all columns of the view.
+ '''
+ ''' The view's columns need to be loaded for this to work!
+ Public Sub SetDateTimeColumns(pView As GridView, pFormatString As String)
+ If pView.Columns Is Nothing Then
+ Exit Sub
+ End If
+
+ Dim oDateColumns = pView.Columns.AsEnumerable.
+ Where(Function(column As GridColumn) column.ColumnType = GetType(Date)).
+ ToList()
+
+ For Each oDateCol In oDateColumns
+ SetDateTimeColumn(oDateCol, pFormatString)
+ Next
+ End Sub
+
+ Public Sub SetDateTimeColumns(pTreeList As TreeList, pFormatString As String)
+ If pTreeList.Columns Is Nothing Then
+ Exit Sub
+ End If
+
+ Dim oDateColumns = pTreeList.Columns.AsEnumerable.
+ Where(Function(column As TreeListColumn) column.ColumnType = GetType(Date)).
+ ToList()
+
+ For Each oDateCol In oDateColumns
+ SetDateTimeColumn(oDateCol, pFormatString)
+ Next
+ End Sub
+
+ Private Sub SetDateTimeColumn(pColumn As GridColumn, pFormatString As String)
+
+ If String.IsNullOrEmpty(pFormatString) Then
+ pFormatString = "g"
+ End If
+
pColumn.DisplayFormat.FormatType = FormatType.Custom
- pColumn.DisplayFormat.FormatString = "g"
+ pColumn.DisplayFormat.FormatString = pFormatString
pColumn.DisplayFormat.Format = DateTimeFormatInfo.CurrentInfo
End Sub
- Private Sub SetDateTimeColumn(pColumn As TreeListColumn)
+ Private Sub SetDateTimeColumn(pColumn As TreeListColumn, pFormatString As String)
+
+ If String.IsNullOrEmpty(pFormatString) Then
+ pFormatString = "g"
+ End If
+
pColumn.Format.FormatType = FormatType.Custom
- pColumn.Format.FormatString = "g"
+ pColumn.Format.FormatString = pFormatString
pColumn.Format.Format = DateTimeFormatInfo.CurrentInfo
End Sub
diff --git a/WEBSERVICES/ZUGFeRDRESTService/Controllers/ValidationController.cs b/WEBSERVICES/ZUGFeRDRESTService/Controllers/ValidationController.cs
index 0ac2c0e8..790c3623 100644
--- a/WEBSERVICES/ZUGFeRDRESTService/Controllers/ValidationController.cs
+++ b/WEBSERVICES/ZUGFeRDRESTService/Controllers/ValidationController.cs
@@ -1,18 +1,21 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Collections.Generic;
+using DigitalData.Modules.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-using DigitalData.Modules.Interfaces;
-using static DigitalData.Modules.Interfaces.Exceptions;
-using static DigitalData.Modules.Interfaces.ZUGFeRDInterface;
-using static DigitalData.Modules.Interfaces.PropertyValues;
-using System.Data.SqlClient;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.Configuration;
-using System.Xml.Linq;
-using Newtonsoft.Json.Linq;
+using Microsoft.VisualStudio.Web.CodeGeneration.Contracts.Messaging;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SqlClient;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
using System.Text.RegularExpressions;
+using System.Xml.Linq;
+using static DigitalData.Modules.Interfaces.Exceptions;
+using static DigitalData.Modules.Interfaces.PropertyValues;
+using static DigitalData.Modules.Interfaces.ZUGFeRDInterface;
namespace ZUGFeRDRESTService.Controllers
{
@@ -26,6 +29,37 @@ namespace ZUGFeRDRESTService.Controllers
public const string ADDED_WHO = "ZUGFeRD REST Service";
public const string MESSAGEID_DOMAIN = "test.wisag.de";
+ public const string VALIDATION_SUCCESS = "VALIDATION SUCCESS";
+ public const string REFERENCES_Rejection_30001 = "REFERENCES_Rejection_30001";
+ public const string REFERENCES_Rejection_30002 = "REFERENCES_Rejection_30002";
+ public const string REFERENCES_Rejection_30002_1 = "REFERENCES_Rejection_30002_1";
+ public const string REFERENCES_Rejection_30003_1 = "REFERENCES_Rejection_30003_1";
+ public const string REFERENCES_Rejection_30003_2 = "REFERENCES_Rejection_30003_2";
+ public const string REFERENCES_Rejection_30003_3 = "REFERENCES_Rejection_30003_3";
+ public const string REFERENCES_Rejection_30004_1 = "REFERENCES_Rejection_30004_1";
+ public const string REFERENCES_Rejection_30004_2 = "REFERENCES_Rejection_30004_2";
+ public const string REFERENCES_Rejection_30004_3 = "REFERENCES_Rejection_30004_3";
+ public const string REFERENCES_Rejection_30005_1 = "REFERENCES_Rejection_30005_1";
+ public const string REFERENCES_Rejection_30005_2 = "REFERENCES_Rejection_30005_2";
+ public const string REFERENCES_Rejection_30006 = "REFERENCES_Rejection_30006";
+ public const string REFERENCES_Rejection_30007 = "REFERENCES_Rejection_30007";
+ public const string REFERENCES_Rejection_30007_1 = "REFERENCES_Rejection_30007_1";
+ public const string REFERENCES_Rejection_30008 = "REFERENCES_Rejection_30008";
+ public const string REFERENCES_Rejection_30009 = "REFERENCES_Rejection_30009";
+ public const string REFERENCES_Rejection_30010 = "REFERENCES_Rejection_30010";
+ public const string REFERENCES_Rejection_30011 = "REFERENCES_Rejection_30011";
+ public const string REFERENCES_Rejection_30012 = "REFERENCES_Rejection_30012";
+ public const string AMOUNT_CALC_REJECTION = "AMOUNT_CALC_REJECTION";
+
+ public const string GERMAN = "de-DE";
+ public const string ENGLISH = "en-US";
+ public const string FRENCH = "fr-FR";
+ public const string SPAIN = "es-ES";
+
+ private List _ValidationErrors;
+ private List _AllowedLanguageCodes;
+ private string _UserLanguageCode = GERMAN;
+
private const int MAX_FILE_SIZE_DEFAULT = 25;
private readonly ZUGFeRDInterface _zugferd;
@@ -33,10 +67,9 @@ namespace ZUGFeRDRESTService.Controllers
private readonly DigitalData.Modules.Logging.LogConfig _logConfig;
private readonly DigitalData.Modules.Logging.Logger _logger;
- private readonly DigitalData.Modules.Filesystem.File _file;
+ //private readonly DigitalData.Modules.Filesystem.File _file;
private readonly PropertyValues _props;
- //private readonly Dictionary _propertyMap = new Dictionary();
private readonly List _propertyMapList = new List();
private readonly List _RecjectionMessageList = new List();
@@ -54,8 +87,6 @@ namespace ZUGFeRDRESTService.Controllers
{
_logConfig = logging.LogConfig;
_logger = _logConfig.GetLogger();
- _file = new DigitalData.Modules.Filesystem.File(_logConfig);
-
_logger.Debug("Validation Controller initializing");
// Read config file and assign all option flags related to
@@ -82,7 +113,37 @@ namespace ZUGFeRDRESTService.Controllers
_logger.Debug("Property Map list initial: [{0}] entries found. [{1}] entries will be available.", oPropertyMapList.Count, _propertyMapList.Count);
_RecjectionMessageList = database.GetRejectionMessageList();
-
+
+ _ValidationErrors = new List() {
+ REFERENCES_Rejection_30001,
+ REFERENCES_Rejection_30002,
+ REFERENCES_Rejection_30003_1,
+ REFERENCES_Rejection_30003_2,
+ REFERENCES_Rejection_30003_3,
+ REFERENCES_Rejection_30004_1,
+ REFERENCES_Rejection_30004_2,
+ REFERENCES_Rejection_30004_3,
+ REFERENCES_Rejection_30005_1,
+ REFERENCES_Rejection_30005_2,
+ REFERENCES_Rejection_30006,
+ REFERENCES_Rejection_30007,
+ REFERENCES_Rejection_30007_1,
+ REFERENCES_Rejection_30008,
+ REFERENCES_Rejection_30009,
+ REFERENCES_Rejection_30010,
+ REFERENCES_Rejection_30011,
+ REFERENCES_Rejection_30012,
+ AMOUNT_CALC_REJECTION
+ };
+
+ _AllowedLanguageCodes = new List()
+ {
+ GERMAN,
+ ENGLISH,
+ FRENCH,
+ SPAIN,
+ };
+
_logger.Debug("Validation Controller initialized!");
}
@@ -146,14 +207,58 @@ namespace ZUGFeRDRESTService.Controllers
///
/// This parameter's name needs to correspond to the html form's file-input name
/// This is the email address which the user supplied
+ /// This is language code which the user supplied (en-US, de-DE)
[HttpPost]
- public ValidationResponse Post(IFormFile file, string user_id)
+ public ValidationResponse Post(IFormCollection collection)
{
_logger.Info("Start processing request to ValidationController");
ZugferdResult oZugferdResult = null;
CheckPropertyValuesResult oPropertyResult = new CheckPropertyValuesResult();
+ var oUserId = string.Empty;
+ var oLanguageId = GERMAN;
+
+ IFormFile file = collection.Files[0];
+
+ foreach (var keyItem in collection.Keys)
+ {
+ if (keyItem == "user_id")
+ {
+ oUserId = collection[keyItem];
+ }
+ else if (keyItem == "language_id")
+ {
+ oLanguageId = collection[keyItem];
+ }
+ }
+
+ if (!string.IsNullOrEmpty(oUserId))
+ {
+ _logger.Info("UserID set to [{0}].", oUserId);
+ }
+ else
+ {
+ _logger.Info("UserID is empty!");
+ }
+
+ if (string.IsNullOrEmpty(oLanguageId))
+ {
+ _logger.Info("Language code was empty. Set to default 'de-DE'");
+ // DEFAULT-Sprache = Deutsch de-DE
+ _UserLanguageCode = GERMAN;
+ }
+ else if (_AllowedLanguageCodes.Where(i => i.Equals(oLanguageId, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() != null)
+ {
+ _logger.Info("Language code is allowed. Set to [{0}].", oLanguageId);
+ _UserLanguageCode = oLanguageId;
+ }
+ else
+ {
+ _logger.Info("Language code was unknown: [{0}]. Set to default 'de-DE'", oLanguageId);
+ _UserLanguageCode = GERMAN;
+ }
+
try
{
using Stream oStream = file.OpenReadStream();
@@ -165,7 +270,6 @@ namespace ZUGFeRDRESTService.Controllers
if (oFileSizeIsOK == false)
{
- //throw new ZUGFeRDExecption(ErrorType.FileTooBig, "FileTooBig");
throw new ZUGFeRDExecption(ErrorCodes.FileSizeLimitReachedException, _MaxFileSizeInMegabytes.ToString(), string.Empty, "FileTooBig");
}
@@ -174,6 +278,7 @@ namespace ZUGFeRDRESTService.Controllers
if (file.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
{
oZugferdResult = _zugferd.ExtractZUGFeRDFileWithGDPicture(oStream);
+ oZugferdResult.ReceiptFileType = "PDF";
}
else if (file.FileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
{
@@ -185,23 +290,23 @@ namespace ZUGFeRDRESTService.Controllers
};
oZugferdResult = _zugferd.SerializeZUGFeRDDocument(oResult);
+ oZugferdResult.ReceiptFileType = "XML";
}
_logger.Info("Detected Specification was: [{0}]", oZugferdResult.Specification);
- var oFilteredPropertyMap = _zugferd.FilterPropertyMap(_propertyMapList, oZugferdResult.Specification);
+ var oFilteredPropertyMap = _zugferd.FilterPropertyMap(_propertyMapList, oZugferdResult.Specification);
if (oFilteredPropertyMap.Count == 0)
{
_logger.Warn("No properties found in property map for specification [{0}]", oZugferdResult.Specification);
- //throw new ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Unsupported Format");
throw new ZUGFeRDExecption(ErrorCodes.UnsupportedFerdException, "Unsupported Format");
- }
+ }
else
{
_logger.Debug("Property map contains [{0}] entries for specification [{1}]", oFilteredPropertyMap.Count, oZugferdResult.Specification);
}
-
+
_logger.Info("Starting structural check against the database.");
oPropertyResult = _props.CheckPropertyValues(oZugferdResult.SchemaObject, oFilteredPropertyMap, "MESSAGEID");
@@ -219,24 +324,21 @@ namespace ZUGFeRDRESTService.Controllers
if (oPropertyResult.MissingProperties.Count > 0)
{
- //throw new ZUGFeRDExecption(ErrorType.MissingProperties, "Missing Properties");
throw new ZUGFeRDExecption(ErrorCodes.MissingValueException, "Missing Properties");
- }
+ }
- Tuple oValidateResult = ValidateBuyerOrderReference(oPropertyResult.ValidProperties);
+ Tuple oValidateResult = ValidateBuyerOrderReference(oPropertyResult.ValidProperties, oZugferdResult);
if (oValidateResult.Item1 == false)
{
- //throw new ZUGFeRDExecption(ErrorType.UnknownError, "Unknown Error");
throw new ZUGFeRDExecption(ErrorCodes.UnhandledException, "Unknown Error");
}
string oValidateResultString = oValidateResult.Item2;
- if (oValidateResultString == "ALL REFERENCES CHECKED POSITIVE")
+ if (oValidateResultString.Equals(VALIDATION_SUCCESS))
{
string oMessage = "Die hochgeladene Datei ist eine gültige-ZUGFeRD Rechnung";
-
_logger.Info($"Responding with message: [{oMessage}]");
return new ValidationResponse()
@@ -244,10 +346,10 @@ namespace ZUGFeRDRESTService.Controllers
status = RESPONSE_OK,
message = oMessage
};
- } else
+ }
+ else
{
string oMessage = oValidateResultString;
-
_logger.Info($"Responding with message: [{oMessage}]");
return new ValidationResponse()
@@ -256,7 +358,8 @@ namespace ZUGFeRDRESTService.Controllers
message = oMessage
};
}
- };
+ }
+
}
catch (ZUGFeRDExecption ex)
{
@@ -282,26 +385,24 @@ namespace ZUGFeRDRESTService.Controllers
oMessage = Regex.Replace(oMessage, "@REPLACE_PARAM2", ex.Param2, RegexOptions.IgnoreCase);
}
- // Der REJECTION-Code wird in alle Meldungen eingefügt.
- if (!string.IsNullOrEmpty(rejectionCodeNumber) && oMessage.Contains("@REJECTION_CODE", StringComparison.OrdinalIgnoreCase))
- {
- oMessage = Regex.Replace(oMessage, "@REJECTION_CODE", "Ablehnungscode: " + rejectionCodeNumber, RegexOptions.IgnoreCase);
- }
-
// Determine if any errors should be sent in the response
switch (ex.ErrorCode)
{
case ErrorCodes.MissingValueException:
- oErrors.AddRange(from item in oPropertyResult.MissingProperties
- select (item.EN16931_ID + " (" + item.Description + ")"));
+
+ var oErrorsText = GetMissingValuesListString(oPropertyResult.MissingProperties);
+ if (!string.IsNullOrEmpty(oErrorsText) && oMessage.Contains("@REPLACE_PARAM3", StringComparison.OrdinalIgnoreCase))
+ {
+ oMessage = Regex.Replace(oMessage, "@REPLACE_PARAM3", oErrorsText, RegexOptions.IgnoreCase);
+ }
break;
default:
break;
}
}
- else
+ else
{
- oMessage = "Alte Logik. Meldung nicht gefunden";
+ oMessage = "Alte Logik. Meldung nicht gefunden";
}
_logger.Info($"Responding with message: [{oMessage}]");
@@ -315,21 +416,61 @@ namespace ZUGFeRDRESTService.Controllers
}
catch (ValidationException ex)
{
+ _logger.Error(ex);
+
var rejectionCodeNumber = this.GetRejectionCodeNumber(ex.ErrorCode);
// Der gesamte Ausgabetext muss anhand des ErrorCodes ermittelt werden
string oMessage = this.GetRejectionMessage(rejectionCodeNumber);
- List oErrors = ex.ValidationErrors.Select(e =>
- {
- return $"Element '{e.ElementName}' mit Wert '{e.ElementValue}': {e.ErrorMessageDE}";
- }).ToList();
+ // Wenn es ValidationErrors gibt, werden diese nun übersetzt und in eine Liste übertragen werden
+ var mainText = GetTextByToken("ItemValueText");
+ var resultList = new List();
+ foreach (var errorItem in ex.ValidationErrors)
+ {
+ var resultString = mainText;
+
+ if (!string.IsNullOrEmpty(errorItem.ElementName))
+ {
+ // replace @ITEM_NAME => e.ElementName
+ resultString = resultString.Replace("@ITEM_NAME", errorItem.ElementName, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (!string.IsNullOrEmpty(errorItem.ElementValue))
+ {
+ // replace ITEM_VALUE => e.ElementValue
+ resultString = resultString.Replace("@ITEM_VALUE", errorItem.ElementValue, StringComparison.OrdinalIgnoreCase);
+ }
+
+ var itemErrorText = GetTextByToken(errorItem.ErrorMessageToken);
+ if (!string.IsNullOrEmpty(itemErrorText))
+ {
+ // attach itemErrorText
+ resultString += " " + itemErrorText;
+ }
+
+ _logger.Debug($"resultString: [{resultString}]");
+ resultList.Add(resultString);
+ }
+
+ // wenn ergebnisse vorliegen, in html transformieren und anhängen
+ if (resultList.Count > 0)
+ {
+ var htmlResultString = "";
+ foreach (var resultItem in resultList)
+ {
+ htmlResultString += " - " + resultItem + "
" + Environment.NewLine;
+ }
+ htmlResultString += "
";
+
+ oMessage += " " + htmlResultString;
+ }
+
return new ValidationResponse()
{
status = RESPONSE_ERROR,
- message = oMessage,
- errors = oErrors
+ message = oMessage
};
}
catch (Exception ex)
@@ -348,20 +489,73 @@ namespace ZUGFeRDRESTService.Controllers
}
}
- private Tuple ValidateBuyerOrderReference(List pProperties)
+ private string GetMissingValuesListString(List missingProperties)
+ {
+ if (missingProperties == null || missingProperties.Count == 0)
+ {
+ return string.Empty;
+ }
+
+ string retValue = "";
+ foreach (var missingProperty in missingProperties)
+ {
+ var searchToken = missingProperty.EN16931_ID + "_Description";
+ var descriptionTranslated = GetTextByToken(searchToken);
+ var rowString = "- " + missingProperty.EN16931_ID + " (" + descriptionTranslated + ")
";
+ retValue += rowString;
+ }
+ retValue += "
";
+
+ return retValue;
+ }
+
+ ///
+ /// Holt sprachgenauen Text anhand eines Titel-Tokens
+ ///
+ ///
+ private string GetTextByToken(string tokenValue)
+ {
+ RejectionStringRow stringRow = null;
+
+ if (!string.IsNullOrEmpty(tokenValue))
+ {
+ stringRow = _RecjectionMessageList.Where(i => i.Title.Equals(tokenValue, StringComparison.OrdinalIgnoreCase) &&
+ i.Language.Equals(_UserLanguageCode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+
+ if (stringRow == null &&
+ !_UserLanguageCode.Equals(GERMAN, StringComparison.OrdinalIgnoreCase))
+ {
+ // Wenn kein sprachgenauer Text vorliegt, hole den deutschen Text.
+ stringRow = _RecjectionMessageList.Where(i => i.Title.Equals(tokenValue, StringComparison.OrdinalIgnoreCase) &&
+ i.Language.Equals(GERMAN, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+ }
+ }
+
+ string retValue = string.Empty;
+
+ if (stringRow != null)
+ {
+ retValue = !string.IsNullOrEmpty(stringRow.String1) ? stringRow.String1.Trim() : string.Empty;
+ }
+
+ _logger.Debug($"Token [{tokenValue}] - String1 [{retValue}]");
+ return retValue;
+ }
+
+ ///
+ /// Hier wird eine externe Prozedur gerufen, PRCUST_INV_CHECK_FROM_PORTAL,
+ /// die das Ergebnis der Referenzpruefung liefert.
+ ///
+ private Tuple ValidateBuyerOrderReference(List pProperties, ZugferdResult pZugferdResult)
{
var oMessageId = GetMessageId();
- _logger.Debug("Created new MessageId: [{0}]", oMessageId);
+ _logger.Debug("Created new MessageId: [{0}]", oMessageId);
_logger.Debug("Inserting properties into database.");
- foreach (var oItem in pProperties)
+ if (!BulkInsertDataToDatabase(oMessageId, pProperties, pZugferdResult))
{
- var oResult = InsertPropertyMap(oItem, oMessageId);
-
- if (oResult == false)
- {
- _logger.Warn("Error while inserting the Property [{0}] into the Database!", oItem.Description);
- }
+ _logger.Warn("Error while Inserting properties into database!");
+ return new Tuple(false, string.Empty);
}
_logger.Debug("Calling validation prodecure.");
@@ -377,6 +571,57 @@ namespace ZUGFeRDRESTService.Controllers
if (_database.MSSQL.ExecuteNonQuery(oCommand))
{
string oReturnValue = (string)oCommand.Parameters["@MSG_OUTPUT"].Value;
+
+ _logger.Debug("Validation Result message from DB: " + oReturnValue);
+
+ if (oReturnValue.Equals("ALL REFERENCES CHECKED POSITIVE", StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.Debug("Validation Success");
+ oReturnValue = VALIDATION_SUCCESS;
+ }
+ else
+ {
+ // Gehe durch die möglichen Fehler, und ermittle Rückmeldung
+ foreach (var oRejectionItem in _ValidationErrors)
+ {
+ if (oReturnValue.Contains(oRejectionItem, StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.Debug("oRejectionItem match: " + oRejectionItem);
+
+ var oDbMessage = this.GetRejectionMessage(oRejectionItem);
+
+ //Jetzt müssen ggf Platzhalter ersetzt werden.
+ if (oRejectionItem == REFERENCES_Rejection_30003_2)
+ {
+ string oReplaceParam1 = GetReplaceText1_30003_2(pProperties);
+ string oReplaceParam2 = GetReplaceText2_30003_2(pProperties);
+
+ oReturnValue = oDbMessage.Replace("@REPLACE_PARAM1", oReplaceParam1);
+ oReturnValue = oReturnValue.Replace("@REPLACE_PARAM2", oReplaceParam2);
+
+ }
+ else if (oRejectionItem == REFERENCES_Rejection_30003_3)
+ {
+ string oReplaceParam1 = GetReplaceText1_30003_3(pProperties);
+
+ oReturnValue = oDbMessage.Replace("@REPLACE_PARAM1", oReplaceParam1);
+ }
+ else if (oRejectionItem == REFERENCES_Rejection_30001)
+ {
+ // TODO - BUKR?
+ oReturnValue = oDbMessage.Replace("@REPLACE_PARAM1", "9999");
+ }
+ else
+ {
+ oReturnValue = oDbMessage;
+ }
+
+ break;
+ }
+ }
+ }
+
+ _logger.Debug("Validation terminal Result message: " + oReturnValue);
return new Tuple(true, oReturnValue);
}
@@ -390,86 +635,391 @@ namespace ZUGFeRDRESTService.Controllers
{
_logger.Error(e);
return new Tuple(false, string.Empty);
- }
+ }
}
- public string GetMessageId()
+ private string GetReplaceText1_30003_3(List pProperties)
+ {
+ string oReplaceParam1 = string.Empty;
+
+ // BuyerOrderReferencedDocument
+ var itemBT13 = pProperties.Where(i => i.TableColumn == "INVOICE_REFERENCE").FirstOrDefault();
+ string valueBt13 = "-";
+ if (itemBT13 != null)
+ {
+ valueBt13 = string.IsNullOrEmpty(itemBT13.Value) ? "-" : itemBT13.Value;
+ }
+ oReplaceParam1 += "[BuyerOrderReferencedDocument] (BT-13) = [" + valueBt13 + "]";
+
+
+ // BuyerReference
+ var itemBT10 = pProperties.Where(i => i.TableColumn == "INVOICE_REFERENCE3").FirstOrDefault();
+ string valueBt10 = "-";
+ if (itemBT10 != null)
+ {
+ valueBt10 = string.IsNullOrEmpty(itemBT10.Value) ? "-" : itemBT10.Value;
+ }
+ oReplaceParam1 += "[BuyerReference] (BT-10) = [" + valueBt10 + "]";
+
+
+ // CostCenter
+ var itemBT19 = pProperties.Where(i => i.TableColumn == "INVOICE_COST_CENTER").FirstOrDefault();
+ string valueBt19 = "-";
+ if (itemBT19 != null)
+ {
+ valueBt19 = string.IsNullOrEmpty(itemBT19.Value) ? "-" : itemBT19.Value;
+ }
+ oReplaceParam1 += "[CostCenter] (BT-19) = [" + valueBt19 + "]";
+
+ // BuyerID
+ var itemBT46 = pProperties.Where(i => i.TableColumn == "INVOICE_BUYER_ID").FirstOrDefault();
+ string valueBt46 = "-";
+ if (itemBT46 != null)
+ {
+ valueBt46 = string.IsNullOrEmpty(itemBT46.Value) ? "-" : itemBT46.Value;
+ }
+ oReplaceParam1 += "[BuyerTradeParty] (BT-46) = [" + valueBt46 + "]";
+
+ oReplaceParam1 = "";
+ _logger.Debug("oReplaceParam1-Text: " + oReplaceParam1);
+
+ return oReplaceParam1;
+ }
+
+ private string GetReplaceText2_30003_2(List pProperties)
+ {
+ string oReplaceParam2 = string.Empty;
+
+ // BuyerTradeParty.Name
+ var itemBT44 = pProperties.Where(i => i.TableColumn == "INVOICE_BUYER_NAME").FirstOrDefault();
+ string valueBt44 = "-";
+ if (itemBT44 != null)
+ {
+ valueBt44 = string.IsNullOrEmpty(itemBT44.Value) ? "-" : itemBT44.Value;
+ }
+ oReplaceParam2 += "[BuyerTradeParty.Name] (BT-44) = [" + valueBt44 + "]";
+
+ // BuyerTradeParty.PostalTradeAddress.LineTwo
+ var itemBT51 = pProperties.Where(i => i.TableColumn == "INVOICE_BUYER_ADRESS2").FirstOrDefault();
+ string valueBt51 = "-";
+ if (itemBT51 != null)
+ {
+ valueBt51 = string.IsNullOrEmpty(itemBT51.Value) ? "-" : itemBT51.Value;
+ }
+ oReplaceParam2 += "[BuyerTradeParty.PostalTradeAddress.LineTwo] (BT-51) = [" + valueBt51 + "]";
+
+ oReplaceParam2 = "";
+ _logger.Debug("oReplaceParam2-Text: " + oReplaceParam2);
+
+ return oReplaceParam2;
+ }
+
+ private string GetReplaceText1_30003_2(List pProperties)
+ {
+ string oReplaceParam1 = string.Empty;
+
+ // BuyerOrderReferencedDocument
+ var itemBT13 = pProperties.Where(i => i.TableColumn == "INVOICE_REFERENCE").FirstOrDefault();
+ string valueBt13 = "-";
+ if (itemBT13 != null)
+ {
+ valueBt13 = string.IsNullOrEmpty(itemBT13.Value) ? "-" : itemBT13.Value;
+ }
+ oReplaceParam1 += "[BuyerOrderReferencedDocument] (BT-13) = [" + valueBt13 + "]";
+
+
+ // BuyerReference
+ var itemBT10 = pProperties.Where(i => i.TableColumn == "INVOICE_REFERENCE3").FirstOrDefault();
+ string valueBt10 = "-";
+ if (itemBT10 != null)
+ {
+ valueBt10 = string.IsNullOrEmpty(itemBT10.Value) ? "-" : itemBT10.Value;
+ }
+ oReplaceParam1 += "[BuyerReference] (BT-10) = [" + valueBt10 + "]";
+
+
+ // CostCenter
+ var itemBT19 = pProperties.Where(i => i.TableColumn == "INVOICE_COST_CENTER").FirstOrDefault();
+ string valueBt19 = "-";
+ if (itemBT19 != null)
+ {
+ valueBt19 = string.IsNullOrEmpty(itemBT19.Value) ? "-" : itemBT19.Value;
+ }
+ oReplaceParam1 += "[CostCenter] (BT-19) = [" + valueBt19 + "]";
+
+ oReplaceParam1 = "";
+ _logger.Debug("oReplaceParam1-Text: " + oReplaceParam1);
+
+ return oReplaceParam1;
+ }
+
+ private string GetMessageId()
{
return $"{Guid.NewGuid()}@{MESSAGEID_DOMAIN}";
}
- public bool InsertPropertyMap(ValidProperty pProperty, string pMessageId)
+ private bool BulkInsertDataToDatabase(string pMessageId, List pProperties, ZugferdResult pZugferdResult)
+ {
+ if (string.IsNullOrEmpty(pMessageId))
+ {
+ return false;
+ }
+
+ if (!DeleteExistingPropertyValues(pMessageId))
+ {
+ return false;
+ }
+
+ DataTable oDataTable = PrepareDataTable(pMessageId, pProperties, pZugferdResult);
+
+ // ColumnList initialisieren
+ List oColumnNames = new List {
+ "REFERENCE_GUID",
+ "ITEM_DESCRIPTION",
+ "ITEM_VALUE",
+ "GROUP_COUNTER",
+ "SPEC_NAME",
+ "IS_REQUIRED"
+ };
+
+ bool oBulkResult = BulkInsert(oDataTable, "TBEDMI_ITEM_VALUE", oColumnNames);
+
+ if (!oBulkResult)
+ {
+ _logger.Error("Bulk Insert for MessageId [{0}] failed!", pMessageId);
+ return false;
+ }
+
+ _logger.Info("Bulk Insert finished. [{0}] rows inserted for MessageId [{1}].", oDataTable.Rows.Count, pMessageId);
+ return true;
+ }
+
+ private bool BulkInsert(DataTable pDataTable, string pDestinationTable, List pColumnNames)
+ {
+ using (var oSqlBulkCopy = new SqlBulkCopy(_database.MSSQL.GetConnection()))
+ {
+ oSqlBulkCopy.DestinationTableName = pDestinationTable;
+ foreach (var columnItem in pColumnNames)
+ {
+ oSqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(columnItem, columnItem));
+ }
+
+ try
+ {
+ oSqlBulkCopy.WriteToServer(pDataTable);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private DataTable PrepareDataTable(string pMessageId, List pProperties, ZugferdResult pDocument)
+ {
+ DataTable oDataTable = new DataTable();
+ oDataTable.Columns.Add(new DataColumn("REFERENCE_GUID", typeof(string)));
+ oDataTable.Columns.Add(new DataColumn("ITEM_DESCRIPTION", typeof(string)));
+ oDataTable.Columns.Add(new DataColumn("ITEM_VALUE", typeof(string)));
+ oDataTable.Columns.Add(new DataColumn("GROUP_COUNTER", typeof(Int32)));
+ oDataTable.Columns.Add(new DataColumn("SPEC_NAME", typeof(string)));
+ oDataTable.Columns.Add(new DataColumn("IS_REQUIRED", typeof(bool)));
+
+ // Erste Zeile enthält die Spezifikation
+ DataRow oFirstRow = oDataTable.NewRow();
+ oFirstRow["REFERENCE_GUID"] = pMessageId;
+ oFirstRow["ITEM_DESCRIPTION"] = "Verwendete Spezifikation der E-Rechnung";
+ oFirstRow["ITEM_VALUE"] = pDocument.Specification;
+ oFirstRow["GROUP_COUNTER"] = 0;
+ oFirstRow["SPEC_NAME"] = "ZUGFERD_SPECIFICATION";
+ oFirstRow["IS_REQUIRED"] = false;
+
+ _logger.Debug("Mapping Property [ZUGFERD_SPECIFICATION] with value [{0}]", pDocument.Specification);
+ oDataTable.Rows.Add(oFirstRow);
+
+ //' Zweite Zeile enthält das verwendete XML Schema
+ DataRow oSecondRow = oDataTable.NewRow();
+ oSecondRow["REFERENCE_GUID"] = pMessageId;
+ oSecondRow["ITEM_DESCRIPTION"] = "Verwendetes XML-Schema (XSD) der E-Rechnung";
+ oSecondRow["ITEM_VALUE"] = pDocument.UsedXMLSchema;
+ oSecondRow["GROUP_COUNTER"] = 0;
+ oSecondRow["SPEC_NAME"] = "ZUGFERD_XML_SCHEMA";
+ oSecondRow["IS_REQUIRED"] = false;
+
+ _logger.Debug("Mapping Property [ZUGFERD_XML_SCHEMA] with value [{0}]", pDocument.UsedXMLSchema);
+ oDataTable.Rows.Add(oSecondRow);
+
+ //' Dritte Zeile enthält das verwendete Datei-Format des Belegs (PDF/XML)
+ if (pDocument.ReceiptFileType != null)
+ {
+ DataRow oThirdRow = oDataTable.NewRow();
+ oThirdRow["REFERENCE_GUID"] = pMessageId;
+ oThirdRow["ITEM_DESCRIPTION"] = "Dateityp der E-Rechnung";
+ oThirdRow["ITEM_VALUE"] = pDocument.ReceiptFileType;
+ oThirdRow["GROUP_COUNTER"] = 0;
+ oThirdRow["SPEC_NAME"] = "RECEIPT_FILE_TYPE";
+ oThirdRow["IS_REQUIRED"] = false;
+
+ _logger.Debug("Mapping Property [RECEIPT_FILE_TYPE] with value [{0}]", pDocument.ReceiptFileType);
+ oDataTable.Rows.Add(oThirdRow);
+ }
+
+ foreach (var propertyItem in pProperties)
+ {
+
+ // ItemType = 3 => eingebettete Datei, nicht den base64 speichern
+ if (propertyItem.ItemType == 3)
+ {
+ continue;
+ }
+
+ // ItemType = 0 (normale texte) dürfen nicht leer sein - leere Werte werden überlesen
+ if (propertyItem.ItemType == 0 && string.IsNullOrEmpty(propertyItem.Value))
+ {
+ continue;
+ }
+
+ // If GroupCounter is -1, it means this is a default property that can only occur once.
+ // Set the actual inserted value to 0
+ var oGroupCounterValue = propertyItem.GroupCounter < 0 ? 0 : propertyItem.GroupCounter;
+
+ if (propertyItem.Value.Length > 4000)
+ {
+ _logger.Warn("Value for field [{0}] is longer than 4000 characters, will be truncated!", propertyItem.TableColumn);
+ propertyItem.Value = propertyItem.Value.Substring(0, 4000);
+ }
+
+ // Description mit BT-Feld aufbereiten
+ var betterDescription = propertyItem.Description;
+ if (!string.IsNullOrEmpty(propertyItem.EN16931_ID))
+ {
+ betterDescription = propertyItem.EN16931_ID + " (" + propertyItem.Description + ")";
+ }
+
+ DataRow newRow = oDataTable.NewRow();
+ newRow["REFERENCE_GUID"] = pMessageId;
+ newRow["ITEM_DESCRIPTION"] = betterDescription;
+ newRow["ITEM_VALUE"] = propertyItem.Value;
+ newRow["GROUP_COUNTER"] = oGroupCounterValue;
+ newRow["SPEC_NAME"] = propertyItem.TableColumn;
+ newRow["IS_REQUIRED"] = propertyItem.IsRequired;
+
+ _logger.Debug("Mapping Property [{0}] with value [{1}]", propertyItem.TableColumn, propertyItem.Value);
+ oDataTable.Rows.Add(newRow);
+ }
+
+ return oDataTable;
+ }
+
+ private bool DeleteExistingPropertyValues(string pMessageId)
{
try
{
- if (pProperty.ItemType == 3)
+ var delItemValueSQL = "DELETE FROM TBEDMI_ITEM_VALUE WHERE REFERENCE_GUID = '" + pMessageId + "';";
+ var oCommand = new SqlCommand(delItemValueSQL);
+ var retValue = _database.MSSQL.ExecuteNonQuery(oCommand);
+
+ if (!retValue)
{
- // Wir speichern keine Attachment-Werte in die DB
- return true;
+ _logger.Warn("DELETE FROM TBEDMI_ITEM_VALUE NOT successfull");
+ return false;
}
- if (pProperty.ItemType == 0 && string.IsNullOrEmpty(pProperty.Value.ToString()))
- {
- // Leere Texte speichern wir nicht in der DB
- return true;
- }
-
- var oSql = $"INSERT INTO {pProperty.TableName} " +
- "(REFERENCE_GUID, ITEM_DESCRIPTION, ITEM_VALUE, CREATEDWHO, SPEC_NAME, GROUP_COUNTER, IS_REQUIRED) VALUES " +
- "(@REFERENCE_GUID, @ITEM_DESCRIPTION, @ITEM_VALUE, @CREATEDWHO, @SPEC_NAME, @GROUP_COUNTER, @IS_REQUIRED)";
-
- string itemValue = string.Empty;
- if (pProperty.Value.Length > 4000)
- {
- itemValue = pProperty.Value.Substring(1, 4000);
- _logger.Warn("Value for field [{0}] is longer than 4000 characters, will be truncated!", pProperty.TableColumn);
- }
- else
- {
- itemValue = pProperty.Value;
- }
-
- var oParams = new SqlParameter[]
- {
- new SqlParameter("@REFERENCE_GUID", pMessageId),
- new SqlParameter("@ITEM_DESCRIPTION", pProperty.Description),
- new SqlParameter("@ITEM_VALUE", itemValue.Replace("'", "''")),
- new SqlParameter("@CREATEDWHO", ADDED_WHO),
- new SqlParameter("@GROUP_COUNTER", pProperty.GroupCounter),
- new SqlParameter("@SPEC_NAME", pProperty.TableColumn),
- new SqlParameter("@IS_REQUIRED", pProperty.IsRequired)
- };
-
- var oCommand = new SqlCommand(oSql);
- oCommand.Parameters.AddRange(oParams);
-
- return _database.MSSQL.ExecuteNonQuery(oCommand);
+ _logger.Debug("DELETE FROM TBEDMI_ITEM_VALUE successfull");
}
catch (Exception ex)
{
_logger.Error(ex);
return false;
- }
+ }
+
+ try
+ {
+ var delItemFilesSQL = "DELETE FROM TBEDMI_ITEM_FILES WHERE REFERENCE_GUID = '" + pMessageId + "';";
+ var oCommand = new SqlCommand(delItemFilesSQL);
+ var retValue = _database.MSSQL.ExecuteNonQuery(oCommand);
+
+ if (!retValue)
+ {
+ _logger.Warn("DELETE FROM TBEDMI_ITEM_FILES NOT successfull");
+ return false;
+ }
+ _logger.Debug("DELETE FROM TBEDMI_ITEM_FILES successfull");
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex);
+ return false;
+ }
+
+ return true;
}
///
/// Ermittelt die Ausgabe-nachricht für einen Fehlercode
///
- public string GetRejectionMessage(string pErrorCode)
+ private string GetRejectionMessage(string pErrorCode)
{
_logger.Info("GetRejectionMessage() - errorCode.ToString(): '" + pErrorCode.ToString() + "'");
if (_RecjectionMessageList == null) return string.Empty;
- // Sprache wird man vielleicht mal auswählen können
- var language = "de-DE";
- var searchTitle = "ZUGFERD_Rejection_" + pErrorCode + "_Web";
+ var searchTitle = string.Empty;
- var messageItem = _RecjectionMessageList.Where(i => i.Title.Equals(searchTitle, StringComparison.OrdinalIgnoreCase) && i.Language.Equals(language, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
- if (messageItem != null)
+ if (pErrorCode.Contains("2000"))
{
- _logger.Info("GetRejectionMessage() - messageItem: '" + messageItem.String1 + "'");
- return messageItem.String1;
+ searchTitle = "ZUGFERD_Rejection_" + pErrorCode + "_Web";
+ }
+ else if (pErrorCode.Contains("REFERENCES_Rejection_3000"))
+ {
+ searchTitle = pErrorCode + "_Web";
+ }
+ else if (pErrorCode.Contains("AMOUNT_CALC"))
+ {
+ searchTitle = "AMOUNT_CALC_REJECTION_Web";
+ }
+ else
+ {
+ searchTitle = "ZUGFERD_Rejection_20006_Web";
+ }
+
+ // Sprachgenauen Text suchen.
+ var messageItem = _RecjectionMessageList.Where(i => i.Title.Equals(searchTitle, StringComparison.OrdinalIgnoreCase) &&
+ i.Language.Equals(_UserLanguageCode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+
+ if (messageItem == null &&
+ !_UserLanguageCode.Equals(GERMAN, StringComparison.OrdinalIgnoreCase)) {
+
+ _logger.Info("GetRejectionMessage() - Es wurde kein passender Text für die Sprache [{0}] gefunden.", _UserLanguageCode);
+
+ // Wenn kein sprachgenauer Text vorliegt, hole den deutschen Text.
+ messageItem = _RecjectionMessageList.Where(i => i.Title.Equals(searchTitle, StringComparison.OrdinalIgnoreCase) &&
+ i.Language.Equals(GERMAN, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+ }
+
+ if (messageItem != null && !string.IsNullOrEmpty(pErrorCode))
+ {
+ var resultText = string.Empty;
+
+ // Der REJECTION-Code wird in allen Meldungen ausgetauscht.
+ if (messageItem.String1.Contains("@REJECTION_CODE", StringComparison.OrdinalIgnoreCase))
+ {
+ var substituteText = this.GetLabelText("Ablehnungscode", _UserLanguageCode);
+ substituteText = string.IsNullOrEmpty(substituteText) ? "Ablehnungscode" : substituteText;
+ substituteText = substituteText + ": " + pErrorCode;
+
+ resultText = Regex.Replace(messageItem.String1, "@REJECTION_CODE", substituteText, RegexOptions.IgnoreCase);
+ }
+ else
+ {
+ resultText = messageItem.String1;
+ }
+
+ _logger.Info("GetRejectionMessage() - messageItem: '" + resultText + "'");
+ return resultText;
}
else
{
@@ -478,6 +1028,15 @@ namespace ZUGFeRDRESTService.Controllers
}
}
+ private string GetLabelText(string pLabel, string pLanguage)
+ {
+ // Sprachgenauen Text suchen.
+ var messageItem = _RecjectionMessageList.Where(i => i.Title.Equals(pLabel, StringComparison.OrdinalIgnoreCase) &&
+ i.Language.Equals(pLanguage, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+
+ return messageItem != null ? messageItem.String1 : string.Empty;
+ }
+
private string GetRejectionCodeNumber(ErrorCodes rejectionCode)
{
switch (rejectionCode)
diff --git a/WEBSERVICES/ZUGFeRDRESTService/Pages/Index.cshtml b/WEBSERVICES/ZUGFeRDRESTService/Pages/Index.cshtml
index d941e9ef..1b7cf371 100644
--- a/WEBSERVICES/ZUGFeRDRESTService/Pages/Index.cshtml
+++ b/WEBSERVICES/ZUGFeRDRESTService/Pages/Index.cshtml
@@ -15,7 +15,12 @@
-
+
+
+
+
+
+
diff --git a/WEBSERVICES/ZUGFeRDRESTService/appsettings.Development.json b/WEBSERVICES/ZUGFeRDRESTService/appsettings.Development.json
index b6613161..1bf7cf67 100644
--- a/WEBSERVICES/ZUGFeRDRESTService/appsettings.Development.json
+++ b/WEBSERVICES/ZUGFeRDRESTService/appsettings.Development.json
@@ -20,11 +20,11 @@
},
"Zugferd": {
"AllowZugferd10": true,
- "AllowZugferd2x": false,
- "AllowZugferd23x": false,
- "AllowFacturX": false,
- "AllowXRechnung": false,
- "AllowPeppolBISBill3x": false
+ "AllowZugferd2x": true,
+ "AllowZugferd23x": true,
+ "AllowFacturX": true,
+ "AllowXRechnung": true,
+ "AllowPeppolBISBill3x": true
},
"GDPictureVersion": "",
"MaxFileSizeInMegabytes": 25