Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
abhishekd
Product and Topic Expert
Product and Topic Expert
4,578

Introduction / Requirement


There were days where customer requirement was to create ALV reports in GUI and to provide button on top of ALV to print the report data as PDF or to show the details of selected line item.

Now Customers are focusing on application which are more user friendly, responsive instead of old GUI applications/screens.


In this blog, I will be explaining something similar type of requirement where Print functionality (Fragmented Form) on Fiori List report was required.

I have built an application, which allow user to show the PO data in Fiori list report, where user can select a particular line and preview the form (in my case billing document form).

Technical Details


Step 1 - Creation of Fiori List Report and project in BAS

First step will be creation of CDS view and creating Fiori List report on top of consumption view (I will not go much into details of creating / deploying project in BAS because all that you can explore on your own as there are already lot of blogs for the same).

Preview of list report from ADT


Fiori List Report Preview


Step 2 - Backend OData Service for PDF data

In the backend we will be creating an OData service which will be used to provide the PDF data (xstring)

a) OData project will be created which will have GetPDFDisplay Entity

       


OData Service


b) GetPDFDisplay Entity will have Billing document number as a key property.
c) Redefine the method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM in   DPC_EXT class to get the stream data.


Redefine GET_STREAM method


d) Inside the GET_STREAM method we can write the logic to get the pdf data (we can use                    GET_DOCUMENT () API of class CL_SOMU_FORM_SERVICES to fetch the PDF data for                fragmented forms) by passing the billing document number from the Frontend.

Logic in GET_STREAM method

1) Fetch the incoming billing document number (selected by user from Fiori List report)

2) Prepare the keys for billing doc and master form

3) Call the GET_DOCUMENT API of class CL_SOMU_FORM_SERVICES by passing content and master form keys

4) Prepare the stream data by passing value and mime type and send the response back to UI

Sample code --



  METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.

CONSTANTS: lc_entity_name TYPE c LENGTH 10 VALUE 'BILLINGDOC'.

DATA: lt_odatakeys TYPE /iwbep/t_mgw_tech_pairs,
ls_key TYPE /iwbep/s_mgw_tech_pair,
lv_billdoc TYPE vbeln,
ls_stream TYPE ty_s_media_resource.


DATA: lt_master_keys TYPE cl_somu_form_services=>ty_gt_key.
DATA: lv_content TYPE xstring.
DATA: lo_cl_somu_form_services TYPE REF TO cl_somu_form_services,
lt_keys TYPE cl_somu_form_services=>ty_gt_key.

TRY.

* Step 1-- "-------------- Fetch the billing document selected by user from frontend-----------------------------

lt_odatakeys = io_tech_request_context->get_keys( ).
lv_billdoc = VALUE #( lt_odatakeys[ name = lc_entity_name ]-value OPTIONAL ).

* Step 2 -- " ---------------------------Key Value for the Billing document content form service ---------------------------

lt_keys = VALUE #( ( name = 'BillingDocument' value = lv_billdoc )
( name = 'SenderCountry' value = 'DE' )
( name = 'Language'(040) value = 'E' ) ) .


* " --------------------------- Key Value for the master form template service ---------------------------

lt_master_keys = VALUE #( ( name = 'PrintFormDerivationRule' value = 'ZINVOICE_FORM' )
( name = 'WatermarkText' value = space )
( name = 'LocaleCountry' value = 'DE')
( name = 'LocaleLanguage' value = 'E' )
( name = 'OutputControlApplicationObjectType' value = 'BILLING_DOCUMENT' )
( name = 'OutputControlApplicationObject' value = lv_billdoc )
( name = 'OutputRequestItem' value = '000001' )
( name = 'OutputDocumentType' value = 'BILLING_DOCUMENT' )
( name = 'Recipient'(041) value = '00000001003' )
( name = 'RecipientRole' value = 'RE' )
( name = 'SenderCountry' value = 'DE' )
( name = 'ReceiverPartnerNumber' value = '00000001003' ) ).

* Step3 --" --------------------------- Call GET_DOCUMENT API ---------------------------

lo_cl_somu_form_services = cl_somu_form_services=>get_instance( ).

TRY.
lo_cl_somu_form_services->get_document( EXPORTING iv_master_form_name = 'ZZ1_OTC_INVOICE_MASTER_A4'
iv_form_name = 'ZZ1_OTC_INVOICE_OUTPUT'
it_key = lt_keys
it_master_key = lt_master_keys
iv_form_language = 'E'
iv_form_country = 'DE'
IMPORTING ev_content = lv_content
).

" --------------------------- Set the Header ---------------------------*
DATA(lv_name) = |inline; filename={ 'Billing Document ' && lv_billdoc && '.pdf' };| .
DATA(ls_header) = VALUE ihttpnvp( name = 'Content-Disposition'
value = lv_name

).
set_header( is_header = ls_header ).

