Skip to content

Commit

Permalink
Merge pull request #100 from FasTnT/develop
Browse files Browse the repository at this point in the history
Prepare version 1.3.0
  • Loading branch information
louisaxel-ambroise committed Oct 4, 2019
2 parents 7785407 + 77be27d commit 63fb4ee
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 28 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ The file `documents\EPCIS Examples - 1.2.postman_collection.json` contains XML r

These database endpoints are only available when the EPCIS server is in Development configuration.

See the [wiki](https://github.com/FasTnT/epcis/wiki) for more details.

## Implemented Features

- Capture
Expand Down Expand Up @@ -74,4 +76,4 @@ This project is licensed under the Apache 2.0 license - see the LICENSE file for

Contact: fastnt@pm.me

_Last update: september 2019_
_Last update: October 2019_
2 changes: 1 addition & 1 deletion src/FasTnT.Domain/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace FasTnT.Domain
public static class Constants
{
public static string StandardVersion = "1.2";
public static string ProductVersion = "1.2.0";
public static string ProductVersion = "1.3.0";
public static int SubscriptionTaskDelayTimeoutInMs = 5000;
}
}
2 changes: 1 addition & 1 deletion src/FasTnT.Formatters.Json/FasTnT.Formatters.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<ItemGroup>
<PackageReference Include="morelinq" Version="3.2.0" />
<PackageReference Include="NJsonSchema" Version="10.0.23" />
<PackageReference Include="NJsonSchema" Version="10.0.24" />
</ItemGroup>

<ItemGroup>
Expand Down
51 changes: 36 additions & 15 deletions src/FasTnT.Formatters.Xml/Formatters/XmlEventFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public XmlEventFormatter()
{
eventBuilder = new Dictionary<EventType, FormatAction[]>
{
{ EventType.Object, new FormatAction[]{ EpcListMandatory, Action, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, ExtensionIlmd, SourceDest, AddExtensionField, AddEventExtension } },
{ EventType.Quantity, new FormatAction[]{ QuantityEpc, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDest, AddExtensionField, AddEventExtension } },
{ EventType.Aggregation, new FormatAction[]{ ParentId, ChildEpcs, Action, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDest, AddExtensionField, AddEventExtension } },
{ EventType.Transaction, new FormatAction[]{ BizTransaction, EpcList, Action, BizStep, Disposition, ReadPoint, BizLocation, SourceDest, AddExtensionField, AddEventExtension } },
{ EventType.Transformation, new FormatAction[]{ EpcList, TransformationId, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDest, Ilmd, AddExtensionField, AddEventExtension } },
{ EventType.Object, new FormatAction[]{ EpcListMandatory, Action, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, ExtensionIlmd, SourceDestExt, AddExtensionField, AddEventExtension } },
{ EventType.Quantity, new FormatAction[]{ QuantityEpc, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDestExt, AddExtensionField, AddEventExtension } },
{ EventType.Aggregation, new FormatAction[]{ ParentId, ChildEpcs, Action, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDestExt, AddExtensionField, AddEventExtension } },
{ EventType.Transaction, new FormatAction[]{ BizTransaction, EpcList, Action, BizStep, Disposition, ReadPoint, BizLocation, SourceDestExt, AddExtensionField, AddEventExtension } },
{ EventType.Transformation, new FormatAction[]{ EpcList, TransformationId, BizStep, Disposition, ReadPoint, BizLocation, BizTransaction, SourceDestRoot, Ilmd, AddExtensionField, AddEventExtension } },
};
}

Expand All @@ -46,17 +46,27 @@ private XElement CreateEvent(EpcisEvent @event)
element.Add(new XElement("eventTime", @event.EventTime.ToString(DateTimeFormat, CultureInfo.InvariantCulture)));
element.Add(new XElement("recordTime", @event.CaptureTime.ToString(DateTimeFormat)));
element.Add(new XElement("eventTimeZoneOffset", @event.EventTimeZoneOffset.Representation));
if (@event.ErrorDeclaration != null) AddErrorDeclaration(@event.ErrorDeclaration, element);
if (!string.IsNullOrEmpty(@event.EventId)) element.Add(new XElement("eventID", @event.EventId));
if (@event.ErrorDeclaration != null || !string.IsNullOrEmpty(@event.EventId)) AddErrorDeclaration(@event, element);

