Skip to content

Commit

Permalink
Merge pull request #312 from MikeEdgar/issue-311
Browse files Browse the repository at this point in the history
Fix X12 transaction control validation and writer segment tally
  • Loading branch information
MikeEdgar authored Nov 9, 2022
2 parents 52f7cb9 + 5efcfeb commit 282e0bf
Show file tree
Hide file tree
Showing 8 changed files with 25 additions and 35 deletions.
31 changes: 11 additions & 20 deletions src/main/java/io/xlate/edi/internal/schema/SchemaReaderBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,14 @@ Reference readControlStructure(XMLStreamReader reader,
title,
descr);

types.put(struct.getId(), struct);
/*
* Built-in X12 control schemas include a prohibited transaction element in the
* schema to indicate that a transaction may not be used directly within an interchange
* envelope. The use of `putIfAbsent` prevents this transaction from overlaying the
* actual transaction type nested within the group envelope. EDIFACT and TRADACOMS
* transactions may appear in either location, the `putIfAbsent` has no effect.
*/
types.putIfAbsent(struct.getId(), struct);

Reference structRef = new Reference(struct.getId(), elementType, minOccurs, maxOccurs, title, descr);
structRef.setReferencedType(struct);
Expand Down Expand Up @@ -417,22 +424,14 @@ StructureType readComplexType(XMLStreamReader reader,
final EDIType.Type type = complex.get(complexType);
final String id;
String code = parseAttribute(reader, "code", String::valueOf, null);
// Transaction attributes
EDIElementPosition headerRef = null;
EDIElementPosition trailerRef = null;
EDIElementPosition trailerCount = null;
EDIControlType.Type countType = null;
// Loop attributes
EDIElementPosition levelIdPosition = null;
EDIElementPosition parentIdPosition = null;

switch (type) {
case TRANSACTION:
// "Standard" transaction structure, not the control type from control schema
id = StaEDISchema.TRANSACTION_ID;
headerRef = parseElementPosition(reader, ATTR_HEADER_REF_POSITION);
trailerRef = parseElementPosition(reader, ATTR_TRAILER_REF_POSITION);
trailerCount = parseElementPosition(reader, ATTR_TRAILER_COUNT_POSITION);
countType = parseAttribute(reader, ATTR_COUNT_TYPE, EDIControlType.Type::fromString, EDIControlType.Type.NONE);
break;
case LOOP:
id = code;
Expand Down Expand Up @@ -475,18 +474,10 @@ StructureType readComplexType(XMLStreamReader reader,
if (event == XMLStreamConstants.END_ELEMENT) {
StructureType structure;

switch (type) {
case TRANSACTION:
structure = new ControlType(id, type, code, refs, rules, headerRef, trailerRef, trailerCount, countType, title, descr);
break;
case LOOP:
if (type == Type.LOOP) {
structure = new LoopType(code, refs, rules, levelIdPosition, parentIdPosition, title, descr);
break;
case SEGMENT:
case COMPOSITE:
default:
} else {
structure = new StructureType(id, type, code, refs, rules, title, descr);
break;
}

return structure;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ public EDIStreamWriter endInterchange() throws EDIStreamException {
@Override
public EDIStreamWriter writeStartSegment(String name) throws EDIStreamException {
ensureLevel(LEVEL_INTERCHANGE);
countSegment(name);
location.incrementSegmentPosition(name);

if (state == State.INITIAL) {
dialect = DialectFactory.getDialect(name);
Expand Down Expand Up @@ -455,6 +455,7 @@ public EDIStreamWriter writeStartSegment(String name) throws EDIStreamException
writeString(name);
}

countSegment(name);
level = LEVEL_SEGMENT;
emptyElements = 0;
terminateSegmentTag();
Expand All @@ -463,8 +464,6 @@ public EDIStreamWriter writeStartSegment(String name) throws EDIStreamException
}

void countSegment(String name) {
location.incrementSegmentPosition(name);

if (controlValidator != null) {
controlValidator.countSegment(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ void testElementTypeDescriptionAccess() throws EDIStreamException, EDISchemaExce
+ "NM1*40*2*PPO BLUE*****46*54771~"
+ "HL*1**20*1~"
+ "HL*2*1*22*0~"
+ "SE*6*0001~"
+ "SE*8*0001~"
+ "GE*1*1~"
+ "IEA*1*000000001~").getBytes());

Expand Down Expand Up @@ -268,7 +268,7 @@ void testElementTypeDescriptionAccessOnDescriminator() throws EDIStreamException
+ "PER*IC*EDI DEPT*EM*[email protected]*TE*3305551212~"
+ "NM1*40*2*PPO BLUE*****46*54771~"
+ "HL*1**20*1~"
+ "SE*6*0001~"
+ "SE*7*0001~"
+ "GE*1*1~"
+ "IEA*1*000000001~").getBytes());

Expand Down Expand Up @@ -322,7 +322,7 @@ void testElementTypeDescriptionAccessPriorToDescriminator() throws EDIStreamExce
+ "PER*IC*EDI DEPT*EM*[email protected]*TE*3305551212~"
+ "NM1*40*2*PPO BLUE*****46*54771~"
+ "HL*1**20*1~"
+ "SE*6*0001~"
+ "SE*7*0001~"
+ "GE*1*1~"
+ "IEA*1*000000001~").getBytes());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void testElementTypeDescriptionAccess() throws EDIStreamException, EDISchemaExce
+ "PER*IC*EDI DEPT*EM*[email protected]*TE*3305551212~"
+ "NM1*40*2*PPO BLUE*****46*54771~"
+ "HL*1**20*1~"
+ "SE*6*0001~"
+ "SE*7*0001~"
+ "GE*1*1~"
+ "IEA*1*000000001~").getBytes());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ void testRequiredComponentInC030InAnyElementInAK4() throws EDISchemaException, E
+ "AK4*8:::ANYCOMPONENT*66*7*MI~"
+ "AK5*R*5~"
+ "AK9*R*1*1*0~"
+ "SE*4*0001~"
+ "SE*8*0001~"
+ "GE*1*000005~"
+ "IEA*1*508121953~").getBytes());

