first working version of zugferd rest service

This commit is contained in:
Jonathan Jenne 2020-03-20 13:48:09 +01:00
parent 3d3a491744
commit 7b3dc1bf89
16 changed files with 336 additions and 111 deletions

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZUGFeRDRESTService
{
public class Config
{
public string Name { get; set; }
public string LogPath { get; set; }
public string MSSQLConnectionString { get; set; }
}
}

View File

@ -0,0 +1,126 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using DigitalData.Modules.Interfaces;
using DigitalData.Modules.Logging;
namespace ZUGFeRDRESTService.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValidationController : ControllerBase
{
public static string RESPONSE_OK = "OK";
public static string RESPONSE_ERROR = "ERROR";
private readonly ZUGFeRDInterface _zugferd;
private readonly IDatabase _database;
private readonly DigitalData.Modules.Logging.LogConfig _logConfig;
private readonly DigitalData.Modules.Logging.Logger _logger;
private readonly PropertyValues _props;
private readonly Dictionary<String, XmlItemProperty> _propertyMap;
public class ValidationResponse
{
public string status;
public string message;
public List<string> errors;
public ValidationResponse()
{
status = RESPONSE_OK;
message = String.Empty;
errors = new List<string>();
}
}
public ValidationController(ILogging logging, IDatabase database)
{
_logConfig = logging.LogConfig;
_logger = _logConfig.GetLogger();
_logger.Debug("Validation Controller initializing");
_database = database;
var oGDPictureKey = database.GetGDPictureKey();
var oPropertyMap = database.GetPropertyMap();
_propertyMap = oPropertyMap;
_zugferd = new ZUGFeRDInterface(_logConfig, oGDPictureKey);
_props = new PropertyValues(_logConfig);
_logger.Debug("Validation Controller initialized!");
}
/// <summary>
/// POST: api/Validation
/// </summary>
/// <param name="files">This parameter's name needs to correspond to the html form's file-input name</param>
[HttpPost]
public async Task<ValidationResponse> Post(IFormFile file, string user_id)
{
string oFilePath;
string oFileName;
oFilePath = Path.Combine(Path.GetTempPath(), file.FileName);
oFileName = file.FileName;
using FileStream oStream = new FileStream(oFilePath, FileMode.Create);
await file.CopyToAsync(oStream);
CrossIndustryDocumentType oDocument;
try
{
oDocument = _zugferd.ExtractZUGFeRDFileWithGDPicture(oFilePath);
}
catch (Exception ex)
{
_logger.Error(ex);
return new ValidationResponse()
{
status = RESPONSE_ERROR,
message = "The uploaded file is not a valid ZUGFeRD Invoice!"
};
}
try
{
PropertyValues.CheckPropertyValuesResult oResult = _props.CheckPropertyValues(oDocument, _propertyMap, "MESSAGEID");
if (oResult.MissingProperties.Count > 0)
{
return new ValidationResponse()
{
status = RESPONSE_ERROR,
message = "The uploaded file is a valid ZUGFeRD Invoice but missing some properties!",
errors = oResult.MissingProperties
};
}
}
catch (Exception ex)
{
_logger.Error(ex);
return new ValidationResponse()
{
status = RESPONSE_ERROR,
message = "The uploaded file is not a valid ZUGFeRD Invoice!"
};
}
return new ValidationResponse()
{
status = RESPONSE_OK,
message = "The uploaded files is a valid ZUGFeRD Invoice!"
};
}
}
}

View File

