Giter VIP home page Giter VIP logo

Comments (17)

Nekeniehl avatar Nekeniehl commented on September 15, 2024

Hi there, in my poor understanding of the EdiAttributes, the EdiSegmentGroup is treated as EdiSegment, that means, you cannot create an EdiSegment and then, create a EdiSegmentGroup out of it including said segment, it's redundant.

For example, for the given structure, (ORDRSP) we have a SegmentGroup (SG3) NAD which includes a nested LOC Segment and another SegmentGroup (SG6) CTA with a up to 5 nested COM Segments

2017-04-03_12-23-58

You have to create the EdiSegmentGroup NAD, EdiSegmentGroup CTA and two EdiSegments, LOC and COM, explanation by the author here

This is a working example for the aforementioned structure, hope this can help you.

[EdiPath("COM[0][0]"), EdiSegment]
public class ORDRSP_COM
{
    [EdiValue("X(255)", Path = "COM/0/0")]
    public string ID {
        get; set;
    }

    [EdiValue("X(3)", Path = "COM/0/1")]
    public string Code {
        get; set;
    }
}
[EdiSegmentGroup("CTA[0][0]")]
public class ORDRSP_SG6
{
    [EdiValue("X(3)", Path = "CTA/0/0")]
    public string Funktion {
        get; set;
    }

    [EdiValue("X(17)", Path = "CTA/1/0")]
    public string Kontaktnummer {
        get; set;
    }

    [EdiValue("X(0)", Path = "CTA/1/1")]
    public string Kontakt {
        get; set;
    }

    [EdiCondition("EM", Path = "COM[0][1]")]
    public ORDRSP_COM Elektronische_Post {
        get; set;
    }

    [EdiCondition("FX", Path = "COM[0][1]")]
    public ORDRSP_COM Telefax {
        get; set;
    }

    [EdiCondition("TE", Path = "COM[0][1]")]
    public ORDRSP_COM Telefon {
        get; set;
    }

    [EdiCondition("AJ", Path = "COM[0][1]")]
    public ORDRSP_COM Weiteres_Telefon {
        get; set;
    }

    [EdiCondition("AL", Path = "COM[0][1]")]
    public ORDRSP_COM Handy {
        get; set;
    }
}
[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "CUX[0][0]")]
public class ORDRSP_SG3
{
    [EdiValue("X(3)", Path = "NAD/0/0")]
    public string Code {
        get; set;
    }

    [EdiValue("X(35)", Path = "NAD/1/0")]
    public string ID {
        get; set;
    }

    [EdiValue("X(3)", Path = "NAD/1/2")]
    public string Codeliste {
        get; set;
    }

    public ORDRSP_LOC LOC {
        get; set;
    }

    public ORDRSP_SG6 CTA {
        get; set;
    }
}
[EdiPath("LOC[0][0]"), EdiSegment]
public class ORDRSP_LOC
{
    [EdiValue("X(3)", Path = "LOC/0/0")]
    public string Code {
        get; set;
    }

    [EdiValue("X(35)", Path = "LOC/1/0")]
    public string ID {
        get; set;
    }
}

from edi.net.

cleftheris avatar cleftheris commented on September 15, 2024

@KoosBusters you should think of the approach like this: "It is a bind to entities alternative, designed to make EDI less machine and more human readable"

Take for example The LIN segment. In EDI.Net world this not only marks the beginning of a group, it also is the Line item itself. It is redundant to think that it should be the container and another class inside it. So strictly speaking the LineItem class should contain every possible segment inside it apart from itself. That said there could be an opportunity for improvement here and support an alternative approach as you have contributed in the case if "Header" & "Trailer" segments #45, but that was not my original intention.

Grouping and nesting with the segment group is better seen in action through the examples.

One enhancement we could make in order to make this better is to support a list of potential segment names inside the segment group instead of the escape segment (SequenceEnd)

@Nekeniehl the SequenceEnd marks only the escape Segment name and it is not supposed to be a path.

Does this make sense?

from edi.net.

Nekeniehl avatar Nekeniehl commented on September 15, 2024

Hi @cleftheris, as I'm using reflection.emit to generate the POCO classes, it looks like a EdiPath (CUX[0][0]) because the reflected constructor EdiSegmentGroup.SequenceEnd.ToString() convert it to that:

