Technical Articles
Consume ‘SAP Forms by Adobe’ from SAP UI5 applications
Edited on 19/11/2019 – Removed token generation from within the UI5 application and handled it in the destination.
After publishing the blog on how to generate PDFs in the cloud using Java application, I received few comments and a number of messages on how to consume the SAP Forms by Adobe service from a SAP UI5 application. This blog will cover the steps to do the same.
Please refer my other blog: https://blogs.sap.com/2018/11/08/generate-pdfs-in-the-cloud-sap-forms-by-adobe/#, on how this can be done using a Java application.
As I mentioned in my previous blog, SAP standard documentation covers most of the steps in detail and I will be referring to the official document directly for those steps.
In order to call the Rest API to generate the PDF forms from SAP UI5 application, we need the following:
a. Form Template – PDF Layout
b. Data to be displayed in the form – Invoice data
Pass these two parameters while calling the Rest API and get the PDF form back.[For the sake of simplicity, I used the same PDF layout (Form Template) I used in the other blog].
SAP has introduced ‘Template Stores’ to store the Form templates. They can be referred easily when the PDF rendering API is called. Unlike the other blog in which I passed the XDP template in the API call, I have stored and referred the Form template from template store here.
Some steps are well documented here by SAP. So, I will be covering the additional steps in a more detailed manner.
- Enable the ‘SAP Forms by Adobe’ in your trial subaccount. Refer link
- Assign roles to users and update the destination. Refer link
- Register an oAuth client in the cloud platform subaccount and create a destination pdf render API by following the steps in the link . Use URL as https://adsrestapiformsprocessing-s0008289464trial.hanatrial.ondemand.com/ads.restapi
Now we are all set to call the REST APIs from the ui5 application.
5. UI5 application
Maintain entries in Neo-app.json to access both the destinations configured above.
{
"welcomeFile": "/webapp/index.html",
"authenticationMethod": "saml",
"routes": [
{
"path": "/resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/resources"
},
"description": "SAPUI5 Resources"
},
{
"path": "/test-resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/test-resources"
},
"description": "SAPUI5 Resources"
}
{
"path": "/render",
"target": {
"type": "destination",
"name": "pdf_render_oAuth"
},
"description": "pdf_render_oAuth"
},
{
"path": "/webapp/resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/resources"
},
"description": "SAPUI5 Resources"
},
{
"path": "/webapp/test-resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/test-resources"
},
"description": "SAPUI5 Test Resources"
}
],
"sendWelcomeFileRedirect": true
}
When you have to call the print functionality, use the code below. I have tried to give comments in line for easy understanding.
To know more about the API calls, refer Rest API documentation
renderPDF: function () {
//Generate the token
var modeldata = this.getView().getModel().getData();
//Build the xml data with the data from the model
var xmldata =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><form1><InvoiceNo>" + modeldata.Invoices[0].Invoiceno + "</InvoiceNo><InvoiceTo>" +
modeldata.Invoices[0].Invoiceaddress + "</InvoiceTo><InvoiceTotal>" + modeldata.Invoices[0].Invoiceamount +
"</InvoiceTotal></form1>";
var encdata = btoa(xmldata);
//prepare the render API call. Pick up the template from template store
var jsondata = "{ " + "\"xdpTemplate\": \"" + "InvoiceData/Invoice" + "\", " + "\"xmlData\": \"" + encdata + "\"}";
var url_render = "/render/v1/adsRender/pdf?templateSource=storageName";
//make the API call
$.ajax({
url: url_render,
type: "post",
contentType: "application/json",
data: jsondata,
success: function (data, textStatus, jqXHR) {
//once the API call is successfull, Display PDF on screen
var decodedPdfContent = atob(data.fileContent);
var byteArray = new Uint8Array(decodedPdfContent.length);
for (var i = 0; i < decodedPdfContent.length; i++) {
byteArray[i] = decodedPdfContent.charCodeAt(i);
}
var blob = new Blob([byteArray.buffer], {
type: 'application/pdf'
});
var _pdfurl = URL.createObjectURL(blob);
if (!this._PDFViewer) {
this._PDFViewer = new sap.m.PDFViewer({
width: "auto",
source: _pdfurl
});
jQuery.sap.addUrlWhitelist("blob"); // register blob url as whitelist
}
this._PDFViewer.open();
},
error: function (data) {
}
});
}
Here is the output of the UI5 application.
- Execute the application from SCP
- Click on Edit and change the details (just to make sure that the data is being picked up dynamically)
3.Click on Print. API calls will be made and the PDF is shown in the PdfViewer control
As always, please feel free to comment if you have any feedback or questions.
Great! Very useful post, congrats!
Sharadha Krishnamoorthy
Hi Sharadha,
I am working on one scenario , I want to check if it is feasible or not initially. Below are details of my scenario:-
Shipment functionality is not present in S4C system, I have requirement in which I have to show user shipment with all it’s deliveries and if user click on print, it will print out all delivery output.
In S4C system, Individual deliveries can be taken print out but there is no Shipment concept as such, I have extended Delivery app by custom field that contains Shipment number.
Now I have to build one custom app(SDK) that will ask user for shipment number, on search it should query all deliveries(S4C) with respect to that shipment number and there should be print button, on clicking of Print button, all deliveries should get printed, output is in the adobe form.
DELIVERY_NOTE output type can be used to get the data in xml and I have already developed form which is in .xsd format.
I need your advice what should be the best approach to develop this kind of scenario.
Regards,
Ankesh
Ankesh,
What do you mean by S4C system - is it S4HANA for Cloud? The adobe forms service can be called from both on-premise and cloud applications. please refer the link - https://help.sap.com/viewer/6d3eac5a9e3144a7b43932a1078c7628/Cloud/en-US/ed10b24db1d64e6c87d7303986d174e9.html
It will be just a Rest API call in both the scenarios - storing the form templates in the template store (recommended option) or sending it along with each request.
DELIVERY_NOTE output type can be used to get the data in xml => You have to make sure that the xml data is in the same format as expected by the .xsd form template.
The scenario described by you is very much achievable from either a SAP UI5 application or a Java application ( you can refer my other blog - https://blogs.sap.com/2018/11/08/generate-pdfs-in-the-cloud-sap-forms-by-adobe/ )
Let me know if you have further questions.
-Sharadha
Sharadha Krishnamoorthy
Hi Sharadha,
S4C means S4 HANA Cloud system
https://adsrestapiformsprocessing-s0008289464trial.hanatrial.ondemand.com/ads.restapi/v1/adsRender/pdf
This adove URL is not working. If I replace V1 with # value, then I get 200 response but in response I am getting below response from 2nd Ajax call( HTML response), It is not in file-content format. Can you please suggest what configuration is done wrong in this?
Through Postman , I am also getting same response.
Hi
Thanks for writing this blog, I must address something.
If you follow the steps delivered by SAP, and use SAML authentication, there is no need to generate a token and provide it in the header of the API call.
You can just do a post to adsRender/pdf
Steven,
I am not sure what do you mean by "If you follow the steps delivered by SAP, and use SAML authentication". Can you please share the documentation you are referring here? As far as I am aware, we need to generate the token using the oAuth client and use it to call the REST APIs. It would be helpful if you share the steps or the documentation.
-Sharadha
See step 3 in your blog, hereby the links:
https://help.sap.com/viewer/6d3eac5a9e3144a7b43932a1078c7628/Cloud/en-US/3be5e26d1919495c8f8fc4e8773e3885.html
https://help.sap.com/viewer/6d3eac5a9e3144a7b43932a1078c7628/Cloud/en-US/894418cd915b46bd9fcf27ac0bf6d15f.html
The token is automatically generated, when you set up the destination, as mentioned in the links.
If you then use that destination, there is no further need to request a token yourself.
As a callback to the token method is done automatically.
When changing the neo-app, you have to configure the authentication to SAML.
I have it working in one of our own SAP UI5 Cloud apps
Thanks. But according to the blog and as per the help links, we have to set up the oAuth client for token generation, which I have explained. I do not see any SAML set up as per your comment anywhere in the links. Would be helpful if you can share the details regarding the SAML set up which you are referring here.
-Sharadha
**
For some reason, when I checked earlier, I was able to see only the links in this reply and not the description which you have written clearly ?
I have updated the blog now. Thanks again for this!
Dispatcher takes care of the magic, when the authenticationMethod property is set to saml
As when you call the service (via the destination), it’s using the dispatcher.
Map the Destination to your HTML5 Application via Application Descriptor
You also should change the Authentication on the destination you provided in this blog, from NoAuthentication to OAuth2ClientCredentials and fill up the required fields, with the values from the oAuth Client
Steven,
You are right in saying that there is no need to generate the token from within the application every time. But it is just not achieved by just setting the authentication method to SAML (if you notice, it has already been done in step 5 in my blog).
But we can avoid the call to token generation and set the authentication for the destination pdf_render to 'OAuth2ClientCredentials' and maintain the OAuth credentials directly. I have tested this just now and it works perfectly fine. Will update the blog shortly.
Thanks a lot for pointing this out.
-Sharadha
@Steven De Baerdemaeker/ Sharadha Krishnamoorthy
My destination shows 200 response but I am still getting same error
"Authentication Error: Could not redirect to ADS because could not get the RelayState value from the request. Destination credentials might be wrong."
Regards,
Ankesh
Ankesh, This is the same issue which you have updated in the forum thread. I have replied to that.
-Sharadha
Hi Sharadha,
I am trying to generate pdf by following the same blog.But I am getting below error.
"Authentication type not supported. Please use Basic Authentication or ClientCertificate Authentication"
Regards
Saranya
Saranya,
Did you try testing the destination separately? what is the response?
Hi Sharadha,
I consumed correctly the api in my ui5 application but I have the following issue when I write in the "encdata", the body of "xmlData" property, a word with an accent:
Instead, if the content of the body has not accent words, the api works perfectly.
Do you have any hints to how I can change the way that I consume the api (I suppose)?
Regards,
Simone
Is there any other method or link available for settings of ads destination in cloud foundry environment ?
I'm getting '401 unauthorized' error when trying as per sap help link .