Projects:SAP ECC Integration/How to Create an Idoc Based on a Template
Contents |
Introduction
The SAP ECC Connector infrastructure generates the exported iDocs using the freemarker template technology.
For each iDoc type, two components must be built:
- A template. A template file that will describe the structure of the iDoc file. It will contain placeholders that will be replaced with the actual values of the exported records.
- A template component, a Java class that will be used by freemarker to populate the template. It will read the values from a properties file, that is automatically created by the connector infrastructure after applying the mappings to the exported record.
Export Process Overview
The following image describes how the export process work:
Creating an iDoc Template
To create an iDoc template, developers have to:
- Add an entry to the Template window, filling in the following fields:
- The SAP ECC Mappings modules
- A name for the template (it is not referenced anywhere else)
- iDoc Template as Component Type
- SAP ECC Idoc Template Language as Template Language
- The relative path the to the .ftl template file from the src/ folder of the module
- Create the .FTL file and place it in the path set in the template.
For instance, this is the template definition for the PUBON iDoc:
The template files have some parts that are fixed, and some parts that will vary depending on the record being exported. There are two ways to define non-fixed data:
Using the ${variableName.attributeName} placeholder. variableName is the name of a component template instance. Freemarker will replace ${variableName.attributeName} with the result of invoking the getAttributeName method on the given component template. The variable name for the main component template is ‘data’. The name for other sub component templates is given using the #list tag, which is the second way to define non-fixed data. Code content in a #list tag will be repeated, and its ${} blocks will be filled in using different sources.
For instance, consider the following snipped from the PUBON template:
${data.documentNumber} will be replaced by the result of invoking the getDocumentNumber method on the main component template. For instance, if the order with document number 001 is being exported:
<BONNUMMER>${data.documentNumber}</BONNUMMER> will be replaced by <BONNUMMER>001</BONNUMMER>
If the order has two lines (1 item of product ‘Chair’, 2 items of product ‘Table’), then
<E1WPB02 SEGMENT="1"> <QUALARTNR>ARTN</QUALARTNR> <ARTNR>${line.product}</ARTNR> <MENGE>${line.quantity}</MENGE> </E1WPB02>
Will be replaced by:
<E1WPB02 SEGMENT="1"> <QUALARTNR>ARTN</QUALARTNR> <ARTNR>Chair</ARTNR> <MENGE>1</MENGE> </E1WPB02> <E1WPB02 SEGMENT="1"> <QUALARTNR>ARTN</QUALARTNR> <ARTNR>Table</ARTNR> <MENGE>2</MENGE> </E1WPB02>
Freemarker will know that there are two lines because the getOrderLines method of the main component template will return two lines.
Defining the Template Components
There are two types of SAP ECC template components:
- The main template component of each iDoc
- Sub template components, one for each #list tag declared in the iDoc.
In the PUBON example, there are three component templates:
- One for the order entity
- One for order line entity
- One for the order payment entity
The java implementation of the main component have to:
- Be declared as @ApplicationScoped, so that the dependency injection engine is able to inject it properly.
- Declare a @IdocType qualifier with the name of the mapped entity in SAP ECC
- Extend the IdocTemplate class, and overwrite the getTemplateId, which returns the ID of the template being generated
For instance, this is the header of the main component template for the PUBON template:
The classes that implement the subcomponent templates must extend the PropertiesHolder interface. They must keep a Map<String, Object> attribute, that they will receive in the constructor and that they will return in the getProperties method, like this:
Their instances are manually created from the getter methods of the main component template, for instance, when freemaker processes this line:
<#list data.orderLines as line>
It will invoke the getOrderLines of PubonOrder, that will create instances of PubonOrderLine, like this:
There must be an Entity Mapping per component template. The main one (Order in this case) must set the Is First Level Mapping flag to true, the rest must be set to false.
Modeling blablabla
This section TODO
Modeling a Simple Property
For instance, the BONNUMMER tag represents the document number of the order. The ${data.documentNumber} placeholder is placed in the value of that tag.
Freemarker will know that it must call the getDocumentNumber method on the provided template component to replace the value of the placeholder.
And this is the definition of the property mapping, where the relation between the BONNUMBER SAP ECC property and the documentNo property of the Order is defined:
The image above shows the mapping definition done in the application dictionary, but it also applies with java mappings. In that case, the name of the property returned in the getPropertySorting should be the name that the template component will use to obtain the value from the properties map (BONNUMMER in this case).
The following image summarized mapping of a single property:
Modeling a Segment that Can Be Repeated
For segments that can be repeated several times, the #list instruction must be used. For instance, an order can have several order lines, each one is represented by the E1WPB02 segment. The following code is used in the template to represent this:
Freemarker will retrieve the order lines by invoking the getOrderLines method of the Order template component:
Note that a List of PubonOrderLine, which is the template component for order lines is returned. A new instance is added to this list for each order line.
This is the definition of the property mapping instance of the Order.orderLines property:
Because its mapping name is E1WPB02, the info about the order lines will be available by getting the value for the E1WPB02 key in the properties map.
There are several things to note:
- The orderLineList property of Order returns a list of order lines
- Because of this, the OneToManyEntityPropertyMapping property mapping class is used.
- The Mapping Name is the key used to obtain the order lines in the getOrderLines method of the Order component template.
- Because each orderLine entry represents a whole segment and not a single property, a new Entity Mapping is required to map the order lines, and is referenced by the Referenced Entity Mapping field.
This is the definition of the OrderLine entity mapping: