Skip to Content
Technical Articles

Triggering a workflow on receiving inbound Email with interactive offline adobe form attachment and error handling

Hello all,

There could multiple scenarios in real time where we need to handle an inbound incoming email with attachments  and perform an action for example creation of a Business partner and attach the attachment in business partner or creation of a workflow in receiving the incoming PDF and attach the same in the workflows.

Interactive Offline Forms – Inbound Email Scenario

For this we should adapt to creation of the interactive offline forms

Interactive%20Adobe%20Forms

Interactive Adobe Forms Offline Scenario

This scenario offers a lot of advantages for the external user:

  • No SAP system access needed
  • External user most likely already knows PDF and has Adobe Reader, so no training time is required.
  • Static value help, static checking, simple arithmetic calculations

External user can save locally what he sent to SAP, print it, archive it etc.

For SAP Developer, there are also numerous advantages:

  • SAP Developer don’t need an application to embed the form, so no additional servers are required;
  • SAP Developer don’t need to re-enter data sent via paper or mail.

We can design the interactive adobe form using the below interactive components

Design – Email, Print, Reset Button, Input Button

Email Button

Out of the box Email sending functionality is available in adobe forms to send an email to the email defined in the shown settings.

The PDF attachment is automatically sent on use of this button

There is also option to define the subject for the email

However there are certain limitations that email body text and dynamic variables cannot be defined in this.

Print Form Button can be used to print the form

Reset button will clear all the fillable entries in the form

Preparing Form Template Call in Application Program

  • Call the function module FP_JOB_OPEN.
  • Use the parameters ( IE_OUTPUTPARAMS) of the structure SFPOUTPUTPARAMS to make settings for the form output. For example, specify whether you want the form to be printed, archived, or returned to the application program.
  • Special feature for interactive offline forms: To have the created form returned to you to be forwarded to Business Communication Services for sending by e-mail, set the parameter GETPDF.
  • To determine the name of the generated function module, call the function module FP_FUNCTION_MODULE_NAME.
  • Call the generated function module and send the parameters to the form interface. For example, set the language of the form in the import parameters. Special feature for interactive offline forms: Set the parameter FILLABLE to ‘X’ for Interactive scenario and ’F’  Offline Interactive forms
  • To cancel form processing, call function module FP_JOB_CLOSE.

Calling%20a%20template

Calling a template

Interactive%20Offline%20form

Interactive Offline form

Interactive Offline Forms – Inbound Email Scenario

A classical Offline Customer creation scenario is considered for the interactive form creation

  • A Interactive PDF is sent to a recipient via E-Mail or downloaded from a website
  • Downloaded and filled locally without any connection to the backend SAP system
  • Sent back to the SAP system afterwards either via E-Mail, file upload or by calling a web Service
  • Evaluated in the backend and the data updated to the SAP system.

The new offline forms data processing infrastructure offers out of the box support for processing form data sent back via emails by:

  •  Handling PDFs through inbound mail handlers
  • Retrieving the form template information
  • Extraction of XML based form data from the PDF Form

Mail Input :

  • Mail Inbound Processing identifies the PDF attachments which need to be sent to the FP Inbound handler
  • Forms Processing inbound Handler is the defined generic handler which marshals the extraction of the data from the PDF and calls the correct application handler
  • Mapping identifies which application handler should be used for a given form

Design – Configuring Inbound Processing for Interactive Offline Form

Most important Components

Inbound handler class-

  • The inbound handler for a form should be defined in the transaction SFP on the properties tab.

Function Modules, Interfaces –

  • To process inbound PDFs, an application has to implement the interface IF_FP_OFFLINE.
  • The method HANDLE_PDF is called with the PDF document the extracted form data in XML form the form-template name.
  • Function module FP_FUNCTION_MODULE_NAME for retrieving the name of a generated function module to convert the XML form data into the dictionary structures that are defined in the form interface. The structure of the XML data reflects the structure of the form context.
  • The generated function module transforms context changes back, as far as possible
  • The system administrator has to activate the SMTP plugin.
  •  In transaction SO50, the handler class CL_FP_INBOUND_HANDLER has to be defined as processing exit for the mail addresses for which offline PDFs will be Retrieve

Design%20-%20Configuring%20Inbound%20Processing%20for%20Interactive%20Offline%20Form

Design – Configuring Inbound Processing for Interactive Offline Form

System Configuration

  • The application must configure BCS appropriately in transaction SO50.
  • The main inbound handler class CL_FP_INBOUND_HANDLER must be entered as the Exit Name for the inbound e-mail address.
  • The system logs the main inbound processing steps under the object FP in the application log.
  • You can evaluate the log entries in transaction SLG1.

SO50%20System%20Configuration

SO50 System Configuration

