Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
SachinArtani
Participant

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:

  • In SAP S/4HANA Cloud, the creation of a gateway service via SEGW is only possible by SAP.
  • The concept is intended to be "cloud-ready" under all circumstances.
  • It is not intended for the customer to create a form data provider, neither from on-premise nor from cloud. Only SAP creates a form data provider.
  • If the customer still uses on-premise, but later switches to cloud, there is no effort required to adapt.
  • The customer can create their own forms but must use a form data provider from SAP.
    Typically, they will download a pre-delivered SAP template and create an adapted copy of it.
  • The customer’s form uses the same form data provider as the SAP template.

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 –

  1. Create an Adobe form
  2. Create an OData service
  3. Map OData service to adobe form
  4. Design form layout
  5. Create an OData service act as a driver program to call the Adobe form
  6. Consume driver OData service in UI5

 

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.

SachinArtani_0-1715673968502.png

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:

  • DDIC Based SAP Gateway OData Service
  • OData Service with Data Source Reference as CDS Views
  • SAP RAP OData V2 Service

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 –

SachinArtani_1-1715673968506.png

 

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 –

SachinArtani_2-1715673968509.png

 

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’ –

SachinArtani_3-1715673968511.png

SachinArtani_4-1715673968513.png

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’ –

SachinArtani_5-1715673968514.png

And the root node ‘QueryNode’ also has the key ‘PurchaseOrder’ along with few more keys –

SachinArtani_6-1715673968518.png

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 –

SachinArtani_7-1715673968521.png

Then comes the parent node ZSAC_I_PO_HEADER which is purchase order header –

SachinArtani_8-1715673968523.png

And then comes the child node ZSAC_I_PO_ITEM which is purchase order item –

SachinArtani_9-1715673968524.png

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 –

SachinArtani_10-1715673968526.png

And finally, we create a service binding of type OData V2 Web API as ZSAC_UI_PURCHASE_ORDER –

SachinArtani_11-1715673968529.png

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 –

SachinArtani_12-1715673968531.png

You can validate the change by checking for form in Fiori app – ‘Maintain Form Templates’ –

SachinArtani_13-1715673968533.png

Design form layout:

Download the layout from the Fiori app –

SachinArtani_14-1715673968537.png

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 –

SachinArtani_15-1715673968539.png

We can find the bindings under ‘Data View’ tab as shown below –

SachinArtani_16-1715673968543.png

Once you design the form as per requirement, save it, and upload it back –

SachinArtani_17-1715673968547.png

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

SachinArtani_18-1715673968549.png

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:

  • Taking the value from input parameter: P_PURCHASEORDER
  • Populating LT_KEYS with input parameters where we are expected to pass all the key fields mentioned in the root node ZSAC_R_PO_QUERY
  • Instantiate the class CL_SOMU_FORM_SERVICES
  • Call method GET_DOCUMENT of the class CL_SOMU_FORM_SERVICES by passing the adobe form name and LT_KEYS
  • Pass back the PDF as rawstring from LV_CONTENT to the custom entity.

For exposing the custom entity, create a separate Service Definition and Service Binding –

SachinArtani_19-1715673968549.png

SachinArtani_20-1715673968552.png

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.

SachinArtani_21-1715673968558.png

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 –

https://community.sap.com/t5/technology-blogs-by-sap/preview-download-fragmented-forms-from-fiori-li...

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.

4 Comments
Labels in this area