Expand Down Expand Up @@ -670,7 +670,7 @@ void testMissingRequiredComponentInC030InAnyElementInAK4() throws EDISchemaExcep
+ "AK4*8:::*66*7*MI~"
+ "AK5*R*5~"
+ "AK9*R*1*1*0~"
+ "SE*4*0001~"
+ "SE*8*0001~"
+ "GE*1*000005~"
+ "IEA*1*508121953~").getBytes());

Expand Down Expand Up @@ -724,7 +724,7 @@ void testMultiVersionElementType() throws EDISchemaException, EDIStreamException
+ "S0A*3333~" // Too long
+ "S0A*222~" // Good
+ "S0A*333~" // Invalid code
+ "SE*6*0001~"
+ "SE*7*0001~"
+ "GE*1*000002~"
+ "GS*FA*ReceiverDept*SenderDept*20200615*133025*000003*X*005010~"
+ "ST*000*0001~"
Expand All @@ -734,7 +734,7 @@ void testMultiVersionElementType() throws EDISchemaException, EDIStreamException
+ "S0A*222~" // Good
+ "S0A*333~" // Good
+ "S0A*444~" // Invalid code
+ "SE*3*0001~"
+ "SE*8*0001~"
+ "GE*1*000003~"
+ "IEA*3*508121953~").getBytes());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void testMissingTagSequence() throws EDISchemaException,
+ "GS*FA*ReceiverDept*SenderDept*20050812*195335*000005*X*005010X230~"
+ "ST*997*0001*005010X230~"
+ "AK1*HC*000001~"
+ "SE*8*0001~"
+ "SE*3*0001~"
+ "GE*1*000005~"
+ "IEA*1*508121953~").getBytes());

Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/x12/invalid997_min.edi
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ GS*FA*ReceiverDept*SenderDept*BAD_DATE*295335*000005*X*005010X230~
ST*997*0001~
AK1*<NOT_IN_CODESET>*000001~
AK9*R*1*1*0~
SE*8*0001~
SE*4*0001~
GE*1*<TOO_LONG_AND_NOT_NUMERIC>~
IEA*1*508121953~
4 changes: 2 additions & 2 deletions src/test/resources/x12/sample837-HL-nested.edi
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ HL*12**20*1
HL*14*12*22*1
HL*15*14*23*0
HL*16*14*23*0
SE*8*0001
SE*23*0001
ST*837*0002
BHT*0019*00*565743*20210701*1225*CH
HL*1**20
Expand All @@ -35,6 +35,6 @@ HL*4**20*1
HL*8*6*23*0
HL*9**20*1
HL*10*9*22*0
SE*4*0002
SE*13*0002
GE*2*1
IEA*1*000000001

0 comments on commit 282e0bf

Please sign in to comment.