diff --git a/src/main/java/com/imsweb/x12/reader/X12Reader.java b/src/main/java/com/imsweb/x12/reader/X12Reader.java index 1877a22..c9f64e0 100644 --- a/src/main/java/com/imsweb/x12/reader/X12Reader.java +++ b/src/main/java/com/imsweb/x12/reader/X12Reader.java @@ -667,6 +667,7 @@ private LoopConfig getMatchedLoop(String[] tokens, String previousLoopID) { boolean lastIdCheck = lastId != null && tokens[0].equals(lastId.getXid()) && !config.getLoopId().equals(previousLoopID) && codesValidatedForLoopId(tokens, lastId); if (firstIdCheck || lastIdCheck) { + // clear the potential loop matches if the current segment is a child loop of the loop currently being processed if (isChildSegment(previousLoopID, tokens)) { matchedLoops.clear(); break; @@ -677,8 +678,12 @@ private LoopConfig getMatchedLoop(String[] tokens, String previousLoopID) { } } - if (matchedLoops.size() > 1) - result = getFinalizedMatch(previousLoopID, matchedLoops); + if (matchedLoops.size() > 1) { + // starting a new loop but we aren't quite sure which one yet. Remove loops where the segment is known to be the last segment of that loop - clearly we aren't in a new loop then + matchedLoops = matchedLoops.stream().filter(lc -> !(lc.getLastSegmentXid().getXid().equals(tokens[0]) && codesValidatedForLoopId(tokens, lc.getLastSegmentXid()))).collect( + Collectors.toList()); + result = matchedLoops.isEmpty() ? null : getFinalizedMatch(previousLoopID, matchedLoops); + } else if (matchedLoops.size() == 1) result = matchedLoops.get(0); } @@ -717,19 +722,20 @@ private boolean isChildSegment(String previousLoopId, String[] tokens) { * @return the finalized loop match */ private LoopConfig getFinalizedMatch(String previousLoopId, List matchedLoops) { + LoopConfig result = matchedLoops.get(0); for (LoopConfig lc : _config) { if (lc.getLoopId().equals(previousLoopId)) { - for (LoopConfig s1 : matchedLoops) - if (lc.getChildList() != null && lc.getChildList().contains(s1.getLoopId())) - return s1; - for (LoopConfig s2 : matchedLoops) { + for (LoopConfig s1 : matchedLoops) { String parentLoop = getParentLoop(previousLoopId, null); - if (parentLoop != null && parentLoop.equals(getParentLoop(s2.getLoopId(), null))) - return s2; + if ((lc.getChildList() != null && lc.getChildList().contains(s1.getLoopId())) + || (parentLoop != null && parentLoop.equals(getParentLoop(s1.getLoopId(), null)))) { + result = s1; + break; + } } } } - return matchedLoops.get(0); + return result; } /** diff --git a/src/test/java/com/imsweb/x12/reader/X12ReaderTest.java b/src/test/java/com/imsweb/x12/reader/X12ReaderTest.java index e580b8d..b2244f0 100644 --- a/src/test/java/com/imsweb/x12/reader/X12ReaderTest.java +++ b/src/test/java/com/imsweb/x12/reader/X12ReaderTest.java @@ -139,7 +139,7 @@ public void testWithInputStreamConstructor() throws Exception { validate837Valid(reader.getLoops().get(0)); } - + @Test public void testBadValidCode() throws Exception { URL url = this.getClass().getResource("/837_5010/x12_bad_valid_code.txt"); @@ -147,7 +147,7 @@ public void testBadValidCode() throws Exception { List errors = reader.getErrors(); - assertEquals(2, errors.size()); + assertEquals(3, errors.size()); assertTrue(errors.contains("Unable to find a matching segment format in loop 2000A")); Assert.assertFalse(reader.getFatalErrors().isEmpty()); @@ -1268,4 +1268,31 @@ private void assert2440(Loop loop) { assertEquals("01.04", loop.getLoop("2440", 2).getSegment("LQ").getElementValue("LQ02")); assertEquals("12Q", loop.getLoop("2440", 2).getSegment("FRM").getElementValue("FRM01")); } + + @Test + public void testX223Repeated2320() throws Exception { + URL url = this.getClass().getResource("/837_5010/x223-test.txt"); + X12Reader reader = new X12Reader(FileType.ANSI837_5010_X223, new FileInputStream(new File(url.getFile()))); + + Assert.assertEquals(1, reader.getLoops().size()); + Loop loop = reader.getLoops().get(0); + assertEquals(1, loop.getLoops().size()); + Assert.assertEquals(1, loop.findLoop("2000B").size()); + Assert.assertEquals(2, loop.getLoop("2000B").getSegments().size()); + Assert.assertEquals("HL", loop.getLoop("2000B").getSegment(0).getId()); + Assert.assertEquals("SBR", loop.getLoop("2000B").getSegment(1).getId()); + Assert.assertEquals("SUBSCRIBER GROUP", loop.getLoop("2000B").getSegment(1).getElement("SBR03").getValue()); + Assert.assertEquals(2, loop.findLoop("2320").size()); + Assert.assertEquals(2, loop.getLoop("2000B").findLoop("2320").size()); + Assert.assertEquals(1, loop.getLoop("2000B").getLoop("2320", 0).findLoop("2330A").size()); + Assert.assertEquals(1, loop.getLoop("2000B").getLoop("2320", 0).findLoop("2330B").size()); + Assert.assertEquals(1, loop.getLoop("2000B").getLoop("2320", 1).findLoop("2330A").size()); + Assert.assertEquals(1, loop.getLoop("2000B").getLoop("2320", 1).findLoop("2330B").size()); + Assert.assertEquals("S", loop.getLoop("2320",0).getSegment(0).getElement("SBR01").getValue()); + Assert.assertEquals("T", loop.getLoop("2320",1).getSegment(0).getElement("SBR01").getValue()); + Assert.assertEquals("JOHN", loop.getLoop("2320",0).getLoop("2330A").getSegment(0).getElement("NM104").getValue()); + Assert.assertEquals("JANE", loop.getLoop("2320",1).getLoop("2330A").getSegment(0).getElement("NM104").getValue()); + Assert.assertEquals("AETNA", loop.getLoop("2320",0).getLoop("2330B").getSegment(0).getElement("NM103").getValue()); + Assert.assertEquals("ANOTHER NAME", loop.getLoop("2320",1).getLoop("2330B").getSegment(0).getElement("NM103").getValue()); + } } diff --git a/src/test/resources/837_5010/x223-test.txt b/src/test/resources/837_5010/x223-test.txt new file mode 100644 index 0000000..cf06cb9 --- /dev/null +++ b/src/test/resources/837_5010/x223-test.txt @@ -0,0 +1,51 @@ +ISA*00* *01*SECRET *ZZ*SUBMITTERS.ID *ZZ*RECEIVERS.ID *030101*1253*U*00501*000000905*1*T*:~ +GS*HC*SENDER CODE*RECEIVER CODE*19991231*0802*1*X*005010X223A2~ +ST*837*987654*005010X223A2~ +BHT*0019*00*0123*19960918*0932*CH~ +NM1*41*2*ANGELASZEK MEDICAL*****46*999999999~ +PER*IC*DAVID ANGELASZEK*TE*3016809770*EX*123~ +NM1*40*2*HEALTH RECEIVER*****46*111222333~ +HL*1**20*1~ +NM1*85*2*MEDICAL GROUP*****XX*1234567890~ +N3*3901 CALVERTON BLVD~ +N4*CALVERTON*MD*20705~ +REF*EI*123456789~ +PER*IC*JANE JONES*TE*3022893453~ +PER*IC*JANE JANES*TE*3012833053*EX*201~ +NM1*87*2~ +N3*227 LASTNER LANE~ +N4*GREENBELT*MD*20770~ +HL*2*1*22*0~ +SBR*P**SUBSCRIBER GROUP******CI~ +NM1*IL*1*DOE*JOHN*T**JR*MI*123456~ +N3*123 MAIN STREET*APARTMENT 9~ +N4*RIVERDALE*MD*20737~ +DMG*D8*19611124*M~ +NM1*PR*2*HEALTH INSURANCE COMPANY*****PI*11122333~ +CLM*A37YH556*500***11:B:1*Y*A*Y*I*P~ +DTP*435*D8*20150330~ +DTP*434*D8*20120330~ +CL1*1*7*30~ +REF*EA*1122334~ +HI*BK:1739**~ +SBR*S*01*******CI~ +OI***Y***Y~ +NM1*IL*1*DOE*JOHN*D***MI*ABCDER1234~ +NM1*PR*2*AETNA*****PI*54321~ +N3*A PO BOX~ +N4*ANYTOWN*AL*32143~ +SBR*T*18*******CI~ +OI***Y***Y~ +NM1*IL*1*DOE*JANE****MI*GDAFA1232~ +N3*A STREET ADDRESS~ +N4*A TOWN*AL*54321~ +NM1*PR*2*ANOTHER NAME*****PI*12345~ +N3*PO BOX 1234~ N4*FRED*AL*12345~ +NM1*77*2*KIRBY CLINIC*****XX*1112223334~ +LX*1~ +SV2*0300*HC:81099*73.42*UN*1~ +DTP*472*RD8*20050314-20050325~ +DTP*304*D8*20120428~ +SE*25*987654~ +GE*1*1~ +IEA*1*000000905~ \ No newline at end of file