IBM Support

How to create a PDF in Sterling B2B Integrator

Technical Blog Post


Abstract

How to create a PDF in Sterling B2B Integrator

Body

Although Sterling B2B Integrator can create reports in PDF format, this code is not exposed to the user and currently no Service or Adapter within SBI creates PDF output.  Be that as it may, creating PDF output is nevertheless possible using Apache's fop. The solution outlined here is by no means the only method by which one could accomplish this. Nonetheless, herewith is one approach to creating PDFs in Sterling B2B Integrator.

 

The first step was to download Apache's fop 2.2 classes (as of this writing, these can be found at https://xmlgraphics.apache.org/fop/download.html.) I chose the binary version, which did not require any compilation - I merely un-gzipped and un-tarred the downloaded file. The resulting fop-2.2 directory resided in the home directory of the administrative user for the SBI environment..  I was now ready to create the Sterling B2B Integrator components needed to create the PDF.  The input file in this case was a flat file:

10ACMEPROD       850   102055720160125 TECHSUPP
20STTECHNICAL SUPPORT, INC. WEST  T20020159      1234 FRANKLIN AVENUE     HOLLYWOOD      FL33019     USA
301210     1VPEA     3USDPE    505.00
40MONOCULAR MICROSCOPE
404X,10X,40X,100X (OIL)
40ACHROMATIC (DIN) 20W HALOGEN
301222     2VPPK     2USDPE    19.75
40LOW FORM GRADUATED GLASS BEAKER
40250 ML
4012 PER PACK
50    2   1561.20

Since fop handles XML easily, I first created a map to translate the flat file to XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Inbound>
    <CustomerIDCode>TECHSUPP</CustomerIDCode>
    <OrderNum>1020557</OrderNum>
    <OrderDate>20170501</OrderDate>
    <Address>
        <AddressCode>BILL TO</AddressCode>
        <AddressName>TECHNICAL SUPPORT, INC. WEST</AddressName>
        <AddressStreet>7025 FRANKLIN AVENUE</AddressStreet>
        <AddressCity>HOLLYWOOD</AddressCity>
        <AddressState>FL</AddressState>
        <AddressPostCode>33019</AddressPostCode>
        <AddressCountry>USA</AddressCountry>
    </Address>
    <Item>
        <ItemLineNum>1</ItemLineNum>
        <ItemCode>1210</ItemCode>
        <ItemCurrency>US Dollar</ItemCurrency>
        <ItemSoldBy>Each</ItemSoldBy>
        <ItemQuantity>3</ItemQuantity>
        <ItemPriceCode>Price Per Each</ItemPriceCode>
        <ItemPrice>505</ItemPrice>
        <Description>MONOCULAR MICROSCOPE</Description>
        <Description>4X,10X,40X,100X (OIL)</Description>
        <Description>ACHROMATIC (DIN) 20W HALOGEN</Description>
    </Item>
    <Item>
        <ItemLineNum>2</ItemLineNum>
        <ItemCode>1222</ItemCode>
        <ItemCurrency>US Dollar</ItemCurrency>
        <ItemSoldBy>Package</ItemSoldBy>
        <ItemQuantity>2</ItemQuantity>
        <ItemPriceCode>Price Per Each</ItemPriceCode>
        <ItemPrice>19.75</ItemPrice>
        <Description>LOW FORM GRADUATED GLASS BEAKER</Description>
        <Description>250 ML</Description>
        <Description>12 PER PACK</Description>
    </Item>
    <Totals>
        <TotalLineItems>2</TotalLineItems>
        <TotalOrderAmount>1554.50</TotalOrderAmount>
    </Totals>
</Inbound>