@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ZUGFeRDRESTService.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ZugferdValidationController : ControllerBase
{
public static string RESPONSE_OK = "OK";
public static string RESPONSE_ERROR = "ERROR";
private readonly IZugferdValidationDataService _dataService;
public class ZugferdValidationResponse
{
public string status;
public string message;
public List<string> errors;
public ZugferdValidationResponse()
{
status = RESPONSE_OK;
message = String.Empty;
errors = new List<string>();
}
}
public ZugferdValidationController(IZugferdValidationDataService dataService)
{
_dataService = dataService;
}
/// <summary>
/// POST: api/ZugferdValidation
/// </summary>
/// <param name="files">This parameter's name needs to correspond to the html form's file-input name</param>
[HttpPost]
public async Task<ZugferdValidationResponse> Post(List<IFormFile> files)
{
var oFilePaths = new List<String>();
var oFileNames = new List<String>();
if (files.Count == 0) {
return new ZugferdValidationResponse()
{
status = RESPONSE_ERROR,
message = "No File received!"
};
}
foreach (var formFile in files)
{
var oFilePath = Path.GetTempFileName();
oFilePaths.Add(oFilePath);
oFileNames.Add(formFile.FileName);
using (var oStream = new FileStream(oFilePath, FileMode.Create))
{
await formFile.CopyToAsync(oStream);
}
}
var oResponse = new ZugferdValidationResponse
{
message = "You uploaded the following file: " + oFileNames.First()
};
return oResponse;
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using DigitalData.Modules.Database;
using DigitalData.Modules.Interfaces;
using Microsoft.Extensions.Configuration;
namespace ZUGFeRDRESTService
{
public class Database: IDatabase
{
private string _gdPictureKey = null;
private Dictionary<String, XmlItemProperty> _propertyMap = null;
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 TBEDM_XML_ITEMS WHERE SPECIFICATION = '{0}' AND ACTIVE = True ORDER BY XML_PATH";
public MSSQLServer MSSQL { get; set; }
public Firebird Firebird { get; set; }
public Database(ILogging Logging, IConfiguration Config)
{
var LogConfig = Logging.LogConfig;
var AppConfig = Config.GetSection("Config");
var FBConfig = AppConfig.GetSection("Firebird");
MSSQL = new MSSQLServer(LogConfig, AppConfig["MSSQLConnectionString"]);
Firebird = new Firebird(LogConfig, FBConfig["Datasource"], FBConfig["Database"], FBConfig["Username"], FBConfig["Password"]);
}
public string GetGDPictureKey()
{
if (_gdPictureKey == null)
_gdPictureKey = MSSQL.GetScalarValue(QUERY_GET_GDPICTURE_KEY).ToString();
return _gdPictureKey;
}
public Dictionary<String, XmlItemProperty> GetPropertyMap()
{
if (_propertyMap == null)
{
_propertyMap = new Dictionary<string, XmlItemProperty>();
var oDatatable = Firebird.GetDatatable(string.Format(QUERY_GET_PROPERTY_MAP, "DEFAULT"));
foreach (DataRow oRow in oDatatable.Rows)
{
_propertyMap.Add(oRow["XML_PATH"].ToString(), new XmlItemProperty()
{
Description = oRow["DESCRIPTION"].ToString(),
TableName = oRow["TABLE_NAME"].ToString(),
GroupScope = oRow["GROUP_SCOPE"].ToString(),
IsRequired = (bool)oRow["IS_REQUIRED"],
IsGrouped = (bool)oRow["IS_GROUPED"]
});
}
}
return _propertyMap;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using DigitalData.Modules.Database;
using DigitalData.Modules.Interfaces;
namespace ZUGFeRDRESTService
{
public interface IDatabase
{
public MSSQLServer MSSQL { get; set; }
public Firebird Firebird { get; set; }
public string GetGDPictureKey();
public Dictionary<String, XmlItemProperty> GetPropertyMap();
}
}

View File

@ -0,0 +1,9 @@
using DigitalData.Modules.Logging;
namespace ZUGFeRDRESTService
{
public interface ILogging
{
public LogConfig LogConfig { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZUGFeRDRESTService
{
public interface IZugferdValidationDataService
{
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZUGFeRDRESTService
{
public sealed class Logger
{
private static readonly Lazy<Logger> lazy = new Lazy<Logger>(() => new Logger());
public static Logger Instance { get { return lazy.Value; } }
private Logger()
{
}
}
}

View File

@ -0,0 +1,15 @@
using DigitalData.Modules.Logging;
namespace ZUGFeRDRESTService
{
internal class Logging : ILogging
{
public LogConfig LogConfig { get; set; }
public Logging(string LogPath, bool Debug)
{
LogConfig = new LogConfig(LogConfig.PathType.CustomPath, LogPath, null, "Digital Data", "ZUGFeRD-REST-API");
LogConfig.Debug = Debug;
}
}
}

View File

@ -3,14 +3,39 @@
ViewData["Title"] = "UploadTest"; ViewData["Title"] = "UploadTest";
} }
<h1>UploadTest</h1> <h1>ZUGFeRD Validation</h1>
<form method="post" action="/api/zugferdvalidation" enctype="multipart/form-data" > <form method="post" action="/api/validation" enctype="multipart/form-data" >
<p> <p>
<span>PDF Datei:</span> <label>PDF Datei:</label>
<input type="file" name="files" /> <input type="file" name="file" required />
</p>
<p>
<label>Benutzerkennung/Email:</label>
<input type="email" name="user_id" required />
</p> </p>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
<style>
form {}
form p {
border-bottom: 1px solid grey;
padding-bottom: 1rem;
}
form label {
display: block;
width: 20rem;
margin-bottom: 1rem;
}
form input {
display: block;
width: 20rem;
}
</style>

View File

@ -6,6 +6,9 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NLog.Web;
using DigitalData.Modules.Logging;
using System.Reflection;
namespace ZUGFeRDRESTService namespace ZUGFeRDRESTService
{ {

View File

@ -12,7 +12,7 @@
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "api/zugferdvalidation", "launchUrl": "",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }

View File

@ -18,16 +18,29 @@ namespace ZUGFeRDRESTService
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration)
{ {
Configuration = configuration; Configuration = configuration;
AppConfig = configuration.GetSection("Config");
} }
public IConfiguration Configuration { get; } public IConfiguration Configuration { get; }
private IConfigurationSection AppConfig { get; }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
string oLogPath = AppConfig["LogPath"];
bool.TryParse(AppConfig["LogDebug"], out bool oLogDebug);
services.AddControllers().AddNewtonsoftJson(); services.AddControllers().AddNewtonsoftJson();
services.AddRazorPages(); services.AddRazorPages();
services.AddTransient<IZugferdValidationDataService, ZugferdValidationDataService>(); services.Configure<Config>(Configuration.GetSection("Config"));
services.AddSingleton<ILogging>(sp => new Logging(oLogPath, oLogDebug));
services.AddSingleton((Func<IServiceProvider, IDatabase>)(sp => {
var logging = sp.GetService<ILogging>();
var config = sp.GetService<IConfiguration>();
return new Database(logging, config);
}));
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -1,12 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FirebirdSql.Data.FirebirdClient" Version="7.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" />
<PackageReference Include="NLog" Version="4.6.8" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Modules.Database\Database.vbproj" />
<ProjectReference Include="..\..\Modules.Interfaces\Interfaces.vbproj" />
<ProjectReference Include="..\..\Modules.Logging\Logging.vbproj" />
</ItemGroup> </ItemGroup>

View File

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ZUGFeRDRESTService
{
public class ZugferdValidationDataService: IZugferdValidationDataService
{
}
}

View File

@ -6,5 +6,17 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Config": {
"LogPath": "E:\\ZUGFeRDRESTService",
"LogDebug": true,
"Name": "ZUGFeRD REST API",
"MSSQLConnectionString": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM_TEST;User Id=sa;Password=dd;",
"Firebird": {
"Datasource": "172.24.12.41",
"Database": "172.24.12.41:E:\\DB\\Firebird\\Databases\\EDMI_TEMPLATE\\EDMI_MASTER.FDB",
"Username": "SYSDBA",
"Password": "dd"
}
}
} }