import com.americancoders.edi.*; import com.americancoders.edi.x12.*; /** code template to build *<br>class 997 Functional Acknowledgment *<br> * This Draft Standard for Trial Use contains the format and establishes * the data contents of the Functional Acknowledgment Transaction * Set (997) for use within the context of an Electronic Data Interchange * (EDI) environment. The transaction set can be used to define * the control structures for a set of acknowledgments to indicate * the results of the syntactical analysis of the electronically * encoded documents. The encoded documents are the transaction * sets, which are grouped in functional groups, used in defining * transactions for business data interchange. This standard does * not cover the semantic meaning of the information encoded in * the transaction sets. *@author OBOECodeGenerator */ public class build997 { boolean fgInErr=false; boolean tsInErr=false; int acceptedTSs = 0; X12Envelope env; /** constructor for class build997 * @param inEnv an OBOE X12Document object that we are responding to with this 997 * @param inDErr DocumentErrors object created when inEnv was created. * @throws OBOEException - most likely transactionset not found */ public build997(X12Envelope inEnv, DocumentErrors inDErr) throws OBOEException { env = new X12Envelope(EnvelopeFactory.buildEnvelope("x12.envelope", "")); /** add code here to work with the headers and other envelope control segments */ Segment interchange_Control_Header = env.createInterchange_Header(); Segment incomingISA = inEnv.getSegment("ISA"); // get the inEnv ISA so we can use its dataelements // and then set our ISA dataelements interchange_Control_Header.getDataElement("I01").set(incomingISA.getDataElement("I01").get()); interchange_Control_Header.getDataElement("I02").set(incomingISA.getDataElement("I02").get()); interchange_Control_Header.getDataElement("I03").set(incomingISA.getDataElement("I03").get()); interchange_Control_Header.getDataElement("I04").set(incomingISA.getDataElement("I04").get()); interchange_Control_Header.getDataElement(5).set(incomingISA.getDataElement(7).get()); // flip sender/receiver interchange_Control_Header.getDataElement("I06").set(incomingISA.getDataElement("I07").get()); // flip sender/receiver interchange_Control_Header.getDataElement(7).set(incomingISA.getDataElement(5).get()); // flip receiver/sender interchange_Control_Header.getDataElement("I07").set(incomingISA.getDataElement("I06").get()); // flip receiver/sender interchange_Control_Header.getDataElement("I08").set(com.americancoders.util.Util.currentDate()); interchange_Control_Header.getDataElement("I09").set(com.americancoders.util.Util.currentTime()); interchange_Control_Header.getDataElement("I10").set(incomingISA.getDataElement("I10").get()); interchange_Control_Header.getDataElement("I11").set(incomingISA.getDataElement("I11").get()); //we need to write a method called getNextControlNumber(String)... interchange_Control_Header.getDataElement("I12").set(getNextControlNumber("100")); interchange_Control_Header.getDataElement("I13").set("0"); // we don't want acknowledgment, otherwise set to "1" interchange_Control_Header.getDataElement("I14").set(incomingISA.getDataElement("I14").get()); interchange_Control_Header.getDataElement("I15").set(incomingISA.getDataElement("I15").get()); FunctionalGroup fg = env.createFunctionalGroup(); /** add code here to work with the fg header and trailer segments */ Segment fgHeader = fg.getHeader(); Segment incomingGS = inEnv.getFunctionalGroup(0).getSegment("GS"); // to get data out of the GS segment fgHeader.getDataElement("479").set("FA"); // 997's fall into this group fgHeader.getDataElement("142").set(incomingGS.getDataElement(3).get());// flip sender/receiver fgHeader.getDataElement("124").set(incomingGS.getDataElement(2).get());// flip sender/receiver fgHeader.getDataElement("373").set(com.americancoders.util.Util.currentDate()); fgHeader.getDataElement("337").set(com.americancoders.util.Util.currentTime()); fgHeader.getDataElement("28").set(getNextControlNumber("200")); fgHeader.getDataElement("455").set("X"); // could also be a "T" for TDCC, but we're doing X12. fgHeader.getDataElement("480").set("004010"); // ouch; it's hard coded fg.addSegment(fgHeader); Segment fgTrailer = fg.getTrailer(); fgTrailer.useDefault(); fg.addSegment(fgTrailer); env.addFunctionalGroup(fg); TransactionSet ts = TransactionSetFactory.buildTransactionSet("997"); fg.addTransactionSet(ts); Table table; table = ts.getHeaderTable(); buildSegmentTransactionSetHeaderforTableHeader(table); for (int fgcnt = 0; fgcnt < inEnv.getFunctionalGroupCount(); fgcnt++) { acceptedTSs = 0; fgInErr = false; buildSegmentFunctionalGroupResponseHeaderforTableHeader(table, inEnv.getFunctionalGroup(fgcnt)); if (inEnv.getFunctionalGroup(fgcnt).getTransactionSetCount() > 0) buildLoopTransactionSetResponseHeaderforTableHeader(table, inEnv.getFunctionalGroup(fgcnt), inDErr); } for (int fgcnt = 0; fgcnt < inEnv.getFunctionalGroupCount(); fgcnt++) buildSegmentFunctionalGroupResponseTrailerforTableHeader(table, inEnv.getFunctionalGroup(fgcnt), fgInErr, acceptedTSs); buildSegmentTransactionSetTrailerforTableHeader(table); ts.setTrailerFields(); Segment interchange_Control_Trailer = env.createInterchange_Trailer(); interchange_Control_Trailer.useDefault(); for (int i = 0; i < env.getFunctionalGroupCount(); i++) { env.getFunctionalGroup(i).setCountInTrailer(); for (int j = 0; j < env.getFunctionalGroup(i).getTransactionSetCount(); j++) { env.getFunctionalGroup(i).getTransactionSet(j).trim(); env.getFunctionalGroup(i).getTransactionSet(j).setTrailerFields(); } } env.setFGCountInTrailer(); } /** builds segment ST that is part of the TableHeader *<br>Transaction Set Header used *<br>To indicate the start of a transaction set and to assign a control number * @param inTable table containing this segment * @return segment object ST * @throws OBOEException - most likely segment not found */ public Segment buildSegmentTransactionSetHeaderforTableHeader(Table inTable) throws OBOEException { Segment segment = inTable.createSegment("ST"); inTable.addSegment(segment); DataElement de; de = (DataElement) segment.buildDE(1); // 143 Transaction Set Identifier Code de.set("997"); de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number de.set(getNextControlNumber("200")); segment.useDefault(); return segment; } /** builds segment AK1 that is part of the TableHeader *<br>Functional Group Response Header used *<br>To start acknowledgment of a functional group * @param inTable table containing this segment * @param inFG functional group we are responding to * @throws OBOEException - most likely segment not found */ public Segment buildSegmentFunctionalGroupResponseHeaderforTableHeader(Table inTable, FunctionalGroup inFG) throws OBOEException { Segment segment = inTable.createSegment("AK1"); inTable.addSegment(segment); DataElement de; de = (DataElement) segment.buildDE(1); // 479 Functional Identifier Code de.set(inFG.getHeader().getDataElement("479").get()); de = (DataElement) segment.buildDE(2); // 28 Group Control Number de.set(inFG.getHeader().getDataElement("28").get()); segment.useDefault(); return segment; } /** builds loop AK2 that is part of the TableHeader *<br>Transaction Set Response Header used * @param inTable table containing this segment * @param inFG functional group containing transaction sets we're responding to * @param inDErr possible errors are contained in this. * @throws OBOEException - most likely segment not found */ public Loop buildLoopTransactionSetResponseHeaderforTableHeader(Table inTable, FunctionalGroup inFG, DocumentErrors inDErr) throws OBOEException { Loop loop = inTable.createLoop("AK2"); inTable.addLoop(loop); for (int tscnt = 0; tscnt < inFG.getTransactionSetCount(); tscnt++) { tsInErr = false; buildSegmentTransactionSetResponseHeaderforLoopAK2(loop, inFG.getTransactionSet(tscnt), inDErr); } if (tsInErr) buildSegmentTransactionSetResponseTrailerforLoopAK2(loop, "R", "5"); else { buildSegmentTransactionSetResponseTrailerforLoopAK2(loop, "A", null); acceptedTSs++; } return loop; } /** builds segment AK2 that is part of the LoopAK2 *<br>Transaction Set Response Header used *<br>To start acknowledgment of a single transaction set * @param inLoop loop containing this segment * @return segment object AK2 * @throws OBOEException - most likely segment not found */ public Segment buildSegmentTransactionSetResponseHeaderforLoopAK2(Loop inLoop, TransactionSet inTS, DocumentErrors inDErr) throws OBOEException { Segment segment = inLoop.createSegment("AK2"); inLoop.addSegment(segment); DataElement de; de = (DataElement) segment.buildDE(1); // 143 Transaction Set Identifier Code de.set(inTS.getID()); //not quite the same but just as effective de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number de.set(inTS.getHeaderTable().getSegment("ST").getDataElement("329").get()); // get the header table then the ST segment Table inTbl = null; while (true) { if (inTbl == inTS.getSummaryTable()) break; else if (inTbl == inTS.getDetailTable()) inTbl = inTS.getSummaryTable(); else if (inTbl == inTS.getHeaderTable()) inTbl = inTS.getDetailTable(); else if (inTbl == null) inTbl = inTS.getHeaderTable(); if (inTbl == null) break; for (int i = 0; i < inDErr.getErrorCount(); i++) { if (inDErr.getContainer(i) == inTbl) { buildLoopAndSegmenAK3forTableHeaderLoopAK2(inLoop, inDErr.getErrorID(i), inDErr.getErrorPosition(i), inDErr.getErrorCode(i)); } } for (int i = 0; i < inTbl.getContainerSize(); i++) if (inTbl.isSegment(i)) checkSegment(inLoop, inTbl.getSegment(i), inDErr); else if (inTbl.isLoop(i)) checkLoop(inLoop, inTbl.getLoop(i), inDErr); else if (inTbl.isVector(i)) { for (int j = 0; j < inTbl.getSegmentCount(i); j++) { if (inTbl.isSegment(i,j)) checkSegment(inLoop, inTbl.getSegment(i,j), inDErr); else if (inTbl.isLoop(i,j)) checkLoop(inLoop, inTbl.getLoop(i,j), inDErr); } } } return segment; } /** works with loops looking to see if DocumentError object is pointing at any of its elements * @param loopAK2forAK3 loop to contain the reporting AK3 * @param loop * @param inDErr DocumentErrors object */ public void checkLoop(Loop loopAK2forAK3, Loop inLoop, DocumentErrors inDErr) { for (int i = 0; i < inDErr.getErrorCount(); i++) { if (inDErr.getContainer(i) == inLoop) { tsInErr = true; fgInErr = true; buildLoopAndSegmenAK3forTableHeaderLoopAK2(loopAK2forAK3, inDErr.getErrorID(i), inDErr.getErrorPosition(i), "1"); return; } } for (int i = 0; i < inLoop.getContainerSize(); i++) if (inLoop.isSegment(i)) checkSegment(inLoop, inLoop.getSegment(i), inDErr); else if (inLoop.isLoop(i)) checkLoop(inLoop, inLoop.getLoop(i), inDErr); else if (inLoop.isVector(i)) { for (int j = 0; j < inLoop.getSegmentCount(i); j++) { if (inLoop.isSegment(i,j)) checkSegment(inLoop, inLoop.getSegment(i,j), inDErr); else if (inLoop.isLoop(i,j)) checkLoop(inLoop, inLoop.getLoop(i,j), inDErr); } } } /** works with individual segments looking to see if DocumentError object is pointing at it * @param loopAK2forAK3 loop to contain the reporting AK3 * @param testSeg segment we are testing * @param inDErr DocumentErrors object */ public void checkSegment(Loop loopAK2forAK3, Segment testSeg, DocumentErrors inDErr) { for (int i = 0; i < inDErr.getErrorCount(); i++) { if (inDErr.getContainer(i) == testSeg) { tsInErr = true; fgInErr = true; if ((inDErr.getErrorObject(i) instanceof Segment) || (inDErr.getErrorObject(i) instanceof TemplateSegment)) { buildLoopAndSegmenAK3forTableHeaderLoopAK2(loopAK2forAK3, inDErr.getErrorID(i), inDErr.getErrorPosition(i), inDErr.getErrorCode(i)); } else if ((inDErr.getErrorObject(i) instanceof TemplateDE) || (inDErr.getErrorObject(i) instanceof TemplateComposite) || (inDErr.getErrorObject(i) instanceof DataElement) || (inDErr.getErrorObject(i) instanceof CompositeDE)) { Loop ak3Loop = buildLoopAndSegmenAK3forTableHeaderLoopAK2( loopAK2forAK3, inDErr.getErrorID(i), inDErr.getErrorPosition(i)); buildSegmentAK4forTableHeaderLoopAK2LoopAK3(ak3Loop, inDErr.getErrorObject(i), inDErr.getErrorCode(i), inDErr.getErrorID(i)); } else if (inDErr.getErrorDescription(i).startsWith( "Unknown or out of place segment")) buildLoopAndSegmenAK3forTableHeaderLoopAK2(loopAK2forAK3, inDErr.getErrorID(i), inDErr.getErrorPosition(i), "1"); } } } /** * builds loop and segment AK3 that is part of the TableHeader LoopAK2 <br> * Data Segment Note used <br> * To report errors in a data segment and identify the location of the data * segment * * @param inLoop * loop containing this subsegment, the AK2 loop * @param errID * segment ID in error * @param errPos * int * @throws OBOEException - * most likely segment not found * @returns Loop the AK3 loop that was built so the AK4 can be attached * later */ public Loop buildLoopAndSegmenAK3forTableHeaderLoopAK2(Loop inLoop, String errID, int errPos) throws OBOEException { tsInErr = true; fgInErr = true; Loop ak3Loop = inLoop.createLoop("AK3"); inLoop.addLoop(ak3Loop); Segment segment = ak3Loop.createSegment("AK3"); ak3Loop.addSegment(segment); DataElement de; /* segment.useDefault(); */ de = (DataElement) segment.buildDE(1); // 721 Segment ID Code de.set(errID); de = (DataElement) segment.buildDE(2); // 719 Segment Position in Transaction Set de.set(errPos+""); // change the int to a String return ak3Loop; } /** builds loop and segment AK3 that is part of the HeaderAK2 *<br>Data Segment Note used *<br>To report errors in a data segment and identify the location of the data segment * @param inLoop loop containing this subsegment, the AK2 loop * @param errID segment ID containing errors * @param errPos int * @param errCode String value as reported by parser * @throws OBOEException - most likely segment not found */ public Loop buildLoopAndSegmenAK3forTableHeaderLoopAK2(Loop inLoop, String errID, int errPos, String errCode) throws OBOEException { tsInErr = true; fgInErr = true; Loop ak3Loop = inLoop.createLoop("AK3"); inLoop.addLoop(ak3Loop); Segment segment = ak3Loop.createSegment("AK3"); ak3Loop.addSegment(segment); DataElement de; /* segment.useDefault(); */ de = (DataElement) segment.buildDE(1); // 721 Segment ID Code de.set(errID); de = (DataElement) segment.buildDE(2); // 719 Segment Position in Transaction Set de.set(errPos+""); // change the int to a String de = (DataElement) segment.buildDE(3); // 447 Loop Identifier Code de.set(""); // loop ID not used de = (DataElement) segment.buildDE(4); // 720 Segment Syntax Error Code de.set(errCode); return ak3Loop; } /** builds segment AK4 that is part of the HeaderAK2AK3 *<br>Data Element Note used *<br>To report errors in a data element or composite data structure and identify the location of the data element * @param inLoop containing this subsegment * @param inErrObject object causing the error * @param errCode 723 error code * @param errID field id in error * @throws OBOEException - most likely segment not found */ public Segment buildSegmentAK4forTableHeaderLoopAK2LoopAK3(Loop inLoop, Object inErrObject, String errCode, String errID) throws OBOEException { Segment segment = inLoop.createSegment("AK4"); inLoop.addSegment(segment); DataElement de; /* segment.useDefault(); */ if (inErrObject instanceof CompositeDE) { CompositeDE composite = (CompositeDE) segment.buildDE(1); // C030 Position in Segment CompositeDE errcde = (CompositeDE) inErrObject; de = (DataElement) composite.buildDE(1); // composite element 722 Element Position in Segment de.set(errcde.getSequence()+""); de = (DataElement) composite.buildDE(2); // composite element 1528 Component Data Element Position in Composite de.set(""); } else if (inErrObject instanceof TemplateComposite) { CompositeDE composite = (CompositeDE) segment.buildDE(1); // C030 Position in Segment TemplateComposite errcde = (TemplateComposite) inErrObject; de = (DataElement) composite.buildDE(1); // composite element 722 Element Position in Segment de.set(errcde.getSequence()+""); de = (DataElement) composite.buildDE(2); // composite element 1528 Component Data Element Position in Composite de.set(""); } de = (DataElement) segment.buildDE(2); // 725 Data Element Reference Number de.set(errID); de = (DataElement) segment.buildDE(3); // 723 Data Element Syntax Error Code de.set(errCode); if (inErrObject instanceof DataElement) { DataElement derr = (DataElement) inErrObject; de = (DataElement) segment.buildDE(4); // 724 Copy of Bad Data Element de.set(derr.get()); } return segment; } /** builds segment AK5 that is part of the HeaderAK2 *<br>Transaction Set Response Trailer used *<br>To acknowledge acceptance or rejection and report errors in a transaction set * @param inLoop Loop that will hold the AK5 segment to be built, an AK2. * @param accRej - "A" or "R" * @param code - 718 code indicating type of error * @throws OBOEException - most likely segment not found */ public void buildSegmentTransactionSetResponseTrailerforLoopAK2(Loop inLoop, String accRej, String code) throws OBOEException { Segment segment = inLoop.createSegment("AK5"); inLoop.addSegment(segment); DataElement de; /* segment.useDefault(); */ de = (DataElement) segment.buildDE(1); // 717 Transaction Set Acknowledgment Code de.set(accRej); if (code != null) { de = (DataElement) segment.buildDE(2); // 718 Transaction Set Syntax Error Code de.set(code); } } /** builds segment AK9 that is part of the TableHeader * @param inTable table containing the AK9 segment to be built * @param inFG functional group reporting on * @param boolean error or no error * @param int - number of accepted TSs. * @throws OBOEException - most likely segment not found */ public Segment buildSegmentFunctionalGroupResponseTrailerforTableHeader(Table inTable, FunctionalGroup inFG, boolean inErr, int acceptCnt) throws OBOEException { Segment segment = inTable.createSegment("AK9"); inTable.addSegment(segment); DataElement de; /* segment.useDefault(); */ de = (DataElement) segment.buildDE(1); // 715 Functional Group Acknowledge Code if (inErr) de.set("R"); else de.set("A"); de = (DataElement) segment.buildDE(2); // 97 Number of Transaction Sets Included de.set(inFG.getTrailer().getDataElement("28").get()); de = (DataElement) segment.buildDE(3); // 123 Number of Received Transaction Sets de.set(inFG.getTransactionSetCount()+""); de = (DataElement) segment.buildDE(4); // 2 Number of Accepted Transaction Sets de.set(acceptCnt+""); /* de = (DataElement) segment.buildDE(5); // 716 Functional Group Syntax Error Code de.set(""); */ return segment; } /** builds segment SE that is part of the TableHeader *<br>Transaction Set Trailer used *<br>To indicate the end of the transaction set and provide the count of the transmitted segments (including the beginning (ST) and ending (SE) segments) * @param inTable table containing this segment * @return segment object SE * @throws OBOEException - most likely segment not found */ public Segment buildSegmentTransactionSetTrailerforTableHeader(Table inTable) throws OBOEException { Segment segment = inTable.createSegment("SE"); inTable.addSegment(segment); DataElement de; de = (DataElement) segment.buildDE(1); // 96 Number of Included Segments de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number segment.useDefault(); return segment; } /** routine to return a control number - not very useful. here to satisfy the compiler */ static int num = 0; public String getNextControlNumber(String what) { return what + "0000" + num++; } /** the application main method. * <br>format: java build997 X12FileToBeParsed * @param String arg[0] X12 file to be parsed * @return nothing. 997 output is written to system.out file */ public static void main(String args[]) { DocumentErrors de = new DocumentErrors(); //create a empty document errors in case there aren't any X12DocumentHandler dh = new X12DocumentHandler(); try { dh.startParsing(new java.io.FileReader(args[0])); } catch (OBOEException oe) // the application assumes an error exists { de = oe.getDocumentErrors(); for (int i = 0; i < de.getErrorCount(); i++) { System.out.println(i + " " + de.getErrorCode(i) + " " + de.getErrorID(i) + " " + de.getErrorDescription(i)); } } catch (java.io.IOException ioe) { ioe.printStackTrace(); } finally { build997 b = new build997((X12Envelope) dh.getEnvelope(), de); System.out.println(b.env.getFormattedText(Envelope.X12_FORMAT)); } } }