Inbound Handler

  • Inbound%20HandlerInbound Exit classes CL_FP_INBOUND_HANDLER are singleton classes that must implement the IF_INBOUND_EXIT_BCS interface.
  • Must implement the two methods defined on this interface.
  • CREATE_INSTANCE – contains code to create the singleton instance. Must set the returning parameter RO_REF to the instance of the class.
  • PROCESS_INBOUND – contains code to process the inbound email.
  • Import parameter: IO_SREQ type ref to CL_SEND_REQUEST_BCS
  • Contains inbound email document class CL_DOCUMENT_BCS Can be used to create reply emails.
  • Import parameter: IT_RECIPIENTS type BCSY_SMTPA – list of SMTP recipients.
  • Import parameter: IT_DOCTYPES type BCSY_SODOC – list of documents types make up the email.
  • Exporting parameter: E_RETCODE – used to control processing of other
  • Inbound Exit processes in the call sequence.
  • Exporting parameter: ES_T100MSG – used to store T100 messages that can be written to a log.

Inbound%20Class

Inbound Class

Example Programs and Interactive forms for Reference

  • Offline form: FP_TEST_IA_01
  • Inbound handler class: CL_FP_OFFLINE_FP_TEST_IA_01
  • Generation and dispatch: Test report FP_TEST_IA_01
  • Trigger for inbound processing of an offline form (no e-mail): FP_TEST_INBOUND

Below is the example of form which can be used to test :

Example%20of%20Interactive%20form

Example of Interactive form

Code to handle the incoming email using the inbound handler class

method IF_FP_OFFLINE~GET_INSTANCE.
    CREATE OBJECT ro_instance TYPE ZCL_INBOUND_HANLDER_BUPA.
  endmethod.


  method if_fp_offline~handle_pdf.
constants lc_object type balobj_d  value 'FORM_TEST'.
  constants lc_subobj type balsubobj value 'OTHERS'.
  data ls_log_header type bal_s_log.
  data ls_msg        type bal_s_msg.
  data  : lv_fm_name    type rs38l_fnam,
t_return type standard table of bapiret2,
t_per_info type standard table of smum_xmltb.
  data lv_url           type string.
  data lv_preprinted    type fpboolean.
  data lv_effchangedate type sydate.
  data lv_employeeid    type string.
  data lv_department    type string.
  data lv_name          type string.
  data ls_newaddress    type fptest_smpladd.
  data ls_oldaddress    type fptest_smpladd.
  data ls_groupstates   type fptest_states.
  data :
       lv_name1 type name1,
       lv_street type ad_street,
       lv_housenumber type ad_hsnm1,
       lv_country type land1,
       lv_postalcode type ad_pstcd1,
      lv_telcountry type ad_comctry,
      lv_telephone  type ad_tlnmbr.
* Check parameters.
  if iv_form_name is initial or iv_pdf is initial or iv_xml is initial.
    raise exception type cx_fp_offline
      exporting
        textid = cx_fp_offline=>cx_fp_offline.
  endif.

* Create application log.
  ls_log_header-object     = lc_object.
  ls_log_header-subobject  = lc_subobj.
  ls_log_header-aldate_del = sy-datum + 90.
  call function 'BAL_LOG_CREATE'
    exporting
      i_s_log = ls_log_header.

  move 'S'   to ls_msg-msgty.
  move 'AD'  to ls_msg-msgid.
  move '010' to ls_msg-msgno.

* Write header log entry.
  ls_msg-msgv1 = cl_abap_classdescr=>get_class_name( me ).
  replace '\CLASS=' in ls_msg-msgv1 with ''.
  ls_msg-detlevel = '1'.
  call function 'BAL_LOG_MSG_ADD'
    exporting
      i_s_msg = ls_msg
    exceptions
      others  = 0.

* Parse the XML data and write the field values into the log,
* using the generated function module to ease this task.
  try.
      call function 'FP_FUNCTION_MODULE_NAME'
        exporting
          i_name              = iv_form_name
        importing
          ev_funcname_inbound = lv_fm_name.
    catch cx_fp_api_repository cx_fp_api_usage cx_fp_api_internal.
      message id 'FPAPIGENERIC' type 'E' number '000' with iv_form_name.
  endtry.

  if iv_form_lang is not initial.
    call function 'SCP_MIXED_LANGUAGES_1_INIT'.
    call function 'SCP_MIXED_LANGUAGES_1_SWITCH'
      exporting
        need_lang            = iv_form_lang
      exceptions
        others               = 0.
  endif.


  call function lv_fm_name
    exporting
      iv_xml_data    = iv_xml
    importing
      name1          = lv_name1
      street         = lv_street
      house_no       = lv_housenumber
      country        = lv_country
      postl_cod1     = lv_postalcode
      telcountry     = lv_telcountry
      telephone      = lv_telephone
    exceptions
      usage_error    = 1
      system_error   = 2
      internal_error = 3
      others         = 4.

  if sy-subrc is not initial.
    message id sy-msgid type sy-msgty number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  endif.
