Introduction
In today’s digital business landscape, automating invoice processing is essential for efficiency, accuracy, and compliance. I have implemented a robust SAP Cloud Platform Integration (CPI) iFlow that transforms incoming XML invoices into professional PDF documents-ready for distribution, archiving, or further processing.
This blog provides a comprehensive, step-by-step guide to building such a solution in SAP CPI, including the actual scripts used for HTML generation and PDF conversion.
Sample XML:
<?xml version=”1.0″ encoding=”UTF-8″?>
<rsm:CrossIndustryInvoice
xmlns:a=”urn:un:unece:uncefact:data:standard:QualifiedDataType:100″
xmlns:rsm=”urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100″
xmlns:qdt=”urn:un:unece:uncefact:data:standard:QualifiedDataType:10″
xmlns:ram=”urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100″
xmlns:xs=”http://www.w3.org/2001/XMLSchema”
xmlns:udt=”urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100″>
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>INV-20250603-001</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format=”102″>20250603</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>Bitte beachten Sie unsere neuen Bankverbindungen.</ram:Content>
<ram:SubjectCode>GEN</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Tech Jogula SRL</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>10178</ram:PostcodeCode>
<ram:LineOne>Alexanderplatz 1</ram:LineOne>
<ram:CityName>Berlin</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID>info@techjogula.com</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID=”VA”>DE999999999</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedLegalOrganization>
<ram:ID>HRB 123456 B</ram:ID>
</ram:SpecifiedLegalOrganization>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Sample Kunde GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80331</ram:PostcodeCode>
<ram:LineOne>Marienplatz 8</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID>buchhaltung@samplekunde.de</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID=”VA”>DE888888888</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:Name>Sample Kunde GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80331</ram:PostcodeCode>
<ram:LineOne>Marienplatz 8</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:PaymentReference>INV-20250603-001</ram:PaymentReference>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:PayeeTradeParty>
<ram:Name>Tech Jogula SRL</ram:Name>
</ram:PayeeTradeParty>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>58</ram:TypeCode>
<ram:Information>Überweisung</ram:Information>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE23100100101234567890</ram:IBANID>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>DEUTDEFFXXX</ram:BICID>
<ram:Name>Deutsche Bank</ram:Name>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>1190.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>1190.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount>226.10</ram:TaxTotalAmount>
<ram:GrandTotalAmount>1416.10</ram:GrandTotalAmount>
<ram:DuePayableAmount>1416.10</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID=”0088″>1234567890123</ram:GlobalID>
<ram:Name>Cloud Hosting Paket Pro</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Laufzeit</ram:Description>
<ram:Value>01.06.2025 – 30.06.2025</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>990.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode=”MON”>1</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode=”MON”>1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format=”102″>20250601</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format=”102″>20250630</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>990.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID=”0088″>1234543210987</ram:GlobalID>
<ram:Name>Support Stundenpaket</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Support-Typ</ram:Description>
<ram:Value>Premium</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>200.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode=”HUR”>1</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode=”HUR”>1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format=”102″>20250601</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format=”102″>20250630</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>200.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
Solution Overview
The process consists of three main steps:
Receive XML Invoice: The iFlow is triggered by an incoming XML invoice (for example, via HTTP, SFTP, or Email).Transform XML to HTML: An XSLT transformation (executed via a Groovy script) converts the XML into a visually rich HTML invoice.Convert HTML to PDF: Another Groovy script leverages iText to generate a PDF from the HTML.
Step 1: Designing the CPI iFlow
The iFlow structure is as follows:
Sender Adapter: Receives the XML invoice.Groovy Script (XML to HTML): Applies XSLT to generate HTML.Groovy Script (HTML to PDF): Cleans and converts HTML to PDF.Receiver Adapter: Sends the PDF to the desired endpoint (e.g., email, SFTP, or document management system).
Step 2: XML to HTML Transformation Script
The following Groovy script is used in a CPI Groovy Script step. It applies an XSLT stylesheet to convert the XML invoice into a styled HTML document.
groovy:::
import javax.xml.transform.*
import javax.xml.transform.stream.*
import java.io.StringReader
import java.io.StringWriter
import com.sap.gateway.ip.core.customdev.util.Message
def processData(def message) {
// XSLT stylesheet (abbreviated for clarity; use your full version)
def xsltContent = ”'<?xml version=”1.0″ encoding=”UTF-8″?>
<xsl:stylesheet version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:rsm=”urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100″
xmlns:ram=”urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100″
xmlns:udt=”urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100″>
<xsl:output method=”html” indent=”yes” encoding=”UTF-8″ />
<xsl:template match=”/rsm:CrossIndustryInvoice”>
<html>
<head>
<title>Invoice</title>
</head>
<body>
<h1>Invoice</h1>
<p>Invoice Number: <xsl:value-of select=”rsm:ExchangedDocument/ram:ID”/></p>
<p>Issue Date: <xsl:value-of select=”rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString”/></p>
<p>Seller: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name”/></p>
<p>Buyer: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:Name”/></p>
<h2>Items</h2>
<table border=”1″>
<tr>
<th>Line</th>
<th>Product</th>
<th>Description</th>
<th>Quantity</th>
<th>Unit</th>
<th>Net Price</th>
</tr>
<xsl:for-each select=”rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem”>
<tr>
<td><xsl:value-of select=”ram:AssociatedDocumentLineDocument/ram:LineID”/></td>
<td><xsl:value-of select=”ram:SpecifiedTradeProduct/ram:Name”/></td>
<td><xsl:value-of select=”ram:SpecifiedTradeProduct/ram:ApplicableProductCharacteristic/ram:Description”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeDelivery/ram:BilledQuantity”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice/ram:ChargeAmount”/></td>
</tr>
</xsl:for-each>
</table>
<h2>Summary</h2>
<p>Total (before tax): <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:LineTotalAmount”/></p>
<p>Tax: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TaxTotalAmount”/></p>
<p>Grand Total: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount”/></p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>”’
def inputXML = message.getBody(String)
def transformerFactory = TransformerFactory.newInstance()
def transformer = transformerFactory.newTransformer(new StreamSource(new StringReader(xsltContent)))
def xmlSource = new StreamSource(new StringReader(inputXML))
def htmlOutputStream = new StringWriter()
def result = new StreamResult(htmlOutputStream)
transformer.transform(xmlSource, result)
message.setBody(htmlOutputStream.toString())
message.setHeader(“Content-Type”, “text/html”)
return message
}
Key Points:
The XSLT template maps XML elements to HTML fields, including seller, buyer, invoice lines, totals, and notes.CSS is embedded for professional styling.
Step 3: HTML to PDF Conversion Script
The next Groovy script (placed after the previous step in your iFlow) uses iText to convert the generated HTML to a PDF.
groovy:::
import com.itextpdf.text.*
import com.itextpdf.text.pdf.PdfWriter
import com.itextpdf.tool.xml.XMLWorkerHelper
import java.io.*
import com.sap.gateway.ip.core.customdev.util.Message
def cleanHtml(String html) {
html = html.replaceAll(/<a[^>]*>(.*?)</a>/, ‘$1’)
html = html.replaceAll(/<span[^>]*>(.*?)</span>/, ‘$1’)
html = html.replaceAll(/<br>/, ‘<br/>’)
html = html.replaceAll(“ ”, ” “)
return html
}
def processData(Message message) {
def document = new Document()
def outputStream = new ByteArrayOutputStream()
try {
def htmlContent = message.getBody(String)
htmlContent = cleanHtml(htmlContent)
PdfWriter writer = PdfWriter.getInstance(document, outputStream)
document.open()
XMLWorkerHelper worker = XMLWorkerHelper.getInstance()
worker.parseXHtml(writer, document, new StringReader(htmlContent))
document.close()
byte[] pdfBytes = outputStream.toByteArray()
message.setBody(pdfBytes)
message.setHeader(“Content-Type”, “application/pdf”)
message.setHeader(“Content-Disposition”, “attachment; filename=invoice.pdf”)
} catch (Exception e) {
throw new RuntimeException(“Error generating PDF: ” + e.message, e)
} finally {
outputStream.close()
}
return message
}
Generated PDF:
Key Points:
The cleanHtml function ensures compatibility by removing problematic tags.The script sets the PDF as the message body and updates headers for file download.
Best Practices & Tips
Testing: Simulate your iFlow with sample XML invoices to ensure correct mapping and formatting.XSLT Maintenance: Keep your XSLT modular and well-documented for easy updates.PDF Styling: Test with different invoice data to ensure the PDF renders well, especially for multi-line items or special characters.Error Handling: Enhance your scripts with logging and error handling for production use.
Conclusion
By combining XSLT-based HTML generation and Groovy/iText PDF conversion in SAP CPI, you can fully automate the transformation of XML invoices into professional PDF documents. This approach ensures compliance, improves efficiency, and provides a scalable solution for digital invoicing.
Ready to streamline your invoice process? Try implementing this iFlow in your SAP CPI tenant today!
IntroductionIn today’s digital business landscape, automating invoice processing is essential for efficiency, accuracy, and compliance. I have implemented a robust SAP Cloud Platform Integration (CPI) iFlow that transforms incoming XML invoices into professional PDF documents-ready for distribution, archiving, or further processing.This blog provides a comprehensive, step-by-step guide to building such a solution in SAP CPI, including the actual scripts used for HTML generation and PDF conversion.Sample XML: <?xml version=”1.0″ encoding=”UTF-8″?>
<rsm:CrossIndustryInvoice
xmlns:a=”urn:un:unece:uncefact:data:standard:QualifiedDataType:100″
xmlns:rsm=”urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100″
xmlns:qdt=”urn:un:unece:uncefact:data:standard:QualifiedDataType:10″
xmlns:ram=”urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100″
xmlns:xs=”http://www.w3.org/2001/XMLSchema”
xmlns:udt=”urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100″>
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>INV-20250603-001</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format=”102″>20250603</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>Bitte beachten Sie unsere neuen Bankverbindungen.</ram:Content>
<ram:SubjectCode>GEN</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Tech Jogula SRL</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>10178</ram:PostcodeCode>
<ram:LineOne>Alexanderplatz 1</ram:LineOne>
<ram:CityName>Berlin</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID>info@techjogula.com</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID=”VA”>DE999999999</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedLegalOrganization>
<ram:ID>HRB 123456 B</ram:ID>
</ram:SpecifiedLegalOrganization>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Sample Kunde GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80331</ram:PostcodeCode>
<ram:LineOne>Marienplatz 8</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID>buchhaltung@samplekunde.de</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID=”VA”>DE888888888</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:Name>Sample Kunde GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80331</ram:PostcodeCode>
<ram:LineOne>Marienplatz 8</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:PaymentReference>INV-20250603-001</ram:PaymentReference>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:PayeeTradeParty>
<ram:Name>Tech Jogula SRL</ram:Name>
</ram:PayeeTradeParty>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>58</ram:TypeCode>
<ram:Information>Überweisung</ram:Information>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE23100100101234567890</ram:IBANID>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>DEUTDEFFXXX</ram:BICID>
<ram:Name>Deutsche Bank</ram:Name>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>1190.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>1190.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount>226.10</ram:TaxTotalAmount>
<ram:GrandTotalAmount>1416.10</ram:GrandTotalAmount>
<ram:DuePayableAmount>1416.10</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID=”0088″>1234567890123</ram:GlobalID>
<ram:Name>Cloud Hosting Paket Pro</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Laufzeit</ram:Description>
<ram:Value>01.06.2025 – 30.06.2025</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>990.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode=”MON”>1</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode=”MON”>1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format=”102″>20250601</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format=”102″>20250630</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>990.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID=”0088″>1234543210987</ram:GlobalID>
<ram:Name>Support Stundenpaket</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Support-Typ</ram:Description>
<ram:Value>Premium</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>200.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode=”HUR”>1</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode=”HUR”>1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format=”102″>20250601</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format=”102″>20250630</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>200.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>Solution OverviewThe process consists of three main steps:Receive XML Invoice: The iFlow is triggered by an incoming XML invoice (for example, via HTTP, SFTP, or Email).Transform XML to HTML: An XSLT transformation (executed via a Groovy script) converts the XML into a visually rich HTML invoice.Convert HTML to PDF: Another Groovy script leverages iText to generate a PDF from the HTML.Step 1: Designing the CPI iFlowThe iFlow structure is as follows:Sender Adapter: Receives the XML invoice.Groovy Script (XML to HTML): Applies XSLT to generate HTML.Groovy Script (HTML to PDF): Cleans and converts HTML to PDF.Receiver Adapter: Sends the PDF to the desired endpoint (e.g., email, SFTP, or document management system).Step 2: XML to HTML Transformation ScriptThe following Groovy script is used in a CPI Groovy Script step. It applies an XSLT stylesheet to convert the XML invoice into a styled HTML document.groovy:::import javax.xml.transform.*
import javax.xml.transform.stream.*
import java.io.StringReader
import java.io.StringWriter
import com.sap.gateway.ip.core.customdev.util.Message
def processData(def message) {
// XSLT stylesheet (abbreviated for clarity; use your full version)
def xsltContent = ”'<?xml version=”1.0″ encoding=”UTF-8″?>
<xsl:stylesheet version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:rsm=”urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100″
xmlns:ram=”urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100″
xmlns:udt=”urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100″>
<xsl:output method=”html” indent=”yes” encoding=”UTF-8″ />
<xsl:template match=”/rsm:CrossIndustryInvoice”>
<html>
<head>
<title>Invoice</title>
</head>
<body>
<h1>Invoice</h1>
<p>Invoice Number: <xsl:value-of select=”rsm:ExchangedDocument/ram:ID”/></p>
<p>Issue Date: <xsl:value-of select=”rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString”/></p>
<p>Seller: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name”/></p>
<p>Buyer: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:Name”/></p>
<h2>Items</h2>
<table border=”1″>
<tr>
<th>Line</th>
<th>Product</th>
<th>Description</th>
<th>Quantity</th>
<th>Unit</th>
<th>Net Price</th>
</tr>
<xsl:for-each select=”rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem”>
<tr>
<td><xsl:value-of select=”ram:AssociatedDocumentLineDocument/ram:LineID”/></td>
<td><xsl:value-of select=”ram:SpecifiedTradeProduct/ram:Name”/></td>
<td><xsl:value-of select=”ram:SpecifiedTradeProduct/ram:ApplicableProductCharacteristic/ram:Description”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeDelivery/ram:BilledQuantity”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode”/></td>
<td><xsl:value-of select=”ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice/ram:ChargeAmount”/></td>
</tr>
</xsl:for-each>
</table>
<h2>Summary</h2>
<p>Total (before tax): <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:LineTotalAmount”/></p>
<p>Tax: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TaxTotalAmount”/></p>
<p>Grand Total: <xsl:value-of select=”rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount”/></p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>”’
def inputXML = message.getBody(String)
def transformerFactory = TransformerFactory.newInstance()
def transformer = transformerFactory.newTransformer(new StreamSource(new StringReader(xsltContent)))
def xmlSource = new StreamSource(new StringReader(inputXML))
def htmlOutputStream = new StringWriter()
def result = new StreamResult(htmlOutputStream)
transformer.transform(xmlSource, result)
message.setBody(htmlOutputStream.toString())
message.setHeader(“Content-Type”, “text/html”)
return message
}Key Points:The XSLT template maps XML elements to HTML fields, including seller, buyer, invoice lines, totals, and notes.CSS is embedded for professional styling.Step 3: HTML to PDF Conversion ScriptThe next Groovy script (placed after the previous step in your iFlow) uses iText to convert the generated HTML to a PDF.groovy:::import com.itextpdf.text.*
import com.itextpdf.text.pdf.PdfWriter
import com.itextpdf.tool.xml.XMLWorkerHelper
import java.io.*
import com.sap.gateway.ip.core.customdev.util.Message
def cleanHtml(String html) {
html = html.replaceAll(/<a[^>]*>(.*?)</a>/, ‘$1’)
html = html.replaceAll(/<span[^>]*>(.*?)</span>/, ‘$1’)
html = html.replaceAll(/<br>/, ‘<br/>’)
html = html.replaceAll(“ ”, ” “)
return html
}
def processData(Message message) {
def document = new Document()
def outputStream = new ByteArrayOutputStream()
try {
def htmlContent = message.getBody(String)
htmlContent = cleanHtml(htmlContent)
PdfWriter writer = PdfWriter.getInstance(document, outputStream)
document.open()
XMLWorkerHelper worker = XMLWorkerHelper.getInstance()
worker.parseXHtml(writer, document, new StringReader(htmlContent))
document.close()
byte[] pdfBytes = outputStream.toByteArray()
message.setBody(pdfBytes)
message.setHeader(“Content-Type”, “application/pdf”)
message.setHeader(“Content-Disposition”, “attachment; filename=invoice.pdf”)
} catch (Exception e) {
throw new RuntimeException(“Error generating PDF: ” + e.message, e)
} finally {
outputStream.close()
}
return message
}Generated PDF:Key Points:The cleanHtml function ensures compatibility by removing problematic tags.The script sets the PDF as the message body and updates headers for file download.Best Practices & TipsTesting: Simulate your iFlow with sample XML invoices to ensure correct mapping and formatting.XSLT Maintenance: Keep your XSLT modular and well-documented for easy updates.PDF Styling: Test with different invoice data to ensure the PDF renders well, especially for multi-line items or special characters.Error Handling: Enhance your scripts with logging and error handling for production use.ConclusionBy combining XSLT-based HTML generation and Groovy/iText PDF conversion in SAP CPI, you can fully automate the transformation of XML invoices into professional PDF documents. This approach ensures compliance, improves efficiency, and provides a scalable solution for digital invoicing.Ready to streamline your invoice process? Try implementing this iFlow in your SAP CPI tenant today! Read More Technology Blog Posts by Members articles
#SAP
#SAPTechnologyblog