private static void SetEdiSegmentGroupAttribute(this TypeBuilder inTypeBuilder, XmlProperty inXmlProperty)
{
    ConstructorInfo ctor = typeof(EdiSegmentGroupAttribute).GetConstructor(new[] { typeof(String) });
    CustomAttributeBuilder ediSegmentBuilder = null;

    EdiSegmentGroupAttribute ediSegmentAttribute =
            (EdiSegmentGroupAttribute)inXmlProperty.AttributeDict[Enums.EdiNetAttributesEnum.EdiSegmentGroup].First();

    Object[] ctorParams = new Object[] { ediSegmentAttribute.Start };

    if (ediSegmentAttribute.SequenceEnd.Equals("[0][0]"))
    {
        //No EndElement
        ediSegmentBuilder = new CustomAttributeBuilder(ctor, ctorParams);
    }
    else
    {
        PropertyInfo[] sequenceEndPI = new PropertyInfo[] { ediSegmentAttribute.GetType().GetProperty("SequenceEnd") };
        Object[] sequenceEndParams = new Object[] { ediSegmentAttribute.SequenceEnd.ToString() };

        ediSegmentBuilder = new CustomAttributeBuilder(ctor, ctorParams, sequenceEndPI, sequenceEndParams);
    }

    if (ctor == null)
    {
        return;
    }

    inTypeBuilder.SetCustomAttribute(ediSegmentBuilder);
}

from edi.net.

cleftheris avatar cleftheris commented on September 15, 2024

@Nekeniehl Aha :)
Yes this is the default ToString() output of an EdiPath struct. Its a multipurpose struct as you have seen. No problem then, just never seen this configured that way.

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

@cleftheris , @Nekeniehl thanks for the extensive explanation, it provided more insight in the current structure and I hope that I understand.

I think I can better explain my approach to an protocol implementation using the nice diagram provided by @Nekeniehl:

I see that the RFF segment is present twice in the diagram, on 1 place it is used inside the SG1 and it can contain a list with 0 to 5 DTM segments as its children. On SG32 the RFF segment is present again.
bc048644-28d6-11e7-83ea-e20f7da5ae51

What I would really like is to create 1 RFF segment class and use it for both cases. Ideally without defining an DTM list on my RFF segment that will be set depending on the place where it used (but the class doesn't have a clue if it's used in SG1 or SG32 although different validations are required between the two segments)

What I wanted before I understood the current structure was as following:

A generic namespace containing my segments

    namespace SegmentRepository
    {
        /// <summary>
        /// UNZ - Interchange trailer
        /// </summary>
        [EdiSegment, EdiPath("UNZ")]
        public class UNZ
        {
            #region Component 1 - 0036

            /// <summary>
            /// The count of the number of messages in the interchange.
            /// </summary>
            [EdiValue("n..6", FormatterType.EdifactSpec, Path = "UNZ/0", Description = "0036", Mandatory = true)]
            public int InterchangeControlCount { get; set; }

            #endregion

            #region Component 2 - 0020

            /// <summary>
            /// Shall be identical to 0020 in UNB.
            /// </summary>
            [EdiValue("an..14", FormatterType.EdifactSpec, Path = "UNZ/1", Description = "0020", Mandatory = true)]
            public string InterchangeControlReferenceCheck { get; set; }

            #endregion
        }

        [EdiSegment, EdiPath("RFF")]
        public class RFF
        {
            // Implement the RFF segment
        }

        [EdiSegment, EdiPath("UNB")]
        public class UNB
        {
            // Implement the UNB segment
        }

        [EdiSegment, EdiPath("LIN")]
        public class LIN
        {
            // Implement the LIN segment
        }
    }