call function 'SMUM_XML_PARSE'
  exporting
    xml_input       = iv_xml
  tables
    xml_table       = t_per_info
    return          = t_return.
data : lfs_per_info type smum_xmltb.
loop at t_per_info into lfs_per_info.
    case lfs_per_info-cname.
      when 'NAME1'.
        lv_name1 = lfs_per_info-cvalue.
      when 'STREET'.
        lv_street = lfs_per_info-cvalue.
      when 'HOUSE_NO'.
        lv_housenumber = lfs_per_info-cvalue.
      when 'COUNTRY'.
        lv_country = lfs_per_info-cvalue.
      when 'POSTL_COD1'.
        lv_postalcode = lfs_per_info-cvalue.
      when 'TELCOUNTRY'.
        lv_telcountry = lfs_per_info-cvalue.
      when 'TELEPHONE'.
        lv_telephone = lfs_per_info-cvalue.
      when others.
    endcase.
  endloop.
  if iv_form_lang is not initial.
    call function 'SCP_MIXED_LANGUAGES_1_NORMAL'.
    call function 'SCP_MIXED_LANGUAGES_1_FINISH'.
  endif.

* Make the log entries.
  define add_message.
    move &1  to ls_msg-msgv1.
    move ':' to ls_msg-msgv2.
    move &2  to ls_msg-msgv3.
    move '2' to ls_msg-detlevel.
    call function 'BAL_LOG_MSG_ADD'
      exporting
        i_s_msg = ls_msg
      exceptions
        others  = 0.
  end-of-definition.
** Declarations


  add_message 'NAME1' lv_name1.
  add_message 'STREET' lv_street.
  add_message 'HOUSE_NO' lv_housenumber.
  add_message 'COUNTRY' lv_country.
  add_message 'POSTL_COD1' lv_postalcode.
  add_message 'TELCOUNTRY' lv_telcountry.
  add_message 'TELEPHONE' lv_telephone.
**---------------------------------------------------------------------
*--------------.
types: begin of ty_bpdata,
*         sel(1) type c,
         businesspartner type bapibus1006_head-bpartner,
         bpvendor type lfa1-lifnr,
         lifnr type lfa1-lifnr,
         reference(25)   type c,
         msg_type        type bapiret2-type,
         message         type bapiret2-message,
         traffic(4)      type c.
types: end of ty_bpdata.
data: lt_vend1       type standard table of mere_outtab_mkvz,
      ls_vend1       like line of lt_vend1,
      lt_vend_main   type standard table of zmere_outtab_mkvz,
      ls_vend_main   like line of lt_vend_main,
      lt_vend        type standard table of zmere_outtab_mkvz,
      ls_vend        like line of lt_vend,
*      lt_lfa1      TYPE STANDARD TABLE OF lfa1,
*      lt_lfb1      TYPE STANDARD TABLE OF lfb1,
*      lt_lfm1      TYPE STANDARD TABLE OF lfm1,
*      lt_wyt3      TYPE STANDARD TABLE OF wyt3,
*      ls_lfa1      LIKE LINE OF lt_lfa1,
      lt_lfa1        type standard table of lfa1,
      ls_lfa1        like line of lt_lfa1,
      lt_lfb1        type standard table of lfb1,
      ls_lfb1        like line of lt_lfb1,
      lt_lfm1        type standard table of lfm1,
      ls_lfm1        like line of lt_lfm1,
      lt_wyt3        type standard table of wyt3,
      ls_wyt3        like line of lt_wyt3,
      lt_adrc        type standard table of adrc,
      ls_adrc        like line of lt_adrc,
      lt_bpdata_temp type standard table of ty_bpdata,
      ls_bpdata_temp like line of lt_bpdata_temp,
      lt_bpdata      type standard table of ty_bpdata,
      ls_bpdata      like line of lt_bpdata,
      ls_bapiret2    type bapiret2.

data: partner                 type bapibus1006_head-bpartner,
      partnercategory         type bapibus1006_head-partn_cat,
      partnertype             type bapibus1006_head-partn_typ,
      partnergroup            type bapibus1006_head-partn_grp,
      partnerextno            type bapibus1006_head-extern_no,
      centraldata             type bapibus1006_central,
      centraldataperson       type bapibus1006_central_person,
      centraldataorganization type bapibus1006_central_organ,
      adressdata              type bapibus1006_address,
      businesspartner        type bapibus1006_head-bpartner,
      lt_telefondata          type standard table of bapiadtel,
      ls_telefondata          type bapiadtel,
      lt_faxdata              type standard table of bapiadfax,
      ls_faxdata              type bapiadfax,
      lt_e_maildata           type standard table of bapiadsmtp,
      ls_e_maildata           type bapiadsmtp,
      lt_return               type standard table of bapiret2,
      ls_return               type bapiret2,
      lv_msg                  type c length 1,
      lv_return               type bapiret2,
      lv_return2              type standard table of bapiret2,
      lv_message              type string,
      lv_file                 type string,
      lv_string               type string,
      lv_minbw                type string,
      lv_azekorg              type string.

