This blog emphasizes on the data source of custom developed Adobe form with fragments. But before we begin, below are the summarized instructions on the creation of a form Data Provider by SAP:
For details, please refer: https://learning.sap.com/learning-journeys/getting-started-with-sap-forms-service-by-adobe/explainin...
Keeping in mind the information above, if business demands for the custom solution, then we can proceed creating custom data provider service for custom adobe form with fragments. In this blog, we will demonstrate Adobe form with fragment with form type – ‘Content’ without master form template.
To achieve that, we will be following below steps –
Create an Adobe form:
Adobe forms with OData service can only be created through the Fiori app – ‘Maintain Form Templates’.
When we create an adobe form, we must specify a data source with OData service. But it does not list custom OData service by default. We also must upload a template while creating a form. For template, we can first create a layout without any bindings in Adobe LiveCycle Designer tool and save it as XDP file.
Alternatively, you can try to find a standard form which has similar attributes and copy it and create a custom adobe form. This will pick the template from the standard form which we can override with our changes.
Create an OData service:
Based on the complexity of data, we will decide which OData service creation is best suited for the requirement:
The prerequisite for opting any of the above option is that there will always be a root entity which must have all the key fields like the parent node. Didn’t get it?
Let us understand it better with an example of standard OData service - FDP_EF_PURCHASE_ORDER which is used for an Adobe form MM_PUR_PURCHASE_ORDER –
This OData service has ‘PurchaseOrder’ as the parent node and ‘PurchaseOrderItems’ as the child node. The association of one to many has also been maintained –
Even though the parent node of the OData service is the Entity Set – ‘PurchaseOrder’. The entry point for this OData service is the Entity Set - ‘Query’, so we consider ‘Query’ as the root node.
For same reason, we have association and association sets are maintained between ‘QueryNode’ and ‘PurchaseOrderNode’ –
In case of RAP based OData service as well, we need to maintain the relationship in similar fashion that there will be a root node with composition to the node which is the parent node. And that parent node will again have composition node if needed.
So, for purchase order header and item, we will create a root node including the keys of purchase order header. Then we will create a child of the root node which will be purchase order header. And finally, we will create purchase order item as a child of purchase order header.
As for the prerequisite, we can see that the parent node - ‘PurchaseOrderNode’ has a key ‘PurchaseOrder’ –
And the root node ‘QueryNode’ also has the key ‘PurchaseOrder’ along with few more keys –
For developing a custom DDIC Based SAP Gateway OData service for adobe form, we can refer to any standard OData service such as FDP_EF_PURCHASE_ORDER from the Fiori app - ‘Maintain Form Templates’.
In this blog, we will demonstrate creating RAP based OData V2 service as a data source of adobe form. Note that SAP does not support OData V4 services for Adobe Forms developed through the Fiori app – ‘Maintain Form Templates’ as of today.
So, let’s dive to practical part and develop a RAP based OData V2 Web API. The steps are as follows:
As mentioned before, first we will create a root node ZSAC_R_PO_QUERY –
Then comes the parent node ZSAC_I_PO_HEADER which is purchase order header –
And then comes the child node ZSAC_I_PO_ITEM which is purchase order item –
It’s quite simple, right? It is just a two-level CDS hierarchy where the root node has all the key fields present in parent node.
Now we just create service definition ZSAC_UI_PURCHASE_ORDER, expose all three data definitions we just created –
And finally, we create a service binding of type OData V2 Web API as ZSAC_UI_PURCHASE_ORDER –
For OData service using Data Source Reference as CDS Views, we can design the CDS nodes relation in the manner explained above.
Map OData service to adobe form:
Now that OData service is created, map it to the custom form by opening it in T-code: SFP –
You can validate the change by checking for form in Fiori app – ‘Maintain Form Templates’ –
Design form layout:
Download the layout from the Fiori app –
Open Adobe LiveCycle Designer app and open the XSD file. Click yes to the below popup which will load the bindings from the custom OData service we created –
We can find the bindings under ‘Data View’ tab as shown below –
Once you design the form as per requirement, save it, and upload it back –
Create an OData service act as a driver program to call the Adobe form:
In our case, we need an OData service which take Purchase Order as input and return the PDF with details in the designed layout. For that, we will create a Custom entity-based RAP Web API.
CDS View - ZSAC_I_PO_PDF
Below is the logic in the query class ZSAC_CL_PDF –
CLASS zsac_cl_pdf DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_rap_query_provider .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zsac_cl_pdf IMPLEMENTATION.
METHOD if_rap_query_provider~select.
DATA: lt_tab TYPE TABLE OF zsac_i_po_pdf,
lv_content TYPE xstring,
lo_cl_somu_form_services TYPE REF TO cl_somu_form_services,
lt_keys TYPE cl_somu_form_services=>ty_gt_key.
TRY.
IF io_request->is_data_requested( ).
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 ) .
TRY.
DATA(lt_parameters) = io_request->get_parameters( ).
DATA(lv_po) = VALUE #( lt_parameters[ parameter_name = 'P_PURCHASEORDER' ]-value OPTIONAL ).
lt_keys = VALUE #( ( name = 'PurchaseOrder' value = lv_po ) ) .
lo_cl_somu_form_services = cl_somu_form_services=>get_instance( ).
TRY.
lo_cl_somu_form_services->get_document( EXPORTING iv_form_name = 'ZZ1_PO_FORM'
it_key = lt_keys
IMPORTING ev_content = lv_content
).
CATCH cx_somu_error INTO DATA(lv_formerror).
ENDTRY.
lt_tab = VALUE #( ( pdf = lv_content ) ).
io_response->set_total_number_of_records( 1 ).
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.
Logic explanation:
For exposing the custom entity, create a separate Service Definition and Service Binding –
The reason why we created a separate Service Definition and Service Binding is because the OData Binding must have a root and only it’s child entities. If we add a custom entity in the binding which is not related to the root entity through association or consumption, we will get the error – “Service ZSAC_UI_PURCHASE_ORDER does not have a unique top node” when we call the adobe form.
To test the OData service, you can check in T-code: /IWFND/GW_CLIENT.
Consume driver OData service in UI5:
For consuming the OData service developed above in a Fiori application, you can write your own logic. To understand how PDF can be previewed, you could refer below blog –
If you are wondering, how to call adobe form having a master form template assigned? Refer the same blog mentioned above for added syntax.
As you may know that we cannot create a custom OData service and assign it to any form from the Fiori app ‘Maintain Form Templates’. If we are not using on-premise system, it is not possible to opt for the custom solution we developed above. It’s one of the reason SAP does not recommend creating custom data provider OData service in the first place.
Thanks for reading it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
4 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 | |
3 | |
3 | |
2 |