I start the process by first creating a X12-997 parsing program using the OBOECodeGenenerator.
Then I discuss the changes to the program I made. Using a standard text editor a final program
is created that shows you how objects are used to get to data and create a different type of
EDI document.
- Using the OBOECodeGenerator class create a source program that builds 997 transactions.
java com.americancoders.util.OBOECodeGenerator x12.envelope.xml bJ 997 build997.java
The Generated Program
Another alternative to generating a program from the command line is to use the Swing
application RulesAndCodeBuilder that is also part of the util package.
- Using a text editor, edit the newly created source program build997.java
- The source program class will create a 997 document but it needs data. The data will come from
an already OBOE parsed EDI document that may or may not be valid. So we change
the constructor to accept two parameters, the parsed document, in this case an X12Envelope object, and
the DocumentErrors object created when the envelope object was created.
public build997(X12Envelope inEnv, DocumentErrors inDErr)
- Don't forget to keep the source program documentation up to date. So change
/** constructor for class build997
*@throws OBOEException - most likely transactionset not found
*/
to read as
/** 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
*/
- So the constructor now looks like
/** 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)
- Now we need to populate the ISA segment data
If we were using the Extended Edition we could set up default functionality
in the OBOE rules file. But since we're not, let's go through the steps for giving
values to each data element object.
- remove the lineinterchange_Control_Header.useDefault();
- add the following:
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());
- we could have added an import com.americancoders.util; to simplify some of the previous statements.
- We are not using the Grade of Service or Deferred Delivery
request segments. So we remove the following code
// Grade of Service Request not required
Segment grade_of_Service_Request = Grade_of_Service_Request.getInstance();
grade_of_Service_Request.useDefault();
// Deferred Delivery Request not required
Segment deferred_Delivery_Request = Deferred_Delivery_Request.getInstance();
deferred_Delivery_Request.useDefault();
- Now we need to populate one functional group for the outbound document.
So we work the GS segment and its dataelements.
The segment is available to us through the variable fgHeader. Using data from the incoming Envelope,
using some static methods in the Util class, and hard coding other values we can fill all the
GS dataelements. So after the lines of code where the program sets
the fg header segment we add code to populate its dataelements.
Replace the statement fgHeader.useDefault(); with
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
- Now we need to populate our documents ST segment data. So go to the method named
buildSegmentTransactionSetHeaderforTableHeader(Table...
and change the last set statement to fill in the transaction set control number. Again we using the
class method getNextControlNumber. The call goes from
de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number
de.set("");
to
de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number
de.set(getNextControlNumber("200"));
- For each functional group in the incoming Envelope object we generate an AK1 segment and later an AK9
segment. The code generator doesn't do
everything for us so we need to pass the functional group we are currently working on to the method.
We change the method buildSegmentFunctionalGroupResponseHeaderforTableHeader,
which builds the AK1 response segment. There
is one AK1 for each functional group in the incoming document.
* @param inTable table containing this segment
* @throws OBOEException - most likely segment not found
*/
public Segment buildSegmentFunctionalGroupResponseHeaderforTableHeader(Table inTable)
to accept the functionalgroup object as
* @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)
Notice the documentation change.
- Next we replace the ubiquitous de.set("") statements
de = (DataElement) segment.buildDE(1); // 479 Functional Identifier Code
de.set("");
de = (DataElement) segment.buildDE(2); // 28 Group Control Number
de.set("");
to use the parsed inFG dataelements.
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());
- For each transaction set in a functional group the outgoing document needs an AK2.
And hanging off of the AK2 segment is a AK3 loop and a AK5 segment. The AK3 loop contains
a AK3 and AK4 segment
The AK3 loop and AK5 segment report on each transaction set, AK3 for segment notes
and AK5 for response indicators
for the transaction set. And with the AK3 segment, the
AK4s are for reporting problems with specific
data elements of the segment reported by the AK3 segment.
- As with the other methods generated by the OBOECodeGenerator utility,
we change the buildLoopTransactionSetResponseHeaderforTableHeader to accept two additional parameters,
the transactionset we responding to and the DocumentErrors object that contains the error information.
* @throws OBOEException - most likely segment not found
*/
public Loop buildLoopTransactionSetResponseHeaderforTableHeader(Table inTable)
is replaced with
* @param inTable table containing this segment
* @param inFG functional group with 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)
Likewise up in the constructor we need to change the method call
buildLoopTransactionSetResponseHeaderforTableHeader(table);
to
buildLoopTransactionSetResponseHeaderforTableHeader(table, inEnv.getFunctionalGroup(fgcnt).getTransactionSet(tscnt), inDErr);
- Since the generator built logic for the segment within the AK2 loop we update the buildSegmentAK2... call and
method. But this time we will be using the incoming transaction set object and the document errors object.
We replace the call
buildSegmentTransactionSetResponseHeaderforLoopAK2(loop);
with
buildSegmentTransactionSetResponseHeaderforLoopAK2(loop, inTS, inDErr);
Similarly the method itself is changed from
* @param inLoop loop containing this segment
* @returns segment object AK2
* @throws OBOEException - most likely segment not found
*/
public Segment buildSegmentTransactionSetResponseHeaderforLoopAK2(Loop inLoop) throws OBOEException
to
* @param inLoop loop containing this segment
* @param inTS transactionset we're responding to
* @param inDErr possible errors are contained in this.
* @returns segment object AK2
* @throws OBOEException - most likely segment not found
*/
public Segment buildSegmentTransactionSetResponseHeaderforLoopAK2(Loop inLoop, TransactionSet inTS, DocumentErrors inDErr) throws OBOEException
- We change the dummy set statements with useful information from the inTS object.
de = (DataElement) segment.buildDE(1); // 143 Transaction Set Identifier Code
de.set(inTS.getID());
de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number
de.set("");
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
- Now to report on the individual segment errors we need to drill down
through the incoming OBOE transaction set object to find the
segments referenced by the DocumentErrors object. We can do this recursively
since the DocumentErrors objects reference SegmentContainers. SegmentContainers
are implemented by several different OBOE objects which can contain other implemented SegmentContainers
hence allowing for recursion.
We will work primarily with the generated method buildSegmentDataSegmentNoteforLoopAK3.
And we will need two similar methods
one to work with a AK3 segment to report specific segment errors and the other to create AK3 that will
also contain AK4s to report data element errors within a segment.
First, the drill done logic is written. We simply go through looking for each of the three
possible Table object. If one is found we drill down through each of its segments until the last
table has been processed.
While we check the transaction set we add a boolean to track if the transaction set
has any errors, likewise the functional group. And we track the number of transaction sets that
are acceptable. So at the very top of the program we add three class attributes to do this for
us.
boolean fgInErr=false;
boolean tsInErr=false;
int acceptedTSs = 0;
Obviously we need to set these booleans at the appropriate places. So we set the fgInErr boolean
as we loop trough each functional group in the incoming object. So back in the constructor we add
the following code. And we will edit the call to build the AK1 segment for each functional group
and AK2 for each transaction set within a functional group.
We replace
buildSegmentFunctionalGroupResponseHeaderforTableHeader(table);
// for (i = 0; i < multipletimes; i++)
buildLoopTransactionSetResponseHeaderforTableHeader(table, inEnv.getFunctionalGroup(fgcnt).getTransactionSet(tscnt), inDErr);
with
for (int fgcnt = 0; fgcnt < inEnv.getFunctionalGroupCount(); fgcnt++)
{
acceptedTSs = 0;
fgInErr = false;
buildSegmentFunctionalGroupResponseHeaderforTableHeader(table, inEnv.getFunctionalGroup(fgcnt));
}
Work must be done to populate the AK2 segment. So in the buildLoopTransactionSetResponseHeaderforTableHeader method we
replace the call to build the AK2 segment
buildLoopTransactionSetResponseHeaderforTableHeader(loop);
with
if (inEnv.getFunctionalGroup(fgcnt).getTransactionSetCount() > 0)
buildLoopTransactionSetResponseHeaderforTableHeader(table,
inEnv.getFunctionalGroup(fgcnt),
inDErr);
And we update buildLoopTransactionSetResponseHeaderforTableHeader by replacing
buildSegmentTransactionSetResponseHeaderforLoopAK2(loop, inTS);
with
for (int tscnt = 0; tscnt < inFG.getTransactionSetCount(); tscnt++)
{
tsInErr = false;
buildSegmentTransactionSetResponseHeaderforLoopAK2(loop, inFG.getTransactionSet(tscnt), inDErr);
}
Then down in method buildSegmentTransactionSetResponseHeaderforLoopAK2
we add the code that goes through each table object. As a
segment container object and it matches the DocumentErrors container object, found
with the getContainer method call, we report the segment in error by building an AK3.
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)
{
buildLoopDataSegmentNoteforLoopAK2(inLoop,
inDErr.getErrorID(i),
inDErr.getErrorPosition(i),
inDErr.getErrorCode(i));
}
}
- If you notice, the while (true) loop is not closed. That is to show that we also
need to check the loops and segments within the table.
First we need to write two new methods. I call them checkLoop and checkSegment.
These methods will take four arguments:
- the AK3 container, the AK2 loop
- the segment container holding the erroneous segment. The container in this method is the table.
- the position of the segment within the container object
- and the reported error code.
So inside the while (true) loop we add the call
for (int i = 0; i < inTbl.getContainerSize(); i++)
if (inTbl.isSegment(i))
checkSegment(inLoop, inTbl.getSegment(i), inDErr);
else
if (inTbl.isLoop(i))
checkSegment(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))
checkSegment(inLoop, inTbl.getLoop(i,j), inDErr);
}
}
Notice the check for vectors using the isVector call. This is because Loops and Segments can
occur multiple times within its container. For these multiply occurring objects OBOE contains them
in a Vector object.
Again,
the code checks to see if the position
parameter points to a vector object. If what is held in that position is a vector then the code
gets the element type at each vector position and calls the appropriate method.
And finally the method checkSegment, the one that does the individual segment checking,
is called if the position points to an
individual segment. Both methods are presented below. It is in the checkSegment
method where the application determines if the error is at the segment level,
thereby generating
only an AK3 segment or at the data level and so the method needs to generate both an AK3 and the AK3's
AK4 subsegment.
If the reported container is a Loop object the error is reported.
Note: This error can only be an unknown segment.
Since loops implement the loopContainer interface, like tables in the
previous method discussion, we can now recursively call
the checkLoop method for loops that are contained by other loops
/** 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");
}
}
- We now alter the call to AK3 loops and segments
Instead of simply passing it the outbound
SegmentContainer object we pass error information and other codes.
Also since we are building
the AK4 outbound segment we need to reference its parent AK3 loop.
So we alter one of the buildLoopAK3forTableHeaderLoopAK2 methods
and create a new second method, in which one of its new functions is to
return the outbound AK3 loop that the method creates for use with the AK4
To simply things will combine the process of building the AK3 loop and AK3 segment within one
method.
/** 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)l
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;
}
- We are almost done drilling down to the lowest levels of the OBOE object we will report
data element errors. As mentioned earlier the AK4 segment is used to do report dataelement
errors. Like all of the other
generated methods from the OBOECodeGenerator application there is not enough information
available to the method. So we change the
buildSegmentAK4forTableHeaderLoopAK2LoopAK3 method to accept more information. The information is
to populate the outbound AK4 segment.
Also the method needs to determine if it is reporting errors at the composite level or the
individual data element. The new code reads as follows:
/** 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 segment
* @param inErrObject 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;
}
- We are done drilling down through the transaction set object. Notice that in the new code
that if an error is found we set our class attribute variable tsInErr to true. This attribute
assists us in two ways. One, to send an Accept or Reject indicator in the AK5 outbound segment
And second, to keep a track of the accepted transactions sets for the AK9 segment.
So we edit the way the AK5 segment is built in the buildSegmentTransactionSetResponseTrailerforLoopAK2 method.
Two new parameters are added, the accept/reject value for the transactions set and the 718 syntax
error code. If the transaction set is being accepted then there is no reason to build the 718
data element. Here's the updated method.
/** 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);
}
}
- Back up in the method buildLoopTransactionSetResponseHeaderforTableHeader where
the code loops through the transaction sets we update the
call to the above method.
if (tsInErr)
buildSegmentTransactionSetResponseTrailerforLoopAK2(loop, "R", "5");
else
{
buildSegmentTransactionSetResponseTrailerforLoopAK2(loop, "A", null);
acceptedTSs++;
}
- And as we reported each transaction set in the incoming document with an AK2 AK5 segment combination
we report each functional group with a AK1 AK9 combo.
We update the code in the constructor method where we loop through each functional group. Here
the method call to buildSegmentFunctionalGroupResponseTrailerforTableHeader will pass the
functional group tested, the fgInErr attribute and the number of accepted transactions sets in the
functional group.
for (int fgcnt = 0; fgcnt < inEnv.getFunctionalGroupCount(); fgcnt++)
buildSegmentFunctionalGroupResponseTrailerforTableHeader(table, inEnv.getFunctionalGroup(fgcnt), fgInErr, acceptedTSs);
- And the updated buildSegmentFunctionalGroupResponseTrailerforTableHeader now reads as:
/** builds segment AK9 that is part of the Header
*
Functional Group Response Trailer used
*
To acknowledge acceptance or rejection of a functional group and report the number of included transaction sets from the original trailer, the accepted sets, and the received sets in this functional group
* @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;
}
- We are almost done. To close our 997 transaction the code sets the SE segment. Remembering that
the OBOECodeGenerator class build very generic code. We need to clean some of the SE logic up.
In the method buildSegmentSEforTableHeader remove the de.set("") statements and add code in the constructor
that instructs the
transactionset object populate the two dataelements.
from
de = (DataElement) segment.buildDE(1); // 96 Number of Included Segments
de.set("");
de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number
de.set("");
to
de = (DataElement) segment.buildDE(1); // 96 Number of Included Segments
de = (DataElement) segment.buildDE(2); // 329 Transaction Set Control Number
In the constructor add the following by changing
buildSegmentTransactionSetTrailerforTableHeader(table);
to
buildSegmentTransactionSetTrailerforTableHeader(table);
ts.setTrailerFields();
- We are now done. So close our functional group. Since
the generator adds the following code inside a simple loop.
env.getFunctionalGroup(i).setCountInTrailer();
,
which sets the count and the control code, there's nothing really to do.
- Finish up our document with an IEA segment. The generator adds the following code
env.setFGCountInTrailer();
which sets the FG count and the ISA control code in the IEA segment, so, again, there's nothing really to do.
- Things added.
- We needed a method to generate control numbers. Here's mine but it's not too effective.
/** 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++;
}
- And for testing I usually add a main method
to the class to test from the command line.
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));
}
}
- The Finished Product