" --------------------------- Set the stream data ---------------------------*
ls_stream-value = lv_content.
ls_stream-mime_type = 'application/pdf'.

CATCH cx_somu_error INTO DATA(lr_root).
MESSAGE lr_root->get_text( ) TYPE 'E'.
ENDTRY.

"Step 4----------------------------- Send the stream data to frontend ---------------------------*
copy_data_to_ref( EXPORTING
is_data = ls_stream
CHANGING
cr_data = er_stream ).

CATCH /iwbep/cx_mgw_busi_exception .

CATCH /iwbep/cx_mgw_tech_exception .

ENDTRY.

ENDMETHOD.

Test the service in gateway.


Test Service


*Note – This approach can also be used with adobe forms*

Step 3 Frontend (Extension in BAS)

Extension in BAS

Apart from default data source, we must define additional data source for the backend OData service which we have created in gateway builder in step 2, under the “dataSources” section of manifest file for fetching PDF data (xstring).



 

Define data source in manifest


This OData data source should be mapped to a UI5 model in manifest file under “models” section.


Model


Using Guided development, button will be added which will add the required information in manifest file and create controller.js file with function.

Steps -

1) Right click on the project and open guided development


Guided Development


In Guided development we have different options to perform extension on Fiori report.
For our requirement we will select 1st option, add a custom action to a page using extension.


In this step, we will create a controller extension to define a handler function for the custom action button.
If a controller extension is already available for a page, we can copy the code and use it.


Click on create button to create the controller.js file.

Step 2 - Update the manifest file.

In this step, we will add the extension settings of the custom action to the manifest.


After clicking on insert snippet, manifest file will be updated with required information.
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport": {
"controllerName": "xx.sellbuybackreport.ext.controller.ListReportExt",
"sap.ui.generic.app": {
"ZC_OTC_SELLBUYBACK_DETAILS": {
"EntitySet": "ZC_OTC_SELLBUYBACK_DETAILS",
"Actions": {
"onPrint": {
"id": "printID",
"text": "Print Preview",
"press": "onPrintPreview",
"requiresSelection": true
}
}
}
}
}
}
}
}

 

Once we preview the application, we can see the Print Preview button in the toolbar section of report.


Report Preview


Now we have to plug in the code in button method which was created via guided development in controller.js file.
Explanation of controller code

1) Create object of PDF Viewer and add it to current view

2) Get selected billing document number

3) Use createKey method to create the key by passing the billing document number if billing document is present for the selected line.

4) Create the final URL, the service URL + the OData entity set which will return the PDF with a $Value parameter.
Set this URL to the PDFViewer Object along with the title of PDF, In the end open the PDF Viewer
  onPrintPreview: function(oEvent) {

var opdfViewer = new PDFViewer();
this.getView().addDependent(opdfViewer);
//get selected line index
var selectedIndex = this.getView().byId('xx.sellbuybackreport::sap.suite.ui.generic.template.ListReport.view.ListReport::ZC_OTC_SELLBUYBACK_DETAILS--GridTable')
.getAggregation("plugins")[0].getSelectedIndex() ;

// get billing document from selected index
var vSelectedBillDoc = this.getView().byId('xx.sellbuybackreport::sap.suite.ui.generic.template.ListReport.view.ListReport::ZC_OTC_SELLBUYBACK_DETAILS--GridTable').
getContextByIndex(selectedIndex).getProperty('CorrectBillingDocZG2');

if (vSelectedBillDoc !== '') {

// create the path for OData Get_stream call
const path = this.getView().getModel("oERPSOModel").createKey("/GetPDFDisplaySet", {
// Key(s) and value(s) of that entity set
"BillingDoc": vSelectedBillDoc,
});
var sServiceURL = this.getView().getModel("oERPSOModel").sServiceUrl;
// Create the final URL
var sSource = sServiceURL + path + "/$value";
opdfViewer.setSource(sSource);
opdfViewer.setTitle("Billing Document ");
// Opne the PDF Viewer
opdfViewer.open();

} else {
// If billing doc is not present for selected line
sap.m.MessageBox.error("Billing Document doesn't exists");

}

}
};

 

Let’s test the code …

Select a line where billing document exists and click on print preview to show the form in preview mode. User can download this form by clicking download.



Print Preview of Billing Document


Below backend call was made on click of Print button to fetch the PDF data .
"/sap/opu/odata/sap/ZGW_OTC_SELLBUYBACK_SRV/GetPDFDisplaySet ('94000058')/$value"

That’s the end of the topic, I appreciate that you have gone through the concept. This was one such requirement where extension is required on top of Fiori list report.

In the 2nd part of the blog, I will be explaining how we can switch/ convert SEGW project to Unmanaged query (Custom CDS view) to make the solution as cloud ready.

Part-2- Preview/Download Fragmented Forms from Fiori List Report (Part -2) | SAP Blogs
10 Comments