Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using EDILibrary;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using TransformerBeeClient.Model;
using Xunit;

namespace TransformerBeeClient.IntegrationTest;

/// <summary>
/// Tests that a edifact can be converted to bo4e
/// </summary>
public class EdifactToBo4eTests : IClassFixture<ClientFixture>
{

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<List<Marktnachricht>>();
result.Single().Transaktionen.Should().NotBeNullOrEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -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'
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@
/>
</ItemGroup>

<ItemGroup>
<None Update="TestEdifacts\FV2310\55001.edi">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=de4efd69_002D9f4a_002D4e00_002D83fa_002Ddaa381865bd8/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="ConnectionTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::80EF1570-CB4E-4E56-A8BC-56C787A48543::net8.0::TransformerBeeClient.UnitTest.ConnectionTests&lt;/TestId&gt;&#xD;
&lt;TestId&gt;xUnit::77598126-7BB0-4C07-BF06-331033E0DE78::net8.0::TransformerBeeClient.IntegrationTest.EdifactToBo4eTests.Edifact_Shall_Be_Converted_To_Bo4e&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>
19 changes: 19 additions & 0 deletions TransformerBeeClient/TransformerBeeClient/Interfaces.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using EDILibrary;
using TransformerBeeClient.Model;

namespace TransformerBeeClient;

/// <summary>
/// Interface of all the things that can convert EDIFACT to BO4E
/// </summary>
/// <remarks>This will be useful if you want to mock the client elsewhere</remarks>
public interface ICanConvertToBo4e
{
/// <summary>
/// convert an edifact to BO4E
/// </summary>
/// <param name="edifact">edifact message as string</param>
/// <param name="formatVersion"><see cref="EdifactFormatVersion"/></param>
/// <returns><see cref="Marktnachricht"/></returns>
public Task<List<Marktnachricht>> ConvertToBo4e(string edifact, EdifactFormatVersion formatVersion);
}
26 changes: 26 additions & 0 deletions TransformerBeeClient/TransformerBeeClient/Model/BOneyComb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Text.Json.Serialization;
using BO4E.BO;
using Newtonsoft.Json;

namespace TransformerBeeClient.Model;

/// <summary>
/// BOneyComb is a data structure that represents a "transaction" in the marktkommunikation.
/// 1 transaction = 1 Geschäftsvorfall
/// </summary>
public class BOneyComb
{
/// <summary>
/// the business objects
/// </summary>
[JsonPropertyName("stammdaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so
[JsonProperty(PropertyName = "stammdaten")]
public List<BusinessObject> Stammdaten { get; set; }

/// <summary>
/// Transaktionsdaten are metadata related to the Marktprozess and are not related to a specific Business object.
/// </summary>
[JsonPropertyName("transaktionsdaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so
[JsonProperty(PropertyName = "transaktionsdaten")]
public Dictionary<string, string> Transaktionsdaten { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using EDILibrary;

namespace TransformerBeeClient.Model;

/// <summary>
/// The request to convert edifact to bo4e
/// </summary>
internal class EdifactToBo4eRequest
{
// internally we only use system.text, no newtonsoft

/// <summary>
/// the edifact as plain string
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("EDI")]
public string Edifact { get; set; }

/// <summary>
/// the format version to use
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("FormatPackage")]
public EdifactFormatVersion FormatVersion { get; set; }

/// <summary>
/// legacy for MP. can be false by default
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("UseMap")]
public bool UseMap { get; set; } = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using EDILibrary;

namespace TransformerBeeClient.Model;

/// <summary>
/// The response to a <see cref="EdifactToBo4eRequest"/>
/// </summary>
internal class EdifactToBo4eResponse
{
// internally we only use system.text, no newtonsoft

/// <summary>
/// the bo4e as plain json string
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("BO4E")]
public string Bo4eJsonString { get; set; }

/// <summary>
/// the format version that was used
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("FormatPackage")]
public EdifactFormatVersion FormatVersion { get; set; }
}
32 changes: 32 additions & 0 deletions TransformerBeeClient/TransformerBeeClient/Model/Marktnachricht.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json.Serialization;
using Newtonsoft.Json;

namespace TransformerBeeClient.Model;

/// <summary>
/// A marktnachricht contains of 1 or more <see cref="BOneyComb"/>s
/// </summary>
/// <remarks>E.g. a UTILMD message with more than 1 IDE contains multiple transactions</remarks>
public class Marktnachricht
{
/// <summary>
/// the UNH (interchange header) of the message
/// </summary>
[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; }

/// <summary>
/// One marktnachricht contains at least 1 transaction aka BOneyComb
/// </summary>
[JsonPropertyName("transaktionen")]// we want to support both System.Text and Newtonsoft as long as BO4E.net does so
[JsonProperty(PropertyName = "transaktionen")]
public List<BOneyComb> Transaktionen { get; set; }

/// <summary>
/// Nachrichtendaten are similar to <see cref="BOneyComb.Transaktionsdaten"/> but are not 100% identical.
/// </summary>
[JsonPropertyName("nachrichtendaten")] // we want to support both System.Text and Newtonsoft as long as BO4E.net does so
[JsonProperty(PropertyName = "nachrichtendaten")]
public Dictionary<string, string> Nachrichtendaten { get; set; }
}
48 changes: 47 additions & 1 deletion TransformerBeeClient/TransformerBeeClient/RestClient.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using EDILibrary;
using TransformerBeeClient.Model;

namespace TransformerBeeClient;

/// <summary>
/// a client for the transformer.bee REST API
/// </summary>
public class TransformerBeeRestClient
public class TransformerBeeRestClient : ICanConvertToBo4e
{
private readonly HttpClient _httpClient;
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
Converters = { new JsonStringEnumConverter() }
};

/// <summary>
/// Provide the constructor with a http client factory.
Expand Down Expand Up @@ -43,4 +54,39 @@ public async Task<bool> IsAvailable()
var response = await _httpClient.GetAsync(versionUrl);
return response.IsSuccessStatusCode;
}

/// <summary>
/// convert an edifact to BO4E
/// </summary>
/// <param name="edifact">edifact message as string</param>
/// <param name="formatVersion"><see cref="EdifactFormatVersion"/></param>
/// <returns><see cref="Marktnachricht"/></returns>
/// <exception cref="HttpRequestException"></exception>
public async Task<List<Marktnachricht>> 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<EdifactToBo4eResponse>(responseContent, _jsonSerializerOptions);
// todo: handle the case that the deserialization fails and bo4eResponse is null
var unescapedJson = bo4eResponse!.Bo4eJsonString.Unescape();
var result = JsonSerializer.Deserialize<List<Marktnachricht>>(unescapedJson, _jsonSerializerOptions);
// todo: handle the case that the deserialization fails and result is null
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="EDILibrary.Core" Version="1.5.9" />
<PackageReference Include="Hochfrequenz.BO4Enet" Version="0.2.147" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
</ItemGroup>

Expand Down
17 changes: 17 additions & 0 deletions TransformerBeeClient/TransformerBeeClient/Utils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace TransformerBeeClient;

/// <summary>
/// Utility extension methods
/// </summary>
internal static class Utils
{
/// <summary>
/// revert the escaping of the converter
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
internal static string Unescape(this string s)
{
return s.Replace("\\n", "\n");
}
}