return element;
}

private void AddErrorDeclaration(ErrorDeclaration eventError, XElement element)
private void AddErrorDeclaration(EpcisEvent @event, XElement element)
{
var correctiveEventIds = eventError.CorrectiveEventIds.Any() ? new XElement("correctiveEventIDs", eventError.CorrectiveEventIds.Select(x => new XElement("correctiveEventId", x.CorrectiveId))) : null;
var errorDeclaration = new XElement("errorDeclaration", new XElement("declarationTime", eventError.DeclarationTime), new XElement("reason", eventError.Reason), correctiveEventIds);
element.Add(new XElement("baseExtension", errorDeclaration));
XElement errorDeclaration = default, eventId = default;
if (@event.ErrorDeclaration != null)
{
var correctiveEventIds = @event.ErrorDeclaration.CorrectiveEventIds.Any() ? new XElement("correctiveEventIDs", @event.ErrorDeclaration.CorrectiveEventIds.Select(x => new XElement("correctiveEventID", x.CorrectiveId))) : null;
errorDeclaration = new XElement("errorDeclaration", new XElement("declarationTime", @event.ErrorDeclaration.DeclarationTime), new XElement("reason", @event.ErrorDeclaration.Reason), correctiveEventIds);
}

if (!string.IsNullOrEmpty(@event.EventId))
{
eventId = new XElement("eventID", @event.EventId);
}


element.Add(new XElement("baseExtension", eventId, errorDeclaration));
}

public void EpcListMandatory(EpcisEvent evt, XContainer element) => EpcList(evt, element, true);
Expand All @@ -75,8 +85,8 @@ public void EpcList(EpcisEvent evt, XContainer element, bool mandatoryEpcList)
if (inputEpcList.HasElements) element.Add(inputEpcList);
if (inputQuantity.HasElements) element.Add(inputQuantity);
if (quantityList.HasElements) AddInExtension(element, quantityList);
if (outputQuantity.HasElements) element.Add(outputQuantity);
if (outputEpcList.HasElements) element.Add(outputEpcList);
if (outputQuantity.HasElements) element.Add(outputQuantity);
}

public void QuantityEpc(EpcisEvent evt, XContainer element)
Expand Down Expand Up @@ -116,7 +126,7 @@ public void TransformationId(EpcisEvent evt, XContainer container)
if (!string.IsNullOrEmpty(evt.TransformationId)) container.Add(new XElement("transformationID", evt.TransformationId));
}

private void SourceDest(EpcisEvent @event, XContainer element)
private void InternalSourceDest(EpcisEvent @event, XContainer element, bool wrapInExtension = true)
{
if (@event.SourceDestinationList == null || !@event.SourceDestinationList.Any()) return;

Expand All @@ -131,10 +141,21 @@ private void SourceDest(EpcisEvent @event, XContainer element)
destination.Add(new XElement("destination", new XAttribute("type", sourceDest.Type), sourceDest.Id));
}

if (source.HasElements) AddInExtension(element, source);
if (destination.HasElements) AddInExtension(element, destination);
if (source.HasElements)
{
if (wrapInExtension) AddInExtension(element, source);
else element.Add(source);
}
if (destination.HasElements)
{
if(wrapInExtension) AddInExtension(element, destination);
else element.Add(destination);
}
}

private void SourceDestRoot(EpcisEvent @event, XContainer element) => InternalSourceDest(@event, element, false);
private void SourceDestExt(EpcisEvent @event, XContainer element) => InternalSourceDest(@event, element, true);