With a specific class per message, composing the message and the defined structure + structure constraints (number of occurrences) from the segment repository

    public class MessageImplementation
    {
        public class Interchange
        {
            public SegmentRepository.UNB UNB { get; set; }
            public Message Message { get; set; }
            public SegmentRepository.UNZ UNZ { get; set; }
        }

        [EdiMessage]
        public class Message
        {
            // UNH

            // BGM

            // DTM_Segment_Group (parsing the different DTM segments to 1 complex class as in the edifact examples)

            [EdiSegmentOccurence(Min = 0, Max = 999)] // Could be use to define occurence min-max for this specific message structure
            // List IMD

            [EdiSegmentOccurence(Min = 0, Max = 9999)]
            public List<SG1> Segment1 { get; set; }

            // SG2

            [EdiSegmentOccurence(Min = 0, Max = 5)]
            // List SG3

            [EdiSegmentOccurence(Min = 0, Max = 200000)]
            public List<SG27> Segment27 { get; set; }

            // UNS
        }

        #region Segments

        [EdiSegmentGroup("RFF")] // or an EdiGroup equivalent that doesn't behave as an EdiSegment so I could use the EdiSegment decorated class inside
        public class SG1
        {
            public SegmentRepository.RFF RFF { get; set; }
            // DTM_Segment_Group (parsing the different DTM segments to 1 complex class as in the edifact examples)
        }

        public class SG27
        {
            public SegmentRepository.LIN LIN { get; set; }

            [EdiSegmentOccurence(Min = 0, Max = 99)]
            // List QTY

            [EdiSegmentOccurence(Min = 0, Max = 10)]
            // List MOA

            [EdiSegmentOccurence(Min = 0, Max = 99)]
            // List FTX

            [EdiSegmentOccurence(Min = 0, Max = 25)]
            // List SG31

            [EdiSegmentOccurence(Min = 0, Max = 9999)]
            public List<SG32> Segement32 { get; set; }  // Could also be list of RFF because only multiple RFF elements need to be supported and it will have no children in this case. Kept for demonstration purposes.
        }

        public class SG32
        {
            public SegmentRepository.RFF RFF { get; set; } // Re-uses the RFF segment from the generic segment repository
        }

        #endregion
    }

I like the readability inside the segments and do not care so much for the extra SG classes that I would create because I will create Business objects that contain a lot less properties than these extensive classes that should generate valid EDIFACT message. An compose method that creates the EDIFACT POCO from the Business object grow a little bit in complexity, but the business objects should already be structured similar as the EDIFACT classes (meaning they should have the same structure as in one-to-one, one-to-many, many-to-many relationship between elements).

I have found a way to implement my desired structure on the current implementation. Given the same example it would result in the following:

 public class MessageImplementation
    {
        public class Interchange
        {
            public SegmentRepository.UNB UNB { get; set; }
            public Message Message { get; set; }
            public SegmentRepository.UNZ UNZ { get; set; }
        }

        [EdiMessage]
        public class Message
        {
            // UNH

            // BGM

            // DTM_Segment_Group (parsing the different DTM segments to 1 complex class as in the edifact examples)

            [EdiSegmentOccurence(Min = 0, Max = 999)] // Could be use to define occurence min-max for this specific message structure
            // List IMD

            [EdiSegmentOccurence(Min = 0, Max = 9999)]
            public List<SG1> Segment1 { get; set; }

            // SG2

            [EdiSegmentOccurence(Min = 0, Max = 5)]
            // List SG3

            [EdiSegmentOccurence(Min = 0, Max = 200000)]
            public List<SG27> Segment27 { get; set; }

            // UNS
        }

        #region Segments

        [EdiSegmentGroup("RFF")]
        public class SG1 : SegmentRepository.RFF
        {
            // DTM_Segment_Group (parsing the different DTM segments to 1 complex class as in the edifact examples)
        }

        public class SG27 : SegmentRepository.LIN
        {
            [EdiSegmentOccurence(Min = 0, Max = 99)]
            // List QTY

            [EdiSegmentOccurence(Min = 0, Max = 10)]
            // List MOA

            [EdiSegmentOccurence(Min = 0, Max = 99)]
            // List FTX

            [EdiSegmentOccurence(Min = 0, Max = 25)]
            // List SG31

            [EdiSegmentOccurence(Min = 0, Max = 9999)]
            public List<SG32> Segement32 { get; set; } // Could also be list of RFF because only multiple RFF elements need to be supported and it will have no children in this case. Kept for demonstration purposes.
        }

        public class SG32 : SegmentRepository.RFF
        {
        }

        #endregion
    }

Here the element that is coupled with the SG in the diagram is extended in the SG. Because attribute inheritance flag is not set when retrieving the set of edi attributes on the classes their [EdiSegment] attribute is ignored and the [EdiSegmentGroup] attribute will be used instead.