Now it was time to create the XSL with formatting commands to transform the XML into a wonderful Portable Document Format (PDF) file suitable for framing. Not knowing much about formatting XML, I muddled through until I had the following stylesheet:
 

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform&quot; xmlns:fo="http://www.w3.org/1999/XSL/Format"&gt;
    <xsl:template match="/">
        <fo:root>
            <fo:layout-master-set>
                <fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21cm" margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm">
                    <fo:region-body margin-top="3cm"/>
                    <fo:region-before extent="3cm"/>
                    <fo:region-after extent="1.5cm"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="simple">
                <fo:flow flow-name="xsl-region-body">
                    <xsl:apply-templates/>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
    <xsl:template match="Inbound">
        <xsl:text>Invoice</xsl:text>
        <fo:block>
            <xsl:apply-templates select="CustomerIDCode"/>
            <xsl:apply-templates select="Address/AddressCode"/>
            <xsl:for-each select="Item">
                <fo:block font-size="12pt" font-family="sans-serif" line-height="15pt" background-color="rgb(240,255,255)" text-align="left" white-space-collapse="false" space-after.optimum="12pt">
                    <fo:block>
                        <xsl:text>PO Line Number: </xsl:text>
                        <xsl:value-of select="./ItemLineNum"/>
                        <xsl:text>     Item Code: </xsl:text>
                        <xsl:value-of select="./ItemCode"/>
                        <xsl:text>     Quantity Ordered: </xsl:text>
                        <xsl:value-of select="./ItemQuantity"/>
                    </fo:block>
                    <fo:block>
                        <xsl:text>Price: $</xsl:text>
                        <fo:inline background-color="red" color="white">
                            <xsl:value-of select="./ItemPrice"/>
                        </fo:inline>
                    </fo:block>
                    <fo:block>
                        <xsl:text>Unit: </xsl:text>
                        <xsl:value-of select="./ItemSoldBy"/>
                    </fo:block>
                    <fo:block>
                        <fo:inline white-space-collapse="false">
                          <xsl:text>            Item Description: </xsl:text>
                        </fo:inline>
                    </fo:block>
                    <xsl:for-each select="./Description">
                        <fo:block>
                            <xsl:value-of select="."/>
                        </fo:block>
                    </xsl:for-each>
                    <fo:block>
                        <xsl:text>Total This Item: $</xsl:text>
                        <fo:inline background-color="red" color="white">
                            <xsl:value-of select="number(./ItemQuantity * ./ItemPrice)"/>
                        </fo:inline>
                    </fo:block>
                </fo:block>
            </xsl:for-each>
        </fo:block>
        <xsl:apply-templates select="Totals"/>
    </xsl:template>
    <xsl:template match="CustomerIDCode">
        <fo:block font-size="18pt" font-family="sans-serif" line-height="24pt" background-color="rgb(70,130,180)" color="white" text-align="center" padding-top="3pt" space-after.optimum="12pt">
            <fo:block>
                <xsl:text>Customer Identification Code: </xsl:text>
                <xsl:value-of select="."/>
            </fo:block>
            <fo:block>
                <xsl:text>Invoice for Order Number: </xsl:text>
                <xsl:value-of select="following-sibling::OrderNum"/>
            </fo:block>
            <fo:block>
                <xsl:text>Invoice Date: </xsl:text>
                <xsl:value-of select="following-sibling::OrderDate"/>
            </fo:block>
        </fo:block>
    </xsl:template>
    <xsl:template match="AddressCode">
        <fo:block font-size="12pt" font-family="sans-serif" line-height="15pt" background-color="rgb(240,255,240)" color="black" text-align="left" padding-top="3pt" white-space-collapse="false" space-after.optimum="12pt">
            <fo:block>
                <xsl:value-of select="."/>
                <xsl:text>:</xsl:text>
            </fo:block>
            <fo:block>
                <xsl:value-of select="following-sibling::AddressName"/>
            </fo:block>
            <fo:block>
                <xsl:value-of select="following-sibling::AddressStreet"/>
            </fo:block>
            <fo:block>
                <xsl:value-of select="following-sibling::AddressCity"/>
                <xsl:text>, </xsl:text>
                <xsl:value-of select="following-sibling::AddressState"/>
                <xsl:text>  </xsl:text>
                <xsl:value-of select="following-sibling::AddressPostCode"/>
            </fo:block>
            <fo:block>
                <xsl:value-of select="following-sibling::AddressCountry"/>
            </fo:block>
        </fo:block>
    </xsl:template>
    <xsl:template match="Totals">
        <fo:block font-size="14pt" font-family="sans-serif" line-height="16pt"  space-before.optimum="3pt" space-after.optimum="3pt" background-color="rgb(240,255,240)" color="black" text-align="left" padding-top="3pt" white-space-collapse="false">
            <fo:block>
                <xsl:text>Total Line Items: </xsl:text>
                <xsl:value-of select="./TotalLineItems"/>
            </fo:block>
            <fo:block>
                <xsl:text>Total Amount Due: $</xsl:text>
                <fo:inline background-color="red" color="white">
                    <xsl:value-of select="./TotalOrderAmount"/>
                </fo:inline>
            </fo:block>
            <fo:block>
                <xsl:text>Terms: 30 Days Net</xsl:text>
            </fo:block>
            <xsl:if test="ceiling(./TotalOrderAmount/text()) > 500">
                <fo:block>
                    <xsl:text>We're running a special this month on orders of $500 or more!</xsl:text>
                </fo:block>
                <fo:block>
                    <xsl:text>Pay within 15 days and receive a rebate of 2% off your order!</xsl:text>
                </fo:block>
                <fo:block>
                    <xsl:text>On today's order, you qualify for a savings of </xsl:text>
                    <xsl:value-of select="number(./TotalOrderAmount * .02)"/>
                    <xsl:text>!</xsl:text>
                </fo:block>
            </xsl:if>
        </fo:block>
    </xsl:template>
    <xsl:template match="OrderNum | OrderDate"/>
    <xsl:template match="AddressName | AddressStreet | AddressCity | AddressState | AddressCountry"/>
    <xsl:template match="ItemLineNum | ItemCode | ItemCurrency | ItemSoldBy | ItemQuantity | ItemPriceCode |  ItemPrice | Description"/>
    <xsl:template match="TotalLineItems | TotalOrderAmount"/>
