ZUGFeRD REST Service - ErrorCodes aus Exception abfangen, und mit dem Code den Text aus der Datenbank holen und anzeigen.

This commit is contained in:
PitzM 2025-08-08 11:51:49 +02:00
parent aa3a798b24
commit 11d6157726
5 changed files with 205 additions and 59 deletions

View File

@ -12,6 +12,7 @@ using System.Data.SqlClient;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System.Xml.Linq; using System.Xml.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
namespace ZUGFeRDRESTService.Controllers namespace ZUGFeRDRESTService.Controllers
{ {
@ -37,6 +38,7 @@ namespace ZUGFeRDRESTService.Controllers
private readonly PropertyValues _props; private readonly PropertyValues _props;
//private readonly Dictionary<string, XmlItemProperty> _propertyMap = new Dictionary<string, XmlItemProperty>(); //private readonly Dictionary<string, XmlItemProperty> _propertyMap = new Dictionary<string, XmlItemProperty>();
private readonly List<XmlItemProperty> _propertyMapList = new List<XmlItemProperty>(); private readonly List<XmlItemProperty> _propertyMapList = new List<XmlItemProperty>();
private readonly List<RejectionStringRow> _RecjectionMessageList = new List<RejectionStringRow>();
private int _MaxFileSizeInMegabytes; private int _MaxFileSizeInMegabytes;
private bool _AllowFacturX; private bool _AllowFacturX;
@ -79,6 +81,8 @@ namespace ZUGFeRDRESTService.Controllers
_propertyMapList.AddRange(oPropertyMapList); _propertyMapList.AddRange(oPropertyMapList);
_logger.Debug("Property Map list initial: [{0}] entries found. [{1}] entries will be available.", oPropertyMapList.Count, _propertyMapList.Count); _logger.Debug("Property Map list initial: [{0}] entries found. [{1}] entries will be available.", oPropertyMapList.Count, _propertyMapList.Count);
_RecjectionMessageList = database.GetRejectionMessageList();
_logger.Debug("Validation Controller initialized!"); _logger.Debug("Validation Controller initialized!");
} }
@ -89,32 +93,32 @@ namespace ZUGFeRDRESTService.Controllers
if (!bool.TryParse(oZugferdConfig["AllowFacturX"], out _AllowFacturX)) if (!bool.TryParse(oZugferdConfig["AllowFacturX"], out _AllowFacturX))
{ {
_logger.Info("Configuration AllowFacturX was not set. Using default value [{0}]", false); _logger.Info("Configuration AllowFacturX was not set. Using default value [{0}]", true);
_AllowFacturX = false; _AllowFacturX = true;
} }
if (!bool.TryParse(oZugferdConfig["AllowXRechnung"], out _AllowXRechnung)) if (!bool.TryParse(oZugferdConfig["AllowXRechnung"], out _AllowXRechnung))
{ {
_logger.Info("Configuration AllowXRechnung was not set. Using default value [{0}]", false); _logger.Info("Configuration AllowXRechnung was not set. Using default value [{0}]", true);
_AllowXRechnung = false; _AllowXRechnung = true;
} }
if (!bool.TryParse(oZugferdConfig["AllowZugferd2x"], out _AllowZugferd2x)) if (!bool.TryParse(oZugferdConfig["AllowZugferd2x"], out _AllowZugferd2x))
{ {
_logger.Info("Configuration Zugferd2x was not set. Using default value [{0}]", false); _logger.Info("Configuration Zugferd2x was not set. Using default value [{0}]", true);
_AllowZugferd2x = false; _AllowZugferd2x = true;
} }
if (!bool.TryParse(oZugferdConfig["AllowZugferd23x"], out _AllowZugferd23x)) if (!bool.TryParse(oZugferdConfig["AllowZugferd23x"], out _AllowZugferd23x))
{ {
_logger.Info("Configuration Zugferd23x was not set. Using default value [{0}]", false); _logger.Info("Configuration Zugferd23x was not set. Using default value [{0}]", true);
_AllowZugferd23x = false; _AllowZugferd23x = true;
} }
if (!bool.TryParse(oZugferdConfig["AllowZugferd10"], out _AllowZugferd10)) if (!bool.TryParse(oZugferdConfig["AllowZugferd10"], out _AllowZugferd10))
{ {
_logger.Info("Configuration Zugferd10 was not set. Using default value [{0}]", true); _logger.Info("Configuration Zugferd10 was not set. Using default value [{0}]", false);
_AllowZugferd10 = true; _AllowZugferd10 = false;
} }
if (!bool.TryParse(oZugferdConfig["AllowPeppolBISBill3x"], out _AllowPeppolBISBill3x)) if (!bool.TryParse(oZugferdConfig["AllowPeppolBISBill3x"], out _AllowPeppolBISBill3x))
@ -161,7 +165,8 @@ namespace ZUGFeRDRESTService.Controllers
if (oFileSizeIsOK == false) if (oFileSizeIsOK == false)
{ {
throw new ZUGFeRDExecption(ErrorType.FileTooBig, "FileTooBig"); //throw new ZUGFeRDExecption(ErrorType.FileTooBig, "FileTooBig");
throw new ZUGFeRDExecption(ErrorCodes.FileSizeLimitReachedException, _MaxFileSizeInMegabytes.ToString(), string.Empty, "FileTooBig");
} }
_logger.Info("Extracting ZUGFeRD Data from file [{0}]", file.FileName); _logger.Info("Extracting ZUGFeRD Data from file [{0}]", file.FileName);
@ -189,7 +194,8 @@ namespace ZUGFeRDRESTService.Controllers
if (oFilteredPropertyMap.Count == 0) if (oFilteredPropertyMap.Count == 0)
{ {
_logger.Warn("No properties found in property map for specification [{0}]", oZugferdResult.Specification); _logger.Warn("No properties found in property map for specification [{0}]", oZugferdResult.Specification);
throw new ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Unsupported Format"); //throw new ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Unsupported Format");
throw new ZUGFeRDExecption(ErrorCodes.UnsupportedFerdException, "Unsupported Format");
} }
else else
{ {
@ -213,14 +219,16 @@ namespace ZUGFeRDRESTService.Controllers
if (oPropertyResult.MissingProperties.Count > 0) if (oPropertyResult.MissingProperties.Count > 0)
{ {
throw new ZUGFeRDExecption(ErrorType.MissingProperties, "Missing Properties"); //throw new ZUGFeRDExecption(ErrorType.MissingProperties, "Missing Properties");
throw new ZUGFeRDExecption(ErrorCodes.MissingValueException, "Missing Properties");
} }
Tuple<bool, string> oValidateResult = ValidateBuyerOrderReference(oPropertyResult.ValidProperties); Tuple<bool, string> oValidateResult = ValidateBuyerOrderReference(oPropertyResult.ValidProperties);
if (oValidateResult.Item1 == false) if (oValidateResult.Item1 == false)
{ {
throw new ZUGFeRDExecption(ErrorType.UnknownError, "Unknown Error"); //throw new ZUGFeRDExecption(ErrorType.UnknownError, "Unknown Error");
throw new ZUGFeRDExecption(ErrorCodes.UnhandledException, "Unknown Error");
} }
string oValidateResultString = oValidateResult.Item2; string oValidateResultString = oValidateResult.Item2;
@ -254,29 +262,47 @@ namespace ZUGFeRDRESTService.Controllers
{ {
_logger.Error(ex); _logger.Error(ex);
// Determine which message should be sent in the response string oMessage;
string oMessage = ex.ErrorType switch var oErrors = new List<string>();
if (ex.ErrorCode != ErrorCodes.NotInUse)
{ {
ErrorType.NoValidFile => "Die hochgeladene Datei ist keine gültige Datei.", var rejectionCodeNumber = this.GetRejectionCodeNumber(ex.ErrorCode);
ErrorType.NoZugferd => "Die hochgeladene Datei ist keine ZUGFeRD-Rechnung.",
ErrorType.NoValidZugferd => "Die hochgeladene Datei ist keine gültige ZUGFeRD-Rechnung.", // Der gesamte Ausgabetext muss anhand des ErrorCodes ermittelt werden
ErrorType.MissingProperties => "Die hochgeladene Datei ist keine gültige ZUGFeRD-Rechnung, es fehlen einige Metadaten.", oMessage = this.GetRejectionMessage(rejectionCodeNumber);
ErrorType.FileTooBig => string.Format("Die hochgeladene Datei überschreitet die zulässige Dateigröße [{0}].", _MaxFileSizeInMegabytes),
ErrorType.UnsupportedFormat => "Die hochgeladene Datei enthält ein falsches oder nicht unterstütztes ZUGFeRD Format.", // Ersetze jetzt die Platzhalter @REPLACE_PARAM1 und @REPLACE_PARAM2
_ => "Die hochgeladene Datei kann nicht validiert werden.", if (!string.IsNullOrEmpty(ex.Param1) && oMessage.Contains("@REPLACE_PARAM1", StringComparison.OrdinalIgnoreCase))
}; {
oMessage = Regex.Replace(oMessage, "@REPLACE_PARAM1", ex.Param1, RegexOptions.IgnoreCase);
}
if (!string.IsNullOrEmpty(ex.Param2) && oMessage.Contains("@REPLACE_PARAM2", StringComparison.OrdinalIgnoreCase))
{
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 // Determine if any errors should be sent in the response
var oErrors = new List<string>(); switch (ex.ErrorCode)
switch (ex.ErrorType)
{ {
case ErrorType.MissingProperties: case ErrorCodes.MissingValueException:
oErrors.AddRange(from item in oPropertyResult.MissingProperties oErrors.AddRange(from item in oPropertyResult.MissingProperties
select item.Description); select (item.EN16931_ID + "(" + item.Description + ")"));
break; break;
default: default:
break; break;
} }
}
else
{
oMessage = "Alte Logik. Meldung nicht gefunden";
}
_logger.Info($"Responding with message: [{oMessage}]"); _logger.Info($"Responding with message: [{oMessage}]");
@ -289,10 +315,14 @@ namespace ZUGFeRDRESTService.Controllers
} }
catch (ValidationException ex) catch (ValidationException ex)
{ {
string oMessage = "Die hochgeladene Datei enthält ungültige Werte."; var rejectionCodeNumber = this.GetRejectionCodeNumber(ex.ErrorCode);
// Der gesamte Ausgabetext muss anhand des ErrorCodes ermittelt werden
string oMessage = this.GetRejectionMessage(rejectionCodeNumber);
List<string> oErrors = ex.ValidationErrors.Select(e => List<string> oErrors = ex.ValidationErrors.Select(e =>
{ {
return $"Element '{e.ElementName}' mit Wert '{e.ElementValue}': {e.ErrorMessage}"; return $"Element '{e.ElementName}' mit Wert '{e.ElementValue}': {e.ErrorMessageDE}";
}).ToList(); }).ToList();
return new ValidationResponse() return new ValidationResponse()
@ -422,5 +452,61 @@ namespace ZUGFeRDRESTService.Controllers
} }
} }
/// <summary>
/// Ermittelt die Ausgabe-nachricht für einen Fehlercode
/// </summary>
public 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 messageItem = _RecjectionMessageList.Where(i => i.Title.Equals(searchTitle, StringComparison.OrdinalIgnoreCase) && i.Language == language).FirstOrDefault();
if (messageItem != null)
{
_logger.Info("GetRejectionMessage() - messageItem: '" + messageItem.String1 + "'");
return messageItem.String1;
}
else
{
_logger.Info("GetRejectionMessage() - Es wurde kein passender Text gefunden.");
return string.Empty;
}
}
private string GetRejectionCodeNumber(ErrorCodes rejectionCode)
{
switch (rejectionCode)
{
case ErrorCodes.ValidationException:
return "20001";
case ErrorCodes.MD5HashException:
return "20002";
case ErrorCodes.UnsupportedFerdException:
return "20003";
case ErrorCodes.InvalidFerdException:
return "20004";
case ErrorCodes.TooMuchFerdsException:
return "20005";
case ErrorCodes.InvalidFerdNoXMLAttachmentFound:
return "20006";
case ErrorCodes.MissingValueException:
return "20007";
case ErrorCodes.FileSizeLimitReachedException:
return "20008";
case ErrorCodes.OutOfMemoryException:
return "20009";
case ErrorCodes.UnhandledException:
return "20010";
case ErrorCodes.FileMoveException:
return "20011";
default:
return "20010";
}
}
} }
} }