The only change I had to make as in the way the properties are collected, this was done by getting the properties and then visiting the base type which worked by mixed up the order of my edi segments when serializing.

This:

        private static IList<PropertyInfo> GetPropertiesRecursive(this TypeInfo type)
        {
            TypeInfo t = type;
            IList<PropertyInfo> properties = new List<PropertyInfo>();
            while (t != null)
            {
                foreach (var member in t.DeclaredProperties)
                {
                    if (!properties.Any(p => p.Name == member.Name))
                        properties.Add(member);
                }
                t = (t.BaseType != null) ? t.BaseType.GetTypeInfo() : null;
            }
            return properties;
        }

became this:

        private static IList<PropertyInfo> GetPropertiesRecursive(this TypeInfo type)
        {
            IList<PropertyInfo> properties = new List<PropertyInfo>();
            var nestedTypes = GetNestedTypesStack(type);

            foreach (var nestedType in nestedTypes)
            {
                foreach (var member in nestedType.DeclaredProperties) {
                    if (!properties.Any(p => p.Name == member.Name))
                        properties.Add(member);
                }
            }

            return properties;
        }

        private static Stack<TypeInfo> GetNestedTypesStack(TypeInfo type) {
            Stack<TypeInfo> nestedTypes = new Stack<TypeInfo>();
            while (type != null) {
                nestedTypes.Push(type);
                type = (type.BaseType != null) ? type.BaseType.GetTypeInfo() : null;
            }
            return nestedTypes;
        }

And the same for the recursive members/fields methods. This way the properties are added to the properties list depth first. These changes did not trip any unit tests, and if I investigated correctly an property that is overwritten on an extending class already would have triggered an exception, so there should be no side effects to other properties being selected because of the inverted search.

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

A somewhat related question:
Can you tell me if an EdiCondition is suppose to work together with an EdiSegmentGroup?

I should create EdiSegmentGroups of NAD segment, starting from an UNS segment with an D value, until an UNS segment with the S value is found. There are also other NAD segments in the message outside this UNS start <-> UNS end section that should not create EdiSegmentGroups but rather create normal NAD segments.

Simplified diagram:

-UNH
-BGM
-NAD
-UNS (with D value)
--NAD
---LIN
----RFF
----QTY
-UNS (with S value)

How would I combine the edi attributes to capture all segments (including the UNS elements themselves because they are needed for serializing)

from edi.net.

Nekeniehl avatar Nekeniehl commented on September 15, 2024

Hi, I'm not sure about which format is the simplified diagram, but I'm pretty sure the standards for that one differentiates between both NAD Segments with a different segment number, let say Seg5 NAD and Seg32 NAD, therefore you will not need any EdiCondition. But, of course, reinventing the wheel is something developers doesn't like to do, so I see your point of reusing Segments, I just tested it a little bit to see if is possible to use the EdiCondition and in my POCO is working "fine" (since it is not prepared for that and it was a dirty test with the NAD segment, but the EdiCondition was recognise and only parsed the NAD+MR segment)

I did the following:

[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "UNS")]
[EdiCondition("MR", CheckFor = EdiConditionCheckType.Equal, Path = "NAD/0/0")]
SG2 {...}

So I guess you probably can do something like:

[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "UNS")]
[EdiCondition("D", CheckFor = EdiConditionCheckType.Equal, Path = "UNS/0/0")]
FirstNad: SegmentRepository.NadSegment
{...}
[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "UNS")]
[EdiCondition("S", CheckFor = EdiConditionCheckType.Equal, Path = "UNS/0/0")]
SecondNad: SegmentRepository.NadSegment
{...}

EDIT for the Inner NAD:

[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "UNS")]
[EdiCondition("S", CheckFor = EdiConditionCheckType.NotEqual, Path = "UNS/0/0")]
[EdiCondition("D", CheckFor = EdiConditionCheckType.NotEqual, Path = "UNS/0/0")]
InnerNad: SegmentRepository.NadSegment
{...}

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

@Nekeniehl thanks for the suggestion but it still not working. You mentioned that if I were to define the 2 NAD segments as separate classes Seg5 and Seg32 it should work without even using an EdiCondition, but I can't even get that to work.

Do you have an example of such structure in one of your messages that you could share?

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

I think it might be an bug (or just mis-use of the current structure): I have spent some time stepping though the messages, looks like using an EdiCondition of the UNS type on a NAD segment forces the EdiTextWriter to advance the reader in the condition matching method until it finds the path of the EdiCondition.

It will cache its reads into a cache, but this cache is not taken into consideration when creating new containers, so the UNS segment will never be created.

This is when I apply the EdiConditions to the NAD segments.

[EdiCondition("D", CheckFor = EdiConditionCheckType.NotEqual, Path = "UNS/0/0")]
to the first NAD EdiSegment

[EdiCondition("D", CheckFor = EdiConditionCheckType.Equal, Path = "UNS/0/0")]
to the second NAD EdiSegmentGroup as the selector of the second NAD element will change to UNS, advance the reader until the D is found in the UNS patch while keeping the read elements in the cache:

image

Only in this case there is more than just values read, it contains an ElementStart, ComponentStart and String token.

Note that in my case the two NAD elements are identical in the specs, the purpose of this UNS element (Section Control element) is to separate the two type NAD segments. I have to use the structure of the message to differentiate between the first and second NAD.

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

I created an unit test that I think indicates the problem in an simple example: KoosBusters@9d1433b

I somebody could give this unit test a shot and define a structure that would work on this type of message that would be awesome. I will also continue to work on this one.

from edi.net.

Nekeniehl avatar Nekeniehl commented on September 15, 2024

Here a working example where I have two NAD's (SG2 and SG5) for the following diagram (MSCONS)

2017-04-26_09-17-15

[EdiSegmentGroup("NAD[0][0]", SequenceEnd = "UNS")]
public class MSCONS_SG2
{
    [EdiValue("X(3)", Path = "NAD/0/0")]
    public string Code {
        get; set;
    }

    [EdiValue("X(35)", Path = "NAD/1/0")]
    public string ID {
        get; set;
    }

    [EdiValue("X(3)", Path = "NAD/1/2")]
    public string Codeliste {
        get; set;
    }

    public SG4 CTA { get; set; }
}

[EdiSegmentGroup("NAD", SequenceEnd = "UNT")]
public class MSCONS_SG5
{
    [EdiValue("X(3)", Path = "NAD/0/0")]
    public string Qualifier { get; set; }

    [EdiCondition("237", Path = "LOC[0][0]")]
    public MSCONS_SG6 Bilanzkreis { get; set; }

    [EdiCondition("172", Path = "LOC[0][0]")]
    public MSCONS_SG6 Zaehlpunkt { get; set; }

    [EdiCondition("Z04", Path = "LOC[0][0]")]
    public MSCONS_SG6 Profilbezeichnung { get; set; }

    [EdiCondition("107", Path = "LOC[0][0]")]
    public MSCONS_SG6 Bilanzierungsgebiet { get; set; }

    [EdiCondition("Z06", Path = "LOC[0][0]")]
    public MSCONS_SG6 Profilschar { get; set; }
}

In my case the NAD segments has different fields and the UNS is always "D" and I do not have to parse it, but If you say that both NAD segments are equal in specs and the only difference is the UNS segment, maybe what you can do is get the UNS inside the NAD class to later check the value of the UNS to know the type, it will give you something like:

[EdiSegmentGroup("NAD", SequenceEnd = "UNT")]
public class NAD
{
    [EdiValue("X(1)", Path = "UNS/0/0")]
    public string NAD_Type { get; set; }

    [other fields and segments]
}

I hope this can help you a little bit.

Edit
Give me a bit and I will take a look on your examples.

from edi.net.

Nekeniehl avatar Nekeniehl commented on September 15, 2024

Playing around with your example:

+UNA:+.? '
+UNB+UNOC:3+1234567891123:14+7080005059275:14:SPOTMARKED+101012:1104+HBQ001++++1'
+UNH+1+QUOTES:D:96A:UN:EDIEL2+S'
+AAA+1'
+AAA+2'
+AAA+3'
+UNS+D'
+AAA+1'
+BBB+INSIDE:THE:AAA:SG+1'
+AAA+2'
+BBB+INSIDE:THE:AAA:SG+2'
+AAA+3'
+BBB+INSIDE:THE:AAA:SG+3'
+AAA+4'
+AAA+5'
+UNT+14+1'
+UNZ+1+20101000064507'