</xsl:stylesheet>

 

It is probably not the most elegant stylesheet in the world, but it gave me something to use in my test.  Now I needed a business process:

<process name="create_PDF">
  <sequence>
    <operation name="Text to XML">
    <participant name="Translation"/>
      <output message="TranslationTypeInputMessage">
        <assign to="map_name">App_to_XML</assign>
        <assign to="validate_input">NO</assign>
        <assign to="validate_output">NO</assign>
        <assign to="." from="*"></assign>
      </output>
      <input message="inmsg">
        <assign to="." from="*"></assign>
      </input>
     </operation>
     <operation name="Command Line Adapter">
      <participant name="create_PDF_CLA"/>
      <output message="CmdLineInputMessage">
        <assign to="." from="*"/>
      </output>
      <input message="inmsg">
        <assign to="." from="*"/>
      </input>
    </operation>
    <assign to="PrimaryDocument" from="/ProcessData/CLA2/document/@SCIObjectID"/>
    <operation name="FSA">
    <participant name="save_PDF_FSA"/>
      <output message="Xout">
        <assign to="Action">FS_EXTRACT</assign>   
        <assign to="." from="*"/>
      </output>
      <input message="Xin">
        <assign to="." from="*"/>
      </input>
   </operation>
   <operation name="Release Service">
   <participant name="ReleaseService"/>
     <output message="ReleaseServiceTypeInputMessage">
       <assign to="TARGET">/ProcessData/CLA2</assign>
       <assign to="." from="*"/>
     </output>
     <input message="inmsg">
       <assign to="." from="*"/>
     </input>
     </operation>
  </sequence>
</process>

The Command Line Adapter merits a little more scrutiny.  It is configured as follows:

create_PDF_CLA
Service Settings
Service Type  Command Line Adapter
Description   create a PDF file using external fop
System Name   create_PDF_CLA
Group Name    None
Remote Name     localhost
Remote Port     30052
Command Line     /home/admin/fop-2.2/fop/fop -xml $Input -xsl /home/admin/pdf_fo.xsl $Output
Working Directory     None provided
Turn on debugging messages?     Yes
Wait on the process to complete before continuing?     Yes
Does this service start a Business Process?           No
Does the command line process require an input file?     Yes
Input Filename     None provided
Delete input file after process completes?     No
Use the output generated by the command line process?     Yes
Output Filename     ourPDF.pdf
Delete output file after process completes?     No
 

To fill out the picture, here is the File System Adapter's configuration:

save_PDF_FSA    
Service Settings
Service Type File System Adapter
Description Save the PDF to the File System
System Name save_PDF_FSA
Environment node1
Group Name None
Collection folder NONE
Filename filter None provided
Collect files from sub folders within and including the collection folder? No
Use the absolute file path name for the document name? No
Start a business process once files are collected? No
Extraction folder /opt/si/install/nonedioutbound/extract
Unobscure File Contents? No
Filenaming convention Assign a specific name
Filename ourPDF_%^.pdf

 

The moment of truth had come; it was time to test the map, stylesheet  and business process.  I kicked off the BP using the XML created by the translation map. The result was the colorful PDF that you see here:

image
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

This is admittedly a rather bare bones example, but if you find it useful. you can customize it to suit your business needs.
 

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SS3JSW","label":"IBM Sterling B2B Integrator"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11120497