View File

@ -14,6 +14,7 @@ namespace ZUGFeRDRESTService
private DigitalData.Modules.Logging.Logger _Logger = null; private DigitalData.Modules.Logging.Logger _Logger = null;
private string _gdPictureKey = null; private string _gdPictureKey = null;
private List<XmlItemProperty> _propertyMapList = null; private List<XmlItemProperty> _propertyMapList = null;
private List<RejectionStringRow> _RejectionStringList = null;
private LogConfig _logConfig = null; private LogConfig _logConfig = null;
private string _connString; private string _connString;
@ -22,6 +23,7 @@ namespace ZUGFeRDRESTService
private const string QUERY_GET_GDPICTURE_KEY = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'"; private const string QUERY_GET_GDPICTURE_KEY = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'";
private const string QUERY_GET_PROPERTY_MAP = "SELECT * FROM TBDD_ZUGFERD_XML_ITEMS WHERE ACTIVE = 1 ORDER BY XML_PATH"; private const string QUERY_GET_PROPERTY_MAP = "SELECT * FROM TBDD_ZUGFERD_XML_ITEMS WHERE ACTIVE = 1 ORDER BY XML_PATH";
private const string QUERY_GET_REJECTION_MESSAGES = "SELECT * FROM TBDD_GUI_LANGUAGE_PHRASE WHERE CAPT_TYPE = 'RejectionCodeWeb'";
public MSSQLServer MSSQL { get; set; } public MSSQLServer MSSQL { get; set; }
@ -85,5 +87,52 @@ namespace ZUGFeRDRESTService
return _propertyMapList; return _propertyMapList;
} }
public List<RejectionStringRow> GetRejectionMessageList()
{
try
{
if (_RejectionStringList == null)
{
var oDatatable = MSSQL.GetDatatable(QUERY_GET_REJECTION_MESSAGES);
_Logger.Debug("Datatable Rows: [{0}]", oDatatable.Rows.Count);
if (oDatatable != null && oDatatable.Rows.Count > 0)
{
_RejectionStringList = new List<RejectionStringRow>();
foreach (DataRow oRow in oDatatable.Rows)
{
var newRejectionItem = new RejectionStringRow
{
Title = oRow["Title"].ToString(),
ModuleName = oRow["Module"].ToString(),
Caption = oRow["CAPT_TYPE"].ToString(),
Language = oRow["Language"].ToString(),
String1 = oRow["String1"].ToString()
};
_RejectionStringList.Add(newRejectionItem);
}
_Logger.Debug("Returning Rejections messages list with [{0}] entries.", _RejectionStringList.Count);
}
else
{
_RejectionStringList = null;
_Logger.Warn("No Rejections messages found in Table TBDD_GUI_LANGUAGE_PHRASE with CAPT_TYPE = 'RejectionCodeWeb'!!!");
}
}
else
{
_Logger.Debug("Rejections messages list already exists, returning list with [{0}] entries.", _RejectionStringList.Count);
}
}
catch (Exception ex)
{
_RejectionStringList = null;
_Logger.Error("Database Error: [{0}]", ex);
}
return _RejectionStringList;
}
} }
} }

