From 73e8e640bea209f4ab79b3156a75b54bc9a09851 Mon Sep 17 00:00:00 2001 From: konstantin Date: Wed, 31 Jan 2024 14:07:06 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E2=9C=A8=20convert=20EDIFACT=20?= =?UTF-8?q?=E2=9E=A1=20BO4E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EdifactToBo4eTests.cs | 32 +++++++++++++ .../TestEdifacts/FV2310/55001.edi | 34 +++++++++++++ ...ransformerBeeClient.IntegrationTest.csproj | 6 +++ .../TransformerBeeClient.sln.DotSettings.user | 3 +- .../TransformerBeeClient/Interfaces.cs | 19 ++++++++ .../TransformerBeeClient/Model/BOneyComb.cs | 26 ++++++++++ .../Model/EdifactToBo4eRequest.cs | 29 +++++++++++ .../Model/EdifactToBo4eResponse.cs | 23 +++++++++ .../Model/Marktnachricht.cs | 32 +++++++++++++ .../TransformerBeeClient/RestClient.cs | 48 ++++++++++++++++++- .../TransformerBeeClient.csproj | 2 + .../TransformerBeeClient/Utils.cs | 17 +++++++ 12 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs create mode 100644 TransformerBeeClient/TransformerBeeClient.IntegrationTest/TestEdifacts/FV2310/55001.edi create mode 100644 TransformerBeeClient/TransformerBeeClient/Interfaces.cs create mode 100644 TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs create mode 100644 TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs create mode 100644 TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs create mode 100644 TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs create mode 100644 TransformerBeeClient/TransformerBeeClient/Utils.cs diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs new file mode 100644 index 0000000..7be401e --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/EdifactToBo4eTests.cs @@ -0,0 +1,32 @@ +using EDILibrary; +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using TransformerBeeClient.Model; +using Xunit; + +namespace TransformerBeeClient.IntegrationTest; + +/// +/// Tests that a edifact can be converted to bo4e +/// +public class EdifactToBo4eTests : IClassFixture +{ + + private readonly ClientFixture _client; + + public EdifactToBo4eTests(ClientFixture clientFixture) + { + _client = clientFixture; + } + + [Fact] + public async Task Edifact_Can_Be_Converted_To_Bo4e() + { + var httpClientFactory = _client.HttpClientFactory; + ICanConvertToBo4e client = new TransformerBeeRestClient(httpClientFactory); + var edifactString = await File.ReadAllTextAsync("TestEdifacts/FV2310/55001.edi"); + var result = await client.ConvertToBo4e(edifactString, EdifactFormatVersion.FV2310); + result.Should().BeOfType>(); + result.Single().Transaktionen.Should().NotBeNullOrEmpty(); + } +} diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TestEdifacts/FV2310/55001.edi b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TestEdifacts/FV2310/55001.edi new file mode 100644 index 0000000..d8939e5 --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TestEdifacts/FV2310/55001.edi @@ -0,0 +1,34 @@ +UNA:+,? ' +UNB+UNOC:3+9912345789012:500+9909876543210:500+230703:1059+ASDFHGJ' +UNH+11223344556678+UTILMD:D:11A:UN:S1.1' +BGM+E01+918273746512345678901' +DTM+137:202306300558?+00:303' +NAD+MS+9912345789012::293' +NAD+MR+9909876543210::293' +IDE+24+918273746512345678901' +IMD++Z36+Z13' +DTM+92:202212312300?+00:303' +STS+7++E01' +LOC+Z16+78889918283' +LOC+Z17+DE0000111122223333444455556667778' +RFF+Z13:55001' +SEQ+Z01' +CCI+Z30++Z07' +CCI+Z19++11X0-0000-0116-J' +CCI+++Z15' +CCI+++Z88' +CAV+Z74:::Z09' +CAV+Z73:::Z11' +SEQ+Z12' +QTY+Z16:0:P1' +SEQ+Z03' +CCI+++E13' +CAV+Z30:::788811123' +SEQ+Z75' +CCI+Z61++ZG1' +NAD+Z09+++Schaefer:Ulrike:::Frau:Z01' +NAD+Z04+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247 +DE' +NAD+DP++++Flughafenstrasse::64+Vilseck++92247+DE' +NAD+Z05+++Schaefer:Ulrike:::Frau:Z01+Flughafenstrasse::64+Vilseck++92247 +DE' +UNT+31+11223344556678' +UNZ+1+ASDFHGJ' diff --git a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj index 7bcda48..216ac56 100644 --- a/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj +++ b/TransformerBeeClient/TransformerBeeClient.IntegrationTest/TransformerBeeClient.IntegrationTest.csproj @@ -22,4 +22,10 @@ /> + + + Always + + + diff --git a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user index 3afa14e..1e7aa60 100644 --- a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user +++ b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user @@ -1,6 +1,7 @@ - + <SessionState ContinuousTestingMode="0" IsActive="True" Name="ConnectionTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> <TestId>xUnit::80EF1570-CB4E-4E56-A8BC-56C787A48543::net8.0::TransformerBeeClient.UnitTest.ConnectionTests</TestId> + <TestId>xUnit::77598126-7BB0-4C07-BF06-331033E0DE78::net8.0::TransformerBeeClient.IntegrationTest.EdifactToBo4eTests.Edifact_Shall_Be_Converted_To_Bo4e</TestId> </TestAncestor> </SessionState> \ No newline at end of file diff --git a/TransformerBeeClient/TransformerBeeClient/Interfaces.cs b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs new file mode 100644 index 0000000..ba950ef --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs @@ -0,0 +1,19 @@ +using EDILibrary; +using TransformerBeeClient.Model; + +namespace TransformerBeeClient; + +/// +/// Interface of all the things that can convert EDIFACT to BO4E +/// +/// This will be useful if you want to mock the client elsewhere +public interface ICanConvertToBo4e +{ + /// + /// convert an edifact to BO4E + /// + /// edifact message as string + /// + /// + public Task> ConvertToBo4e(string edifact, EdifactFormatVersion formatVersion); +} diff --git a/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs b/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs new file mode 100644 index 0000000..4245157 --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; +using BO4E.BO; +using Newtonsoft.Json; + +namespace TransformerBeeClient.Model; + +/// +/// BOneyComb is a data structure that represents a "transaction" in the marktkommunikation. +/// 1 transaction = 1 Geschäftsvorfall +/// +public class BOneyComb +{ + /// + /// the business objects + /// + [JsonPropertyName("stammdaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonProperty(PropertyName = "stammdaten")] + public List Stammdaten { get; set; } + + /// + /// Transaktionsdaten are metadata related to the Marktprozess and are not related to a specific Business object. + /// + [JsonPropertyName("transaktionsdaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonProperty(PropertyName = "transaktionsdaten")] + public Dictionary Transaktionsdaten { get; set; } +} diff --git a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs new file mode 100644 index 0000000..dab9fdc --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs @@ -0,0 +1,29 @@ +using EDILibrary; + +namespace TransformerBeeClient.Model; + +/// +/// The request to convert edifact to bo4e +/// +internal class EdifactToBo4eRequest +{ + // internally we only use system.text, no newtonsoft + + /// + /// the edifact as plain string + /// + [System.Text.Json.Serialization.JsonPropertyName("EDI")] + public string Edifact { get; set; } + + /// + /// the format version to use + /// + [System.Text.Json.Serialization.JsonPropertyName("FormatPackage")] + public EdifactFormatVersion FormatVersion { get; set; } + + /// + /// legacy for MP. can be false by default + /// + [System.Text.Json.Serialization.JsonPropertyName("UseMap")] + public bool UseMap { get; set; } = false; +} diff --git a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs new file mode 100644 index 0000000..4103e4a --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs @@ -0,0 +1,23 @@ +using EDILibrary; + +namespace TransformerBeeClient.Model; + +/// +/// The response to a +/// +internal class EdifactToBo4eResponse +{ + // internally we only use system.text, no newtonsoft + + /// + /// the bo4e as plain json string + /// + [System.Text.Json.Serialization.JsonPropertyName("BO4E")] + public string Bo4eJsonString { get; set; } + + /// + /// the format version that was used + /// + [System.Text.Json.Serialization.JsonPropertyName("FormatPackage")] + public EdifactFormatVersion FormatVersion { get; set; } +} diff --git a/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs new file mode 100644 index 0000000..d6b3714 --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; +using Newtonsoft.Json; + +namespace TransformerBeeClient.Model; + +/// +/// A marktnachricht contains of 1 or more s +/// +/// E.g. a UTILMD message with more than 1 IDE contains multiple transactions +public class Marktnachricht +{ + /// + /// the UNH (interchange header) of the message + /// + [JsonPropertyName("UNH")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonProperty(PropertyName = "UNH")] + public string? UNH { get; set; } + + /// + /// One marktnachricht contains at least 1 transaction aka BOneyComb + /// + [JsonPropertyName("transaktionen")]// we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonProperty(PropertyName = "transaktionen")] + public List Transaktionen { get; set; } + + /// + /// Nachrichtendaten are similar to but are not 100% identical. + /// + [JsonPropertyName("nachrichtendaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so + [JsonProperty(PropertyName = "nachrichtendaten")] + public Dictionary Nachrichtendaten { get; set; } +} diff --git a/TransformerBeeClient/TransformerBeeClient/RestClient.cs b/TransformerBeeClient/TransformerBeeClient/RestClient.cs index fe3440f..15b29c8 100644 --- a/TransformerBeeClient/TransformerBeeClient/RestClient.cs +++ b/TransformerBeeClient/TransformerBeeClient/RestClient.cs @@ -1,11 +1,22 @@ +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using EDILibrary; +using TransformerBeeClient.Model; + namespace TransformerBeeClient; /// /// a client for the transformer.bee REST API /// -public class TransformerBeeRestClient +public class TransformerBeeRestClient : ICanConvertToBo4e { private readonly HttpClient _httpClient; + private readonly JsonSerializerOptions _jsonSerializerOptions = new() + { + PropertyNameCaseInsensitive = true, + Converters = { new JsonStringEnumConverter() } + }; /// /// Provide the constructor with a http client factory. @@ -43,4 +54,39 @@ public async Task IsAvailable() var response = await _httpClient.GetAsync(versionUrl); return response.IsSuccessStatusCode; } + + /// + /// convert an edifact to BO4E + /// + /// edifact message as string + /// + /// + /// + public async Task> ConvertToBo4e(string edifact, EdifactFormatVersion formatVersion) + { + var uriBuilder = new UriBuilder(_httpClient!.BaseAddress) + { + Path = "/v1/transformer/EdiToBo4E" + }; + + var convertUrl = uriBuilder.Uri.AbsoluteUri; + var request = new EdifactToBo4eRequest + { + Edifact = edifact, + FormatVersion = formatVersion, + }; + var requestJson = JsonSerializer.Serialize(request, _jsonSerializerOptions); + var httpResponse = await _httpClient.PostAsync(convertUrl, new StringContent(requestJson, Encoding.UTF8, "application/json")); + if (!httpResponse.IsSuccessStatusCode) + { + throw new HttpRequestException($"Could not convert {edifact} to BO4E. Status code: {httpResponse.StatusCode}"); + } + var responseContent = await httpResponse.Content.ReadAsStringAsync(); + var bo4eResponse = JsonSerializer.Deserialize(responseContent, _jsonSerializerOptions); + // todo: handle the case that the deserialization fails and bo4eResponse is null + var unescapedJson = bo4eResponse!.Bo4eJsonString.Unescape(); + var result = JsonSerializer.Deserialize>(unescapedJson, _jsonSerializerOptions); + // todo: handle the case that the deserialization fails and result is null + return result; + } } diff --git a/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj b/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj index 6ca9de3..42d5454 100644 --- a/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj +++ b/TransformerBeeClient/TransformerBeeClient/TransformerBeeClient.csproj @@ -11,6 +11,8 @@ + + diff --git a/TransformerBeeClient/TransformerBeeClient/Utils.cs b/TransformerBeeClient/TransformerBeeClient/Utils.cs new file mode 100644 index 0000000..c900f30 --- /dev/null +++ b/TransformerBeeClient/TransformerBeeClient/Utils.cs @@ -0,0 +1,17 @@ +namespace TransformerBeeClient; + +/// +/// Utility extension methods +/// +internal static class Utils +{ + /// + /// revert the escaping of the converter + /// + /// + /// + internal static string Unescape(this string s) + { + return s.Replace("\\n", "\n"); + } +} From 0e28cb679e54d6c158afe0c8bded384f45b243f9 Mon Sep 17 00:00:00 2001 From: konstantin Date: Wed, 31 Jan 2024 14:08:30 +0000 Subject: [PATCH 2/2] boms --- TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user | 2 +- TransformerBeeClient/TransformerBeeClient/Interfaces.cs | 2 +- TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs | 2 +- .../TransformerBeeClient/Model/EdifactToBo4eRequest.cs | 2 +- .../TransformerBeeClient/Model/EdifactToBo4eResponse.cs | 2 +- .../TransformerBeeClient/Model/Marktnachricht.cs | 2 +- TransformerBeeClient/TransformerBeeClient/Utils.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user index 1e7aa60..a6c2e69 100644 --- a/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user +++ b/TransformerBeeClient/TransformerBeeClient.sln.DotSettings.user @@ -1,4 +1,4 @@ - + <SessionState ContinuousTestingMode="0" IsActive="True" Name="ConnectionTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> <TestId>xUnit::80EF1570-CB4E-4E56-A8BC-56C787A48543::net8.0::TransformerBeeClient.UnitTest.ConnectionTests</TestId> diff --git a/TransformerBeeClient/TransformerBeeClient/Interfaces.cs b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs index ba950ef..4c18919 100644 --- a/TransformerBeeClient/TransformerBeeClient/Interfaces.cs +++ b/TransformerBeeClient/TransformerBeeClient/Interfaces.cs @@ -1,4 +1,4 @@ -using EDILibrary; +using EDILibrary; using TransformerBeeClient.Model; namespace TransformerBeeClient; diff --git a/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs b/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs index 4245157..2c8e2ca 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs @@ -1,4 +1,4 @@ -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; using BO4E.BO; using Newtonsoft.Json; diff --git a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs index dab9fdc..c7d8dcd 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eRequest.cs @@ -1,4 +1,4 @@ -using EDILibrary; +using EDILibrary; namespace TransformerBeeClient.Model; diff --git a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs index 4103e4a..e7c8b0f 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/EdifactToBo4eResponse.cs @@ -1,4 +1,4 @@ -using EDILibrary; +using EDILibrary; namespace TransformerBeeClient.Model; diff --git a/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs index d6b3714..6a5e948 100644 --- a/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs +++ b/TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs @@ -1,4 +1,4 @@ -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; using Newtonsoft.Json; namespace TransformerBeeClient.Model; diff --git a/TransformerBeeClient/TransformerBeeClient/Utils.cs b/TransformerBeeClient/TransformerBeeClient/Utils.cs index c900f30..06651f8 100644 --- a/TransformerBeeClient/TransformerBeeClient/Utils.cs +++ b/TransformerBeeClient/TransformerBeeClient/Utils.cs @@ -1,4 +1,4 @@ -namespace TransformerBeeClient; +namespace TransformerBeeClient; /// /// Utility extension methods