import com.americancoders.edi.*;
import com.americancoders.edi.x12.*;
/** code template to build
*
class 997 Functional Acknowledgment
*
* 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
*
Transaction Set Header used
*
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
*
Functional Group Response Header used
*
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
*
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
*
Transaction Set Response Header used
*
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
* Data Segment Note used
* 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
*
Data Segment Note used
*
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
*
Data Element Note used
*
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
*
Transaction Set Response Trailer used
*
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
*
Transaction Set Trailer used
*
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.
*
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));
}
}
}