This Blog will be continuation of the 1st part of the blog where I explained how we can generate Fragmented Forms from Fiori List report using SEGW (OData) Project.
Part-1 – Preview/Download Fragmented Forms From Fiori List Report
In this 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.
Technical details
Backend API (Unmanaged Query)
For Creating the Form API in backend, we will use custom entity (ZCUSTOM_FORMAPI) with billing doc as parameter which will be used to get the billing document of the selected line.
Custom CDS entity will have one below field.
- Stream_data – This field will hold the data for the PDF file and has a custom data type of RAWSTRING with length 0.
Note: We cannot use RAWSTRING domain directly so we have to create a custom data element with data type as RAWSTRING and Length as ‘0’. This is important as length being ‘0’ would indicate that the RAWSTRING has No length restriction and can accommodate file of larger size.
The above custom CDS entity will not have any select rather the data will be fetched at runtime from the class defined using annotation @ObjectModel.query.implementedBy
It requires an ABAP class that implements the select method of the interface IF_RAP_QUERY_PROVIDER.
Query Implementation Class Logic
- Code first check if data is being requested or not (using io request->requested() )
- Using method io_request->get_parameters( ) to get the selected billing document sent from UI
- Create keys for content and master form.
- Call the get_document() API and send the response back to UI.
CLASS zcl_otc_print DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_rap_query_provider .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_OTC_PRINT IMPLEMENTATION.
METHOD if_rap_query_provider~select.
DATA: lt_tab TYPE TABLE OF ZCUSTOM_FORMAPI.
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.
** requested data
IF io_request->is_data_requested( ).
**paging
DATA(lv_offset) = io_request->get_paging( )->get_offset( ).
DATA(lv_page_size) = io_request->get_paging( )->get_page_size( ).
DATA(lv_max_rows) = COND #( WHEN lv_page_size = if_rap_query_paging=>page_size_unlimited
THEN 0 ELSE lv_page_size ) .
** Get the selected billing document from UI
TRY.
DATA(lt_parameters) = io_request->get_parameters( ).
** P_BILLINGDOC is the parameter of custom entity
DATA(lv_billdoc) = VALUE #( lt_parameters[ parameter_name = 'P_BILLINGDOC' ]-value OPTIONAL ).
* " --------------------------- Key Value for the Billing Doc content form --------
lt_keys = VALUE #( ( name = 'BillingDocument' value = lv_billdoc )
( name = 'SenderCountry' value = 'DE' )
( name = 'Language'(040) value = 'E' ) ) .
* " --------------------------- Key Value for the master form template ---------------------------
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' ) ).
lo_cl_somu_form_services = cl_somu_form_services=>get_instance( ).
TRY.
* " --------------------------- Call GET_DOCUMENT API ---------------------------
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
).
CATCH cx_somu_error INTO DATA(lv_formerror).
ENDTRY.
lt_tab = VALUE #( ( stream_data = lv_content
) ).
io_response->set_total_number_of_records( 1 ).
* " -------------- Send the response back to UI------------
io_response->set_data( lt_tab ).
CATCH cx_rap_query_filter_no_range INTO DATA(lv_range).
DATA(lv_msg) = lv_range->get_text( ).
ENDTRY.
ENDIF.
CATCH cx_rap_query_provider.
ENDTRY.
ENDMETHOD.
ENDCLASS.
Create service definition.
Create service binding for the above service and publish it.
Frontend
Define additional data source for the backend service (Custom CDS entity service binding) which we have created, under the “dataSources” section of manifest file for fetching PDF data.
This OData data source should be mapped to a UI5 model in manifest file under “models” section.
Controller File Logic –
- onPrintPreview method will be called when user select a line and clicks on Print Preview button.
- Create object of PDF Viewer and add it to current view.
- Open the busy indicator and call the getPDFData() method.
- In getPDFData() method, get call was made to get the PDF data from ZAPI_FORM API by passing billing document as a parameter to API.
- Promise data (PDF data) will be returned which will be decoded using atob()
- Create a Blob (binary large object) using byte array (decoded content) and set the type as ‘application/pdf’
- Create the URL by passing the Blob as parameter to createObjectURL method and set it to the source of PDF viewer
getPDFData: function () {
// get the Model reference
var oModel = this.getView().getModel("oFormModel");
//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');
return new Promise((resolve,reject)=>{
// Perform Read operation and pass billingdoc as parameter to URL
oModel.read( "/ZCUSTOM_FORMAPI(p_billingdoc='" + vSelectedBillDoc + "')/Set" ,
{
success: function (oData,oResponse){
resolve(oData);
},
error: function (oError) {
reject(oError);
}
});
})
},
onPrintPreview: async function(oEvent) {
var opdfViewer = new PDFViewer();
this.getView().addDependent(opdfViewer);
var oBusyDialog = new sap.m.BusyDialog({
title: 'Generating Form...'
} );
oBusyDialog.open();
// Get the PDF data
var vPDF = await this.getPDFData();
let base64EncodedPDF = vPDF.results[0].stream_data;
let decodedPdfContent = atob(base64EncodedPDF);
let 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);
opdfViewer.setSource(pdfurl);
opdfViewer.setVisible(true);
opdfViewer.setTitle("Billing Document ");
console.log('Reached to PDF')
opdfViewer.open();
oBusyDialog.close();
}
Working of Application —
Below call was made to the backend API along with selected billing documented in parameter field
That’s the end of requirement. I appreciate that you have gone through the concept. This was one such requirement where extension is required on top of Fiori list report.