I have simplified the class to the following, but I think is not what you really want, this will give you a list of all the AAA inside interchange, in my opinion t is the best structure you can have with your example as you cannot actually put a SequenceEnd distinct than UNT, if you use i.e UNS you will lose the information from it.

public class Interchange_RST
{
    public Message_RST Message { get; set; }
}

[EdiMessage]
public class Message_RST
{
    public List<AAA> AAA { get; set; }
}

[EdiSegmentGroup("AAA", SequenceEnd = "UNT")]
public class AAA
{
    [EdiValue("X(1)", Path = "UNS/0/0")]
    public String AAA_Type { get; set; }

    public BBB BBB { get; set; }

}

[EdiSegment, EdiPath("BBB")]
public class BBB
{
    [EdiValue("X(6)", Path = "BBB/0/0")]
    public string BBBText1 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/1")]
    public string BBBText2 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/2")]
    public string BBBText3 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/3")]
    public string BBBText4 { get; set; }

    [EdiValue("9(3)", Path = "BBB/1/0")]
}

from edi.net.

Nekeniehl avatar Nekeniehl commented on September 15, 2024

So, playing around with your example, I saw it was missing one of the UNS so I modified it:

UNA:+.? '
UNB+UNOC:3+1234567891123:14+7080005059275:14:SPOTMARKED+101012:1104+HBQ001++++1'
UNH+1+QUOTES:D:96A:UN:EDIEL2+S'
UNS+H'
AAA+1'
AAA+2'
AAA+3'
UNS+D'
AAA+1'
BBB+INSIDE:THE:AAA:SG+1'
AAA+2'
BBB+INSIDE:THE:AAA:SG+2'
AAA+3'
BBB+INSIDE:THE:AAA:SG+3'
AAA+4'
AAA+5'
UNT+14+1'
UNZ+1+20101000064507'

And this give the following structure which is tested and working fine, you will get in the Message_RST two elements for each UNS (header and detail) with everything inside:

public class Interchange_RST
{
    public Message_RST Message { get; set; }
}

[EdiMessage]
public class Message_RST
{
    public UNSH UNSH { get; set; }
    public UNSD UNSD { get; set; }
}


[EdiSegmentGroup("UNS")]
[EdiCondition("H", Path = "UNS/0/0")]
public class UNSH
{
    public List<AAA> AAAList { get; set; }

    [EdiValue("X(1)", Path = "UNS/0/0")]
    public String UNSType { get; set; }
}

[EdiSegmentGroup("AAA")]
[EdiPath("AAA/0/0")]
public class AAA
{
    [EdiValue("X(1)", Path = "AAA/0/0")]
    public String AAA_Num { get; set; }

    public BBB BBB { get; set; }
}

[EdiSegmentGroup("UNS")]
[EdiCondition("D", Path = "UNS/0/0")]
public class UNSD
{
    public List<AAA> AAAList { get; set; }

    [EdiValue("X(1)", Path = "UNS/0/0")]
    public String UNSType { get; set; }
}

[EdiSegment, EdiPath("BBB")]
public class BBB
{
    [EdiValue("X(6)", Path = "BBB/0/0")]
    public string BBBText1 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/1")]
    public string BBBText2 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/2")]
    public string BBBText3 { get; set; }

    [EdiValue("X(6)", Path = "BBB/0/3")]
    public string BBBText4 { get; set; }

    [EdiValue("9(3)", Path = "BBB/1/0")]
    public int BBBGroupSegmentOccurence { get; set; }
}

I hope the previous answer and this one can give you a better approach about the logic I have follow to build the structure.

from edi.net.

KoosBusters avatar KoosBusters commented on September 15, 2024

@Nekeniehl thanks a lot for your efforts, information and solutions!

Unfortunately the UNS was not missing by accident in my case, it is not specified in the specs of the messages, it is the single UNS that I need to work with (very unfortunate). Your examples give me some ideas for other approaches that I will try today!

from edi.net.

ligraseac avatar ligraseac commented on September 15, 2024

Hi,

I also have similar issue, my structure is something like this.

HL+S
PWK
TD1
N1
N2
N3
N4
N1
N3
N1
N4
HL+O
PRF
N1
N2
N1
N2

my issue is that the two HL should be on a separate group but it seems that I can't make both have values because of the N1 to N4 segments. If both are present the first HL segment group have all the value but is using the code of the second HL (which is "O") and the second HL won't have any value at all. I already added condition on the segment groups but still not sure what is wrong, here is the sample model.

