Generating Adobe Form Using RAP framework OData Services

Estimated read time 10 min read

This blog emphasizes on the data source of custom developed Adobe form.

The goal here is to use RAP to build the backend logic and expose data to generate Adobe Forms dynamically. 

Steps to be followed 

Generate Adobe form in the Backend system. 

Form Name: ZADOBE_SALES_DATA 

Here I am creating a new class and build the driver Method to call the Adobe form using and return the output form content. 

Now Let us build a RAP Application using Web UI -> Since we do not have Create, update and other functionalities, I am not creating behavior definitions.  

Create a new base View entity: ZI_RAP_SALES_ORD on top of Custom Table

 

@EndUserText.label : ‘Sales Order Header Table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED

define table zar_salesheader {
key salesdocument : abap.char(10) not null;
sddocumentcategory : abap.char(4);
salesdocumenttype : abap.char(4);
createdbyuser : abap.char(12);
creationdate : abap.dats; @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface View for Sales Order’
@Metadata.ignorePropagatedAnnotations: true

define root view entity ZI_RAP_SALE_ORD as select from zar_salesheader
//composition of target_data_source_name as _association_name
{
key salesdocument as Salesdocument,
sddocumentcategory as Sddocumentcategory,
salesdocumenttype as Salesdocumenttype,
createdbyuser as Createdbyuser,
creationdate as Creationdate
// _association_name // Make association public
}

 

Create a Consumption View for the Above View Entity: ZC_RAP_SALE_ORD 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View for Sales Order’
@Metadata.allowExtensions: true

define root view entity ZC_RAP_SALE_ORD
provider contract transactional_query
as projection on ZI_RAP_SALE_ORD
{
key Salesdocument,
Sddocumentcategory,
Salesdocumenttype,
Createdbyuser,
Creationdate
}

 

Create a Metadata Extension file for the Consumption view: ZMDE_RAP_SALE_ORD We can also directly give annotations in consumption view itself, for best practice I am creating a new file to have these Annotation properties. 

 

@Metadata.layer: #CORE
@Search.searchable: true
@UI.headerInfo:{
typeName: ‘Sales Order’,
typeNamePlural: ‘Sale Orders’,
title:{ type:#STANDARD,
label:’Document’ ,
value:’SalesDocument’}
}

annotate view ZC_RAP_SALE_ORD
with
{
@UI:{ lineItem: [{ position : 10}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocument;
@UI:{ lineItem: [{ position : 20}],
selectionField: [{ position : 20 }] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Sddocumentcategory;
@UI:{ lineItem: [{ position : 30}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocumenttype;
@UI:{ lineItem: [{ position : 40}],
selectionField: [{ position : 40 }] }
Createdbyuser;
@UI:{ lineItem: [{ position : 50}],
selectionField: [{ position : 50 }] }
Creationdate;
}

 

Create a new service definition for the Consumption View: ZSDEF_SALE_ORD 

 

@EndUserText.label: ‘Service Definition for Sale Order’
define service ZSDEF_SALES_ORD {
expose ZC_RAP_SALE_ORD;
}

 

Create a new Service Bindings for the Service Definition: ZBIND_SALE_ORD of binding type ODATA V2 – UI and publish it. We can get the Metadata using Service URL .

Now our RAP Application is ready and separate form driver program is also ready. Let us see on how to integrate it. This Integration can be Done by the following steps 

➔ Using SEGW ODATA -> GET_STREAM  

Create a New SEGW ODATA Project and Implement GET Stream method That consumes the common driver program and send back the content. 

GET Stream Code: 

 

DATA(lv_doc) = VALUE numc10( it_key_tab[ name = ‘docId’ ]-value OPTIONAL ).

“”->Call Form Driver Program to get the Form Content
DATA(lv_form_content) = NEW ZCL_SALES_ORD_PDF( )->get_sales_ord_form(
IM_SO_ORD_NO = CONV #( lv_doc ) ).

“”->Build Document Name and Set it in Header
set_header( is_header = VALUE #( name = ‘Content-Disposition’
value = |inline; filename={ lv_doc };| ) ).
copy_data_to_ref( EXPORTING
is_data = VALUE /iwfnd/if_mgw_core_runtime=>ty_s_media_resource(
mime_type = ‘application/pdf’
value = lv_form_content )
CHANGING
cr_data = er_stream ).

 

Testing the SEGW ODATA Service 

Add the Following line in the Interface View: ZI_RAP_SALE_ORD

We are adding two fields ShowPDF -> Has the text PreviewFile

LinkToPDF -> Get Stream Link to be used to navigate as link to open PDF File.

‘PreviewFile’ as ShowPDF, 

concat(‘/sap/opu/odata/sap/ZAR_ADOBE_FORM_SRV/SalesOrderDocumentSetSet(”’,concat(salesdocument, ”’)/$value’)) as LinkToPdf 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface View for Sales Order’
@Metadata.ignorePropagatedAnnotations: true

define root view entity ZI_RAP_SALE_ORD as select from zar_salesheader
//composition of target_data_source_name as _association_name
{
key salesdocument as Salesdocument,
sddocumentcategory as Sddocumentcategory,
salesdocumenttype as Salesdocumenttype,
createdbyuser as Createdbyuser,
creationdate as Creationdate,
‘PreviewFile’ as ShowPDF,
concat(‘/sap/opu/odata/sap/ZAR_ADOBE_FORM_SRV/SalesOrderDocumentSetSet(”’,concat(salesdocument, ”’)/$value’)) as LinkToPdf
// _association_name // Make association public
}

 

Add the Following highlighted Line in the Consumption view ZC_RAP_SALE_ORD to expose the fields 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View for Sales Order’
@Metadata.allowExtensions: true

define root view entity ZC_RAP_SALE_ORD
provider contract transactional_query
as projection on ZI_RAP_SALE_ORD
{
key Salesdocument,
Sddocumentcategory,
Salesdocumenttype,
Createdbyuser,
Creationdate,
ShowPDF,
LinkToPdf
}

 

Add the Following Lines in the Metadata extension file to establish the link to: 

@ui:{  

lineItem: [{ position : 60, label : ‘PDF’}, { type : #WITH_URL, url:’LinkToPDF’ }]  

}  

ShowPDF; 

 

@Metadata.layer: #CORE
@Search.searchable: true
@UI.headerInfo:{
typeName: ‘Sales Order’,
typeNamePlural: ‘Sale Orders’,
title:{ type:#STANDARD,
label:’Document’ ,
value:’SalesDocument’}
}

annotate view ZC_RAP_SALE_ORD
with
{
@UI:{ lineItem: [{ position : 10}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocument;
@UI:{ lineItem: [{ position : 20}],
selectionField: [{ position : 20 }] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Sddocumentcategory;
@UI:{ lineItem: [{ position : 30}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocumenttype;
@UI:{ lineItem: [{ position : 40}],
selectionField: [{ position : 40 }] }
Createdbyuser;
@UI:{ lineItem: [{ position : 50}],
selectionField: [{ position : 50 }] }
Creationdate;
@UI:{
lineItem: [{ position : 60, label : ‘PDF’}, { type : #WITH_URL, url:’LinkToPDF’ }]
}
ShowPDF;
}

 

Testing the RAP Application- Now we can see the New Field as clickable link 

On clicking the Link, the SEGW Service is called, and PDF is shown 

Conclusion: 

Using RAP to generate Adobe Forms in SAP is a powerful combination that leverages the modern ABAP programming model along with the capability of Adobe Document Services. This approach allows for efficient data handling, rendering of complex forms, and can be integrated into SAP Fiori or other front-end applications. 

 

 

 

 

 

 

​ This blog emphasizes on the data source of custom developed Adobe form.The goal here is to use RAP to build the backend logic and expose data to generate Adobe Forms dynamically. Steps to be followed Generate Adobe form in the Backend system. Form Name: ZADOBE_SALES_DATA Here I am creating a new class and build the driver Method to call the Adobe form using and return the output form content. Now Let us build a RAP Application using Web UI -> Since we do not have Create, update and other functionalities, I am not creating behavior definitions.  Create a new base View entity: ZI_RAP_SALES_ORD on top of Custom Table @EndUserText.label : ‘Sales Order Header Table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED

define table zar_salesheader {
key salesdocument : abap.char(10) not null;
sddocumentcategory : abap.char(4);
salesdocumenttype : abap.char(4);
createdbyuser : abap.char(12);
creationdate : abap.dats; @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface View for Sales Order’
@Metadata.ignorePropagatedAnnotations: true

define root view entity ZI_RAP_SALE_ORD as select from zar_salesheader
//composition of target_data_source_name as _association_name
{
key salesdocument as Salesdocument,
sddocumentcategory as Sddocumentcategory,
salesdocumenttype as Salesdocumenttype,
createdbyuser as Createdbyuser,
creationdate as Creationdate
// _association_name // Make association public
}  Create a Consumption View for the Above View Entity: ZC_RAP_SALE_ORD  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View for Sales Order’
@Metadata.allowExtensions: true

define root view entity ZC_RAP_SALE_ORD
provider contract transactional_query
as projection on ZI_RAP_SALE_ORD
{
key Salesdocument,
Sddocumentcategory,
Salesdocumenttype,
Createdbyuser,
Creationdate
}  Create a Metadata Extension file for the Consumption view: ZMDE_RAP_SALE_ORD We can also directly give annotations in consumption view itself, for best practice I am creating a new file to have these Annotation properties.  @Metadata.layer: #CORE
@Search.searchable: true
@UI.headerInfo:{
typeName: ‘Sales Order’,
typeNamePlural: ‘Sale Orders’,
title:{ type:#STANDARD,
label:’Document’ ,
value:’SalesDocument’}
}

annotate view ZC_RAP_SALE_ORD
with
{
@UI:{ lineItem: [{ position : 10}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocument;
@UI:{ lineItem: [{ position : 20}],
selectionField: [{ position : 20 }] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Sddocumentcategory;
@UI:{ lineItem: [{ position : 30}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocumenttype;
@UI:{ lineItem: [{ position : 40}],
selectionField: [{ position : 40 }] }
Createdbyuser;
@UI:{ lineItem: [{ position : 50}],
selectionField: [{ position : 50 }] }
Creationdate;
}  Create a new service definition for the Consumption View: ZSDEF_SALE_ORD  @EndUserText.label: ‘Service Definition for Sale Order’
define service ZSDEF_SALES_ORD {
expose ZC_RAP_SALE_ORD;
}  Create a new Service Bindings for the Service Definition: ZBIND_SALE_ORD of binding type ODATA V2 – UI and publish it. We can get the Metadata using Service URL .Now our RAP Application is ready and separate form driver program is also ready. Let us see on how to integrate it. This Integration can be Done by the following steps ➔ Using SEGW ODATA -> GET_STREAM  Create a New SEGW ODATA Project and Implement GET Stream method That consumes the common driver program and send back the content. GET Stream Code:   DATA(lv_doc) = VALUE numc10( it_key_tab[ name = ‘docId’ ]-value OPTIONAL ).

“”->Call Form Driver Program to get the Form Content
DATA(lv_form_content) = NEW ZCL_SALES_ORD_PDF( )->get_sales_ord_form(
IM_SO_ORD_NO = CONV #( lv_doc ) ).

“”->Build Document Name and Set it in Header
set_header( is_header = VALUE #( name = ‘Content-Disposition’
value = |inline; filename={ lv_doc };| ) ).
copy_data_to_ref( EXPORTING
is_data = VALUE /iwfnd/if_mgw_core_runtime=>ty_s_media_resource(
mime_type = ‘application/pdf’
value = lv_form_content )
CHANGING
cr_data = er_stream ). Testing the SEGW ODATA Service Add the Following line in the Interface View: ZI_RAP_SALE_ORD We are adding two fields ShowPDF -> Has the text PreviewFile LinkToPDF -> Get Stream Link to be used to navigate as link to open PDF File.’PreviewFile’ as ShowPDF, concat(‘/sap/opu/odata/sap/ZAR_ADOBE_FORM_SRV/SalesOrderDocumentSetSet(”’,concat(salesdocument, ”’)/$value’)) as LinkToPdf  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface View for Sales Order’
@Metadata.ignorePropagatedAnnotations: true

define root view entity ZI_RAP_SALE_ORD as select from zar_salesheader
//composition of target_data_source_name as _association_name
{
key salesdocument as Salesdocument,
sddocumentcategory as Sddocumentcategory,
salesdocumenttype as Salesdocumenttype,
createdbyuser as Createdbyuser,
creationdate as Creationdate,
‘PreviewFile’ as ShowPDF,
concat(‘/sap/opu/odata/sap/ZAR_ADOBE_FORM_SRV/SalesOrderDocumentSetSet(”’,concat(salesdocument, ”’)/$value’)) as LinkToPdf
// _association_name // Make association public
}  Add the Following highlighted Line in the Consumption view ZC_RAP_SALE_ORD to expose the fields  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View for Sales Order’
@Metadata.allowExtensions: true

define root view entity ZC_RAP_SALE_ORD
provider contract transactional_query
as projection on ZI_RAP_SALE_ORD
{
key Salesdocument,
Sddocumentcategory,
Salesdocumenttype,
Createdbyuser,
Creationdate,
ShowPDF,
LinkToPdf
}  Add the Following Lines in the Metadata extension file to establish the link to: @ui:{  lineItem: [{ position : 60, label : ‘PDF’}, { type : #WITH_URL, url:’LinkToPDF’ }]  }  ShowPDF;  @Metadata.layer: #CORE
@Search.searchable: true
@UI.headerInfo:{
typeName: ‘Sales Order’,
typeNamePlural: ‘Sale Orders’,
title:{ type:#STANDARD,
label:’Document’ ,
value:’SalesDocument’}
}

annotate view ZC_RAP_SALE_ORD
with
{
@UI:{ lineItem: [{ position : 10}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocument;
@UI:{ lineItem: [{ position : 20}],
selectionField: [{ position : 20 }] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Sddocumentcategory;
@UI:{ lineItem: [{ position : 30}] }
@Search:{ defaultSearchElement: true,
fuzzinessThreshold: 0.7 }
Salesdocumenttype;
@UI:{ lineItem: [{ position : 40}],
selectionField: [{ position : 40 }] }
Createdbyuser;
@UI:{ lineItem: [{ position : 50}],
selectionField: [{ position : 50 }] }
Creationdate;
@UI:{
lineItem: [{ position : 60, label : ‘PDF’}, { type : #WITH_URL, url:’LinkToPDF’ }]
}
ShowPDF;
}  Testing the RAP Application- Now we can see the New Field as clickable link On clicking the Link, the SEGW Service is called, and PDF is shown Conclusion: Using RAP to generate Adobe Forms in SAP is a powerful combination that leverages the modern ABAP programming model along with the capability of Adobe Document Services. This approach allows for efficient data handling, rendering of complex forms, and can be integrated into SAP Fiori or other front-end applications.         Read More Application Development and Automation Blog Posts articles 

#SAP

You May Also Like

More From Author