private void BizTransaction(EpcisEvent @event, XContainer element)
{
if (@event.BusinessTransactions == null || !@event.BusinessTransactions.Any()) return;
Expand Down
54 changes: 53 additions & 1 deletion src/FasTnT.Formatters.Xml/Parsers/XmlHeaderParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,62 @@ internal static StandardBusinessHeader Parse(XElement element)
Type = documentIdentification.Element(XName.Get("Type", EpcisNamespaces.SBDH))?.Value,
TypeVersion = documentIdentification.Element(XName.Get("TypeVersion", EpcisNamespaces.SBDH))?.Value,
InstanceIdentifier = documentIdentification.Element(XName.Get("InstanceIdentifier", EpcisNamespaces.SBDH))?.Value,
ContactInformations = ParseContacts(element.Elements(XName.Get("Sender", EpcisNamespaces.SBDH))).Union(ParseContacts(element.Elements(XName.Get("Receiver", EpcisNamespaces.SBDH)))).ToList()
ContactInformations = ParseContacts(element.Elements(XName.Get("Sender", EpcisNamespaces.SBDH))).Union(ParseContacts(element.Elements(XName.Get("Receiver", EpcisNamespaces.SBDH)))).ToList(),
};
}

internal static List<CustomField> ParseCustomFields(XElement element)
{
var customFields = new List<CustomField>();
var elements = element?.Elements().Where(x => x.Name.Namespace != XNamespace.Xmlns && x.Name.Namespace != XNamespace.None && x.Name.Namespace != EpcisNamespaces.SBDH && x.Name.Namespace != null);

foreach (var field in elements ?? new XElement[0])
{
customFields.Add(ParseCustomField(field));
}

return customFields;
}

private static CustomField ParseCustomField(XElement element)
{
var field = new CustomField
{
Type = FieldType.HeaderExtension,
Name = element.Name.LocalName,
Namespace = element.Name.NamespaceName,
TextValue = element.HasElements ? null : element.Value,
NumericValue = element.HasElements ? null : double.TryParse(element.Value, out double doubleValue) ? doubleValue : default(double?),
DateValue = element.HasElements ? null : DateTime.TryParse(element.Value, out DateTime dateValue) ? dateValue : default(DateTime?),
};

if (element.HasElements)
{
foreach (var children in element.Elements())
{
var childrenField = ParseCustomField(children);
field.Children.Add(childrenField);
}
}

foreach (var attribute in element.Attributes().Where(a => a.Name.LocalName != "xmlns"))
{
var attributeField = new CustomField
{
Type = FieldType.Attribute,
Name = attribute.Name.LocalName,
Namespace = attribute.Name.Namespace.NamespaceName,
TextValue = attribute.Value,
NumericValue = element.HasElements ? null : double.TryParse(element.Value, out double doubleVal) ? doubleVal : default(double?),
DateValue = element.HasElements ? null : DateTime.TryParse(element.Value, out DateTime dateVal) ? dateVal : default(DateTime?),
};

field.Children.Add(attributeField);
}

return field;
}