[EdiMessage]
public class ShipNotice {
    public List<ShipmentInfo> ShipmentInfos { get; set; }
    public List<PurchaseOrderInfo> PurchaseOrderInfos { get; set; }
}

[EdiSegmentGroup("HL", "PWK", "TD1",  "N1", "N2", "N3", "N4", "PER")]
[EdiCondition("S", Path = "HL/2")]
public class ShipmentInfo {
    [EdiValue(Path = "HL/0", Description = "HL01 - Hierarchical ID Number")]
    public string IdNumber { get; set; }

    [EdiValue(Path = "HL/1", Description = "HL02 - Hierarchical Parent ID Number")]
    public string ParentIdNumber { get; set; }

    [EdiValue(Path = "HL/2", Description = "HL03 - Hierarchical Level Code")]
    public string LevelCode { get; set; }

    [EdiValue(Path = "HL/3", Description = "HL04 - Hierarchical Child Code")]
    public string ChildCode { get; set; }

    public List<PWK> PaperWorks { get; set; }
    public List<TD1> QuantityAndWeightDetails { get; set; }
    public List<ShipmentPartyInfo> ShipmentPartyInfos { get; set; }
}

[EdiSegmentGroup("HL", "PRF", "TD1",  "N1", "N2", "N3", "N4", "PER")]
[EdiCondition("O", Path = "HL/2")]
public class PurchaseOrderInfo {
    [EdiValue(Path = "HL/0", Description = "HL01 - Hierarchical ID Number")]
    public string IdNumber { get; set; }

    [EdiValue(Path = "HL/1", Description = "HL02 - Hierarchical Parent ID Number")]
    public string ParentIdNumber { get; set; }

    [EdiValue(Path = "HL/2", Description = "HL03 - Hierarchical Level Code")]
    public string LevelCode { get; set; }

    [EdiValue(Path = "HL/3", Description = "HL04 - Hierarchical Child Code")]
    public string ChildCode { get; set; }

    public PRF Detail { get; set; }
    public List<POPartyInfo> POPartyInfos { get; set; }
}

[EdiSegmentGroup("N1", "N2", "N3",  "N4", "PER")]
public class ShipmentPartyInfo
{
    [EdiValue(Path = "N1/0", Description = "N101 - Entity Identifier Code")]
    public string EntityIdentifierCode { get; set; }

    [EdiValue(Path = "N1/1", Description = "N102 - Name")]
    public string Name { get; set; }

    [EdiValue(Path = "N1/2", Description = "N103 - Identification Code Qualifier")]
    public string IdentificationCodeQualifier { get; set; }

    [EdiValue(Path = "N1/3", Description = "N104 - Identification Code")]
    public string IdentificationCode { get; set; }

    public List<N2> EntityNames { get; set; }
    public List<N3> EntityAddressSummaries { get; set; }
    public N4 EntityLocationDetail { get; set; }
    public List<PER> ContactDetails { get; set; }
}

[EdiSegmentGroup("N1", "N2", "N3",  "N4", "PER")]
public class POPartyInfo
{
    [EdiValue(Path = "N1/0", Description = "N101 - Entity Identifier Code")]
    public string EntityIdentifierCode { get; set; }

    [EdiValue(Path = "N1/1", Description = "N102 - Name")]
    public string Name { get; set; }

    [EdiValue(Path = "N1/2", Description = "N103 - Identification Code Qualifier")]
    public string IdentificationCodeQualifier { get; set; }

    [EdiValue(Path = "N1/3", Description = "N104 - Identification Code")]
    public string IdentificationCode { get; set; }

    public List<N2> EntityNames { get; set; }
    public List<N3> EntityAddressSummaries { get; set; }
    public N4 EntityLocationDetail { get; set; }
    public List<PER> ContactDetails { get; set; }
}

I also tried adding SequenceEnd to both the N1 to N4 group but still same result.

from edi.net.

ligraseac avatar ligraseac commented on September 15, 2024

Just to update, setting AutoEndSegmentGroups = true solved this issue for me.

from edi.net.

cleftheris avatar cleftheris commented on September 15, 2024

Thanks for the example. I will try to make it into a test

from edi.net.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.