data: ls_vend_master_data  type vmds_ei_main,
      lt_vendors           type vmds_ei_extern_t,
      ls_vendors           type vmds_ei_extern,
      ls_vend_header       type vmds_ei_header,
      ls_vend_central_data type vmds_ei_central_data,
      ls_vend_company_data type vmds_ei_vmd_company,
      ls_purchasing_data   type vmds_ei_vmd_purchasing,
      ls_vend_central      type vmds_ei_vmd_central,
      ls_vend_address      type cvis_ei_address1,
      ls_vend_bankdetail   type cvis_ei_bankdetail,
      lt_vend_bankdetails  type cvis_ei_bankdetail_t,
      ls_vend_bankdetails  type cvis_ei_cvi_bankdetail,
      lt_vend_company      type vmds_ei_company_t,
      ls_vend_company      type vmds_ei_company,
      lt_vend_purchasing   type vmds_ei_purchasing_t,
      ls_vend_purchasing   type vmds_ei_purchasing,
      lt_vend_functions    type vmds_ei_functions_t,
      ls_vend_functions    type vmds_ei_functions.

data: es_vend_master_data_correct   type vmds_ei_main,
      es_vend_message_correct       type cvis_message,
      es_vend_master_data_defective type vmds_ei_main,
      es_vend_message_defective     type cvis_message.
*-- Fill the BP data

  refresh: lt_telefondata.
  partnercategory = '2'.
  partnergroup = 'Y001'.
  centraldata-title_key = '0003'.
  centraldataorganization-name1 = lv_name1.
  adressdata-standardaddress = abap_true.
  adressdata-langu = 'EN'.
  adressdata-city = 'Test'.
  adressdata-postl_cod1 = lv_postalcode.
  adressdata-street = lv_street.
  adressdata-house_no = lv_housenumber.
  adressdata-country = lv_country.
  ls_telefondata-country = lv_telcountry.
  ls_telefondata-std_no = 'X'.
  ls_telefondata-telephone = lv_telephone.
  append ls_telefondata to lt_telefondata.
*-- Create BUPA
clear: businesspartner, lv_return.
  call function 'BAPI_BUPA_CREATE_FROM_DATA'
    exporting
      partnercategory         = partnercategory
      partnergroup            = partnergroup
      centraldata             = centraldata
      centraldataorganization = centraldataorganization
      addressdata             = adressdata
    importing
      businesspartner         = businesspartner
    tables
      telefondata             = lt_telefondata

     return                  = lv_return2

    .

  call function 'BAPI_TRANSACTION_COMMIT'
    exporting
      wait   = 'X'
    importing
      return = lv_return.
if businesspartner is not initial.
    ls_bpdata_temp-businesspartner = businesspartner.

  endif.
add_message 'BUPANUM' businesspartner .
* Save the log.
  call function 'BAL_DB_SAVE'
    exporting
      i_save_all = abap_true
    exceptions
      others     = 0.
 call function 'POPUP_TO_INFORM'
      exporting
        titel = 'Busines Partner Creation'
        txt1  = | Busines Partner { businesspartner } Created |
        txt2  = ' '
        txt3  = ' '
        txt4  = ' '.

lv_objtype TYPE sibftypeid,
lv_event TYPE sibfevent,
lv_objkey TYPE sibfinstid.
lv_objtype = 'ZCL_BUPA'.
lv_event = 'BUPA_CREATED.
•	Set up the LPOR instance id
ls_zcl_key- businesspartner  = businesspartner .
MOVE ls_zcl_key TO lv_objkey.
•	Raise the event
TRY.
CALL METHOD cl_swf_evt_event=>raise
EXPORTING
im_objcateg = cl_swf_evt_event=>mc_objcateg_cl
im_objtype = lv_objtype
im_event = lv_event
im_objkey = lv_objkey
•	IM_EVENT_CONTAINER =
.
CATCH cx_swf_evt_invalid_objtype .
CATCH cx_swf_evt_invalid_event .
ENDTRY.
COMMIT WORK.

  endmethod.

Error Handling :

Error handling can be done using the SLG1 transaction of code by giving the form object FP or Form test in the above example. However since all users cannot have the access to the transaction a new report can be developed by using the below logic :

  • Fetching the log details from SLG1 with the OBJECT ‘FORM_TEST’ for the incoming emails with the function block: ‘GHO_MEAS_APPLICATIONLOG_GET’.
Be the first to leave a comment
You must be Logged on to comment or reply to a post.