private static IEnumerable<ContactInformation> ParseContacts(IEnumerable<XElement> elements)
{
return elements.Select(e => new ContactInformation
Expand Down
3 changes: 2 additions & 1 deletion src/FasTnT.Formatters.Xml/XmlRequestFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ private EpcisRequestHeader ParseHeader(XElement root)
{
StandardBusinessHeader = XmlHeaderParser.Parse(root.XPathSelectElement("EPCISHeader/sbdh:StandardBusinessDocumentHeader", EpcisNamespaces.Manager)),
DocumentTime = DateTime.Parse(root.Attribute("creationDate").Value, CultureInfo.InvariantCulture),
SchemaVersion = root.Attribute("schemaVersion").Value
SchemaVersion = root.Attribute("schemaVersion").Value,
CustomFields = XmlHeaderParser.ParseCustomFields(root.XPathSelectElement("EPCISHeader"))
};
}

Expand Down
1 change: 1 addition & 0 deletions src/FasTnT.Model/Events/Enums/FieldType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class FieldType : Enumeration
public static FieldType ReadPointExtension = new FieldType(3, "ReadPointExtension");
public static FieldType Attribute = new FieldType(4, "Attribute");
public static FieldType BusinessLocationExtension = new FieldType(5, "BusinessLocationExtension");
public static FieldType HeaderExtension = new FieldType(6, "HeaderExtension");

public FieldType() { }
public FieldType(short id, string displayName) : base(id, displayName) { }
Expand Down
2 changes: 2 additions & 0 deletions src/FasTnT.Model/Events/EpcisRequestHeader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

namespace FasTnT.Model
{
Expand All @@ -8,5 +9,6 @@ public class EpcisRequestHeader
public DateTime DocumentTime { get; set; }
public DateTime RecordTime { get; set; } = DateTime.UtcNow;
public string SchemaVersion { get; set; }
public List<CustomField> CustomFields { get; set; } = new List<CustomField>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="1.60.6" />
<PackageReference Include="Dapper.SqlBuilder" Version="1.60.1" />
<PackageReference Include="Dapper" Version="2.0.30" />
<PackageReference Include="Dapper.SqlBuilder" Version="2.0.30" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0-preview4.19216.2" />
<PackageReference Include="Npgsql" Version="4.0.8" />
<PackageReference Include="Npgsql" Version="4.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
26 changes: 25 additions & 1 deletion src/FasTnT.Persistence.Dapper/PgSqlRequestManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FasTnT.Domain.Persistence;
Expand All @@ -19,6 +21,7 @@ public async Task<int> Store(EpcisRequestHeader request, User user, Cancellation
var epcisRequest = ModelMapper.Map<EpcisRequestHeader, RequestHeaderEntity>(request, r => { r.UserId = user?.Id; });
epcisRequest.Id = await _unitOfWork.Store(PgSqlRequestRequests.Store, epcisRequest, cancellationToken);
await StoreStandardBusinessHeader(request, epcisRequest, cancellationToken);
await StoreCustomFields(request, epcisRequest, cancellationToken);

return epcisRequest.Id;
}
Expand All @@ -33,5 +36,26 @@ private async Task StoreStandardBusinessHeader(EpcisRequestHeader request, Reque
await _unitOfWork.Execute(PgSqlRequestRequests.StoreStandardHeader, header, cancellationToken);
await _unitOfWork.BulkExecute(PgSqlRequestRequests.StoreStandardHeaderContactInformations, contactInformations, cancellationToken);
}

private async Task StoreCustomFields(EpcisRequestHeader request, RequestHeaderEntity epcisRequest, CancellationToken cancellationToken)
{
var fields = new List<CustomFieldEntity>();
ParseFields(request.CustomFields, epcisRequest.Id, fields);

await _unitOfWork.BulkExecute(PgSqlRequestRequests.StoreCustomFields, fields, cancellationToken);
}

private static void ParseFields(IList<CustomField> customFields, int eventId, List<CustomFieldEntity> mappedList, int? parentId = null)
{
if (customFields == null || !customFields.Any()) return;

foreach (var field in customFields)
{
var entity = field.Map<CustomField, CustomFieldEntity>(f => { f.EventId = eventId; f.Id = mappedList.Count; f.ParentId = parentId; });
mappedList.Add(entity);

ParseFields(field.Children, eventId, mappedList, entity.Id);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/FasTnT.Persistence.Dapper/PgSqlRequestRequests.resx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
<data name="Store" xml:space="preserve">
<value>INSERT INTO epcis.request(document_time, record_time, user_id) VALUES(@documenttime, @recordtime, @userid) RETURNING id;</value>
</data>
<data name="StoreCustomFields" xml:space="preserve">
<value>INSERT INTO sbdh.custom_field(header_id, field_id, parent_id, namespace, name, type, text_value, numeric_value, date_value) VALUES (@eventid, @id, @parentid, @namespace, @name, @type, @textvalue, @numericvalue, @datevalue) ...;</value>
</data>
<data name="StoreStandardHeader" xml:space="preserve">
<value>INSERT INTO sbdh.standardheader(id, version, standard, type_version, identifier, type, creation_datetime) VALUES(@id, @version, @standard, @typeversion, @instanceidentifier, @type, @creationdatetime);</value>
</data>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 63fb4ee

Please sign in to comment.