View File

@ -12,5 +12,7 @@ namespace ZUGFeRDRESTService
public string GetGDPictureKey(); public string GetGDPictureKey();
public List<XmlItemProperty> GetPropertyMapList(); public List<XmlItemProperty> GetPropertyMapList();
public List<RejectionStringRow> GetRejectionMessageList();
} }
} }

View File

@ -1,4 +1,21 @@
{ {
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ZUGFeRDRESTService": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
},
"$schema": "http://json.schemastore.org/launchsettings.json", "$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
@ -7,24 +24,5 @@
"applicationUrl": "http://localhost:52235", "applicationUrl": "http://localhost:52235",
"sslPort": 44388 "sslPort": 44388
} }
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ZUGFeRDRESTService": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/zugferdvalidation",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
} }
} }

View File

@ -6,16 +6,27 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"AllowedHosts": "*",
"Config": { "Config": {
"LogPath": "E:\\ZUGFeRDRESTService", "LogPath": "E:\\ZUGFeRDRESTService",
"LogDebug": true, "LogDebug": true,
"Name": "ZUGFeRD REST API", "Name": "ZUGFeRD REST API",
"MSSQLConnectionString": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM_TEST;User Id=sa;Password=dd;", "MSSQLConnectionString": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;",
"Firebird": { "Firebird": {
"Datasource": "172.24.12.41", "Datasource": "172.24.12.41",
"Database": "172.24.12.41:E:\\DB\\Firebird\\Databases\\EDMI_TEMPLATE\\EDMI_MASTER.FDB", "Database": "172.24.12.41:E:\\DB\\Firebird\\Databases\\EDMI_TEMPLATE\\EDMI_MASTER.FDB",
"Username": "SYSDBA", "Username": "SYSDBA",
"Password": "dd" "Password": "dd"
} },
"Zugferd": {
"AllowZugferd10": true,
"AllowZugferd2x": false,
"AllowZugferd23x": false,
"AllowFacturX": false,
"AllowXRechnung": false,
"AllowPeppolBISBill3x": false
},
"GDPictureVersion": "",
"MaxFileSizeInMegabytes": 25
} }
} }