Skip to Content

Have you ever heard the comment from someone, “Boy I sure would like to get this report as a PDF on my computer in order to send it to Bob over in accounting. He doesn’t have a login for this BSP application and it’d be great to send him this data.” Well I haven’t either, OK, not exactly like it but similiar. It left me with two choices, 1, give “Bob” a login or 2, figure out how to output my report as PDF.
Being a frequent visitor to SDN I remembered reading a few things about PDF and outputing so I began my searching…

BSP Programming: Handling Of Non-HTML Documents

Generate file .doc or .pdf as from a text

Well after playing around with the information, and I mean really good information given in these posts/weblogs I realized that I still had a few questions left unanswered. Namely, “How do I get the data as OTF?”.

This lead me to post a new topic in the BSP forum called PDF output and with the help my fellow SDNers I think we’ve come up with all the info needed to enlighten those stubmling around in the dark like myself.

Special thanks go out to…

So we came down to basically 3 major possibilities for doing this.

  • FM: CONVERT_OTF
  • FM: CONVERT_ABAPSPOOLJOB_2_PDF
  • External Tools

To get started let’s create our BSP page.

Page Layout
\

This is basically the code from Brian’s weblog with a couple of new radio options.

Page Attributes

style=”width:350px;border:thin inset;background:lightgrey;background-color:lightgrey”>\ content\             TYPE\     STRING
display_type\     TYPE\     STRING
display_url\     TYPE\     STRING
file_content\     TYPE\     XSTRING
file_length\     TYPE\     STRING
file_mime_type\     TYPE\     STRING
file_name\     TYPE\     STRING

OnInputProcessing

That there will get all of the normal stuff working that Brian describes in his weblog on dealing with NON-HTML documents.

/wp-content/uploads/2004/11/pdfoutput_1_148925.jpg

Now let’s go into each of these 3 possibilites and see which one works best for you…

FM: CONVERT_OT

This seems to be the best possible solution; to be honest with you, I like this one. Not sure why but I do. First things first is that you have to create a SmartForm (transaction SMARTFORMS) and once you create the SmartForm just in the menu click ENVIRONMENT – FUNCTION MODULE NAME. You see once you create the SmartForm and activate it it generates a function module.

Let’s make a SmartForm

I started by calling transaction SMARTFORMS, there I gave my SmartForm a name and selected “CREATE”

Once created I started to edit the SmartForm, the first step was the Form Interface, I entered my table parameters there.

/wp-content/uploads/2004/11/pdfoutput_3_148926.jpg

Then I defined my global variables for the table and the table structure.

/wp-content/uploads/2004/11/pdfoutput_4_148927.jpg

Then on the Initalization tab of the Global section I was able to initialize my table.

/wp-content/uploads/2004/11/pdfoutput_5_148931.jpg

Then simply click on your Page and you can then create a table element, which then under the data table you define your table LOOP.

/wp-content/uploads/2004/11/pdfoutput_6_148932.jpg

Then for test purposes I simply added one cell of data and one text label to the cell, then dragged from my field list box the name of one cell to the new text box.

/wp-content/uploads/2004/11/pdfoutput_7_148933.jpg

Once that was all complete I was able to “activate” the SmartForm and then get the function module name from the menu option.

So got your SmartForm? OK, then let’s modify our code to add in for that. Go to your OnInputProcessing Event Handler and append this to the bottom of the existing code.

OnInputProcessing

As you can see we give our now selected table of data to the SmartForm for processing and then the OTF encoded results from the SmartForm to the CONVERT_OTF FM for processing.

Did you try it? Did you get your PDF file like me?

/wp-content/uploads/2004/11/pdfoutput_2_148937.jpg

FM: CONVERT_ABAPSPOOLJOB_2_PDF

Raja provided a nice code sample to work with for this option.

sy-spono will then contain your Spool number which you can then use with the function module CONVERT_ABAPSPOOLJOB_2_PDF with the Spool number as a parameter. This will return a table, PDF STRUCTURE TLINE, which you can then save with .pdf extension. As Raja pointed out “I havent tried this myself inside a BSP application, but i feel that it should work.”

From a logic point of view I will say that since the normal ABAP write statements don’t work directly in the BSP you would have to really think hard to figure out how to get this to work. We are now attempting to do just that and will post back with an update to the weblog if we figure it out.

Another option would be if you had the spool number first, for example from a select list or something. You would be as dynamic as with the SmartForm method but it should also work, just gotta convert your PDF table to XSTRING.

I think that should work, we will keep you posted on further developments using this method.

Here is a solution from Raja: SPOOL TO PDF

External Tools

Now there are lots of these tools out there, Eddy points out HTMLDOC. Eddy goes on to tell us that all we have to is

“The way to go is to install HTMLDOC, then make an external command. In your BSP page (with extension pdf, is needed for MIE) make you HTML and write it to temp file. Call the external command with the temp file as input. Then read the pdf and set it as content and set all response headers for pdf. Clean up the temp files. It works good and fast.

There are also JAVA and ActiveX tools out there as well. Each of you will have to decide your own strategy of course. Personally if the system can already do it then why install another component that you may have to worry about compatability issues with in the future?

Where does all this leave us?

So as you can see there are often many possiblities for problems you encounter and it is just a matter of deciding which one works best for you. In this case does it make sense to create a SmartForm for each and every item you want to print out? Perhaps if you have a Corporate Identity that you must adhere to then this could be the best way.

The “spool” seems like a great choice simply because you don’t have create a SmartForm first.  In fact a clever person might just have a ABAP report that runs and creates the Spool outputs and then a BSP which lets a person select an existing Spool and then retrieve it as PDF.

External tools are always available and there are lots of them out there, however, you have to ask yourself “Do you really want to add a component that may not be compatible after the next SP or Release?”. These are problems that sometimes arise as we move into the future, whereas, an internal solution such as SmartForms or ABAPSPOOL to PDF well those I think will be supported in the future.

Please consider this weblog a work in progress as I don’t think we’ve heard the end of our efforts with ABAP Spool and I’m sure there are quite a few more possible solutions out there and I hope you’ll share yours with us as well!

What the future holds!!

From Matthias Zeller, Indeed Interactive Forms is the “next generation” forms tool in SAP (and not only for interactive, but also for print forms). It is available starting with Web AS 6.40. Smart Forms and SAPscript will be continue to be available but all new development around SAP forms will be done in the new Interactive Forms. The Adobe document services (ADS) which are part of Interactive Forms can generate different output including PDF, PS, PCL and ZPL (for Zebra Label printers).
So with Interactive Forms you will be able to generate PDF in an SAP system natively by merging forms data with a form template (so you do not need to create OTF anymore and use the CONVERT_OTF libraries to generate PDF). This can be configured in ABAP using transaction SFP or with Web Dynpro for Java to create PDF documents embedded in a Web UI (and in the future also with Web Dynpro for ABAP).
The PDFs generated with ADS are actually the latest version PDF 1.6 and can be made accessible to blind people via screen readers.

Tips:
From Jonathan Bourne, Just wanted to mention that rather than hunting for the Smartforms function module name the following function module can be used:

SSF_FUNCTION_MODULE_NAME

This FM takes the Smartform name and returns the function module name. This is a more robust solution as the Smartform may receive a different FM name when it is transported to other systems.

To report this post you need to login first.

33 Comments

You must be Logged on to comment or reply to a post.

  1. Subramanian Venkateswaran
    Well you finally did it, great job, Craig.
    Without any help of SMARTFORMS from ABAP programming forum(there you go!!!).

    Thanks a million for the weblog, makes it so much easier.

    Regards,
    Subramanian V.

    (Thanks for putting me in the spotlight :P)

    (0) 
    1. Craig Cmehil
      You deserve as much credit as I do for this effort!

      I struggled for a few hours on the SmartForm – ok it’s a very basic one but it did the trick for testing purposes 🙂

      (0) 
  2. Jonathan Bourne
    Very interesting article and I’m looking forward to giving it a try once I’ve applied SP’s to WebAS 6.20 (incidentally, that is also a great article Craig).

    Just wanted to mention that rather than hunting for the Smartforms function module name the following function module can be used:
    SSF_FUNCTION_MODULE_NAME

    This FM takes the Smartform name and returns the function module name. This is a more robust solution as the Smartform may receive a different FM name when it is transported to other systems.

    Thanks again for a great article.
    JB

    (0) 
  3. Mercedes Benz South Africa
    Hi stuff guys!!

    I’m very familiar with getting PDF’s and Excel onto our Supplier Portal…great to see we are following the same process!! We recently put “EBP Purchase Order Display” via PDF into a BSP on the SAP Portal…GREAT to see you guys using a function module I haven’t used yet (CONVERT_ABAPSPOOLJOB_2_PDF), I’ve always used the “convert OTF” and then get that into PDF to get it to work…I must say the making a COMPLEX SmartForm is the “bottleneck” in the process…I hope SAP get SmartForms to the level of ease as creating a document using Crystal Reports (for example) one day!!

    But once again great work guys!!

    Lynton Grice

    (0) 
      1. Mercedes Benz South Africa
        Haven’t used it yet BUT I have to re-write the “RFQ” display + download I did in Java into BSP…I’ll give it a bach when I need to call the RFQ SmartForm. By the way there is a little problem I’m having and would LOVE a Web log on it…how can someone upload a ZIP file (Excel file zipped…) and then we use a “ZIP class” in ABAP to unzip the file on the server, take out the Excel file and pump the data into SAP. I’ve done it easily in Java BUT now need to do it in BSP…I have an idea, just wanted to know what your thoughts are (we have a Supplier Portal and this sort of thing is NB over SLOW lines!!)

        Regards

        Lynton

        (0) 
    1. Jayesh Shah
      Hi,

      Need help with the following questions.

      Hi,

      1)We want to show some details in an iView pertaining to the person who has logged into the portal. We are calling a function module (when a user clicks on a workset in the portal) and passing some parameters to it. The function module pulls the data from the tables and generates a sap script which displays the data in a SAP Script Form.

      Now our problem is how do we display the form in the iView?

      2) We want to show some details in an iView pertaining to the person who has logged into the portal. We are calling a function module (when a user clicks on a workset in the portal) and passing some parameters to it. The function module pulls the data from the tables and converts the data into a pdf file.

      How do we display the data in the .pdf format in the iView.

      Thanks in advance

      (0) 
        1. Jayesh Shah
          I have a Web Dynpro application which will call an R/3 RFC that returns a PDF file.

          1) Is it possible to pass parameters dynamically (For eg userid of the person who has logged onto the portal) from webdynpro to a RFC? If yes, how?

          Thanks in advance.

          Jayesh

          (0) 
  4. Brant Berg
    Great article.

    I was able to use your code (with minor changes) to convert mail forms to PDF.  You can use FM MAIL_FUNCTION_MODULE_NAME to get the mail form function module name, and substitute that in the ‘call function’ of OnInputProcessing

    Thanks, you saved me tons of work!

    Brant Berg

    (0) 
  5. Greetson Shunmugasundaram
    Hi All,
    Is the same code will work in MVC Concept????

    If yes where we need to write all the code??
    is it in the DO_HANDLE_EVENT or in the View page??

    Expecting the reply ASAP.

    Thanks,
    Greetson

    (0) 
    1. Craig Cmehil
      First off you can expect anything you want ASAP but the reality of it is that you probably won’t get it. I mean this isn’t a support desk and we are all here just trying to help each other out.

      As for this code, yes it works fine in MVC and where you write it all depends on you and your application.

      If you have specific questions take a jump over to the BSP forum, it’s a much better place for helping each other out.

      (0) 
  6. Stephan Westmark
    Great article. Thank you.

    Still, I’m wondering which table you use for zsystems.
    data: lt_sys type table of zsystems.
    I cannot find this table. Would you please tell me the origin?
    And which table do you use for zsystemtab? This table is referenced within the smartform

    Thank you very much for your help,
    Stephan

    (0) 
    1. Craig Cmehil
      Sorry about that the Z indicates a customer created object. So in this case ZSYSTEMS is a table I created that contains basic system info, we have over 100 systems. ZSYSTEMTAB is a “table type” defined with the line type ZSYSTEMS.

      Craig

      (0) 
  7. Jose Manuel Cala Lopez
    I have tried to convert an ABAP list with FM CONVERT_ABAPSPOOLJOB_2_PDF, but it doesn’t work. The problem is the conversion of table of type tline returns by the FM to a xstring. I have tried all solutions in this weblog and in the BSP forum, but anything works.

    I do the test in a 6.40 UNICODE system.

    Finally, I find a code to do the conversion:

    data: spool_nr type TSP01-RQIDENT,
    line type tline,
    l_pdf_xstring type xstring,
    lt_lines type table of tline,
    l_pdf_len type i.
    field-symbols

    type X.

    …code to obtain the spool_nr…

    CALL FUNCTION ‘CONVERT_ABAPSPOOLJOB_2_PDF’
    EXPORTING
    SRC_SPOOLID = spool_nr
    NO_DIALOG = ‘ ‘
    IMPORTING
    PDF_BYTECOUNT = l_pdf_len
    TABLES
    PDF = lt_lines
    EXCEPTIONS
    ERR_NO_ABAP_SPOOLJOB = 1
    ERR_NO_SPOOLJOB = 2
    ERR_NO_PERMISSION = 3
    ERR_CONV_NOT_POSSIBLE = 4
    ERR_BAD_DESTDEVICE = 5
    USER_CANCELLED = 6
    ERR_SPOOLERROR = 7
    ERR_TEMSEERROR = 8
    ERR_BTCJOB_OPEN_FAILED = 9
    ERR_BTCJOB_SUBMIT_FAILED = 10
    ERR_BTCJOB_CLOSE_FAILED = 11
    OTHERS = 12
    .

    clear l_pdf_xstring.
    loop at lt_lines into line.
    assign line to

    casting type X.
    concatenate l_pdf_xstring

    into l_pdf_xstring in byte mode.
    endloop.
    l_pdf_len = xstrlen( l_pdf_xstring ).

    …code to make cached_response…

    (0) 
    1. Jose Manuel Cala Lopez
      Problems with the html formating. Code is as:


      data: spool_nr type TSP01-RQIDENT,
      line type tline,
      l_pdf_xstring type xstring,
      lt_lines type table of tline,
      l_pdf_len type i.
      field-symbols

      type X.

      ...code to obtain the spool_nr...

      CALL FUNCTION 'CONVERT_ABAPSPOOLJOB_2_PDF'
      EXPORTING
      SRC_SPOOLID = spool_nr
      NO_DIALOG = ' '
      IMPORTING
      PDF_BYTECOUNT = l_pdf_len
      TABLES
      PDF = lt_lines
      EXCEPTIONS
      ERR_NO_ABAP_SPOOLJOB = 1
      ERR_NO_SPOOLJOB = 2
      ERR_NO_PERMISSION = 3
      ERR_CONV_NOT_POSSIBLE = 4
      ERR_BAD_DESTDEVICE = 5
      USER_CANCELLED = 6
      ERR_SPOOLERROR = 7
      ERR_TEMSEERROR = 8
      ERR_BTCJOB_OPEN_FAILED = 9
      ERR_BTCJOB_SUBMIT_FAILED = 10
      ERR_BTCJOB_CLOSE_FAILED = 11
      OTHERS = 12
      .

      clear l_pdf_xstring.
      loop at lt_lines into line.
      assign line to

      casting type X.
      concatenate l_pdf_xstring into l_pdf_xstring
      in byte mode.
      endloop.
      l_pdf_len = xstrlen( l_pdf_xstring ).

      ...code to make cached_response...

      (0) 
  8. Community User
    The table contained (no longer have it) just the SID of the system and the name (desc) of the system not really anything much.

    This was also on a 620 system. But you can really use any tables.

    (0) 
  9. Anubhav Jain
    I have used my smartform:zdpbir and table:zdpbar and the generated FM for smartform is ‘/1BCDWB/SF00000571’  , but when i execute the BSP Application it throws the following error:
    SAP Note

    The following error text was processed in the system:
    An exception with the type CX_SY_DYN_CALL_PARAM_MISSING occurred, but was neither handled locally, nor declared in a RAISING clause

     
    Exception Class CX_SY_DYN_CALL_PARAM_MISSING
    Error Name 
    Program CL_O20Q0EUR89BCFKJ1CHWU5YVP65JCP
    Include CL_O20Q0EUR89BCFKJ1CHWU5YVP65JCM005
    ABAP Class CL_O20Q0EUR89BCFKJ1CHWU5YVP65J
    Method _ONINPUTPROCESSING
    BSP Application ZANU_PDF_OUTPUT
    BSP Page FIRST.HTM
    Line 99 
    Long text The call of the function /1BCDWB/SF00000571 failed: the required parameter WA_ZDPBIR was not filled.

    What is the reason and possible solution?
    Regards,
    Anubhav Jain.

    (0) 
  10. Hallo

    I want to convert a smartform document into pdf in my BSP Applikation.
    But when it have to convert, i got the message “Data didnt begins with ‘%pdf-‘”in the pdf reade . I dont know why???

    Here is my Code from the Intialization Event:

    * event handler for data retrieval

    * parameters for generated function module
    data: l_function_module_name type rs38l_fnam,
          ls_output_options      type ssfcompop,
          ls_control_parameters  type ssfctrlop,
          ls_output_data         type ssfcrescl,
          l_devtype              type rspoptype.

    * generated result: HTML with embedded CSS
    data: ls_xmloutput   type ssfxmlout,
          lt_html_raw    type tsfixml,
          l_xstring      type xstring,    “needed for HTTP response
          l_html_xstring type xstring,
          l_xlength      type i.


    * generated result: PDF format
    data: l_pdf_xstring  type xstring,
          lt_lines       type table of tline,
          ls_line        type tline,
          l_pdf_len      type i.

    * Cookie mit Eingabewerten holen
    cl_bsp_server_side_cookie=>get_server_cookie(
      EXPORTING
         name                      = ‘lt_fields’
         application_namespace     = ‘NONE’
         application_name          = ‘NONE’
         username                  = ‘NONE’
         session_id                = ‘NONE’
         data_name                 = ‘NONE’
      “IMPORTING
        “expiry_date                = date
        “expiry_time                = time
      CHANGING
        data_value                 = lt_fields ).


    * Cookie mit Equipmentdaten holen
    cl_bsp_server_side_cookie=>get_server_cookie(
      EXPORTING
         name                      = ‘ums_equip_ges’
         application_namespace     = ‘NONE’
         application_name          = ‘NONE’
         username                  = ‘NONE’
         session_id                = ‘NONE’
         data_name                 = ‘NONE’
      “IMPORTING
        “expiry_date                = date
        “expiry_time                = time
      CHANGING
        data_value                 = ums_equip ).

    *———————————————————————–
    * Get name of generated function module
    *———————————————————————–
    call function ‘SSF_FUNCTION_MODULE_NAME’
         exporting  formname           = ‘Z_REPKOST_GES’
    *                 variant            = ‘ ‘
    *                 direct_call        = ‘ ‘
         importing  fm_name            = l_function_module_name
         exceptions no_form            = 1
                    no_function_module = 2
                    others             = 3.

    if sy-subrc  0.
    *   error handling
      message id sy-msgid type sy-msgty number sy-msgno
              with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      exit.
    endif.

    *—————————————————————————
    * get device type from language
    *—————————————————————————
    call function ‘SSF_GET_DEVICE_TYPE’
      exporting
        i_language                   = sy-langu
    *     i_application                = ‘SAPDEFAULT’
      importing
        e_devtype                    = l_devtype
      exceptions
        no_language                  = 1
        language_not_installed       = 2
        no_devtype_found             = 3
        system_error                 = 4
        others                       = 5.

    if sy-subrc  0.
    *   error handling
      message id sy-msgid type sy-msgty number sy-msgno
              with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endif.

    * set device type in output options
    ls_output_options-tdprinter = l_devtype.

    *———————————————————————–
    * Call the generated function module
    *———————————————————————–
    call function l_function_module_name
         exporting
    *                 archive_index        =
    *                 archive_parameters   =
                    control_parameters   = ls_control_parameters
    *                 mail_appl_obj        =
    *                 mail_recipient       =
    *                 mail_sender          =
                    output_options       = ls_output_options
                    user_settings        = space
                    UMS_EQUIP             = UMS_EQUIP
                    LT_FIELDS             = LT_FIELDS

         importing
    *                 document_output_info =
                    job_output_info      = ls_output_data
    *                 job_output_options   =
    *      tables
    *                zsystems             = lt_sys
         exceptions formatting_error     = 1
                    internal_error       = 2
                    send_error           = 3
                    user_canceled        = 4
                    others               = 5.

    if sy-subrc  0.
    *   error handling
      message id sy-msgid type sy-msgty number sy-msgno
              with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endif.

    *———————————————————————–
    * Conversion of output format OTF into PDF format
    *———————————————————————–
    * now convert the final document (OTF format) into PDF format
    call function ‘CONVERT_OTF’
         exporting
           format                      = ‘PDF’
    *        MAX_LINEWIDTH               = 132
    *        ARCHIVE_INDEX               = ‘ ‘
    *        COPYNUMBER                  = 0
         importing
           bin_filesize                = l_pdf_len
           bin_file                    = l_pdf_xstring       ” binary file
         tables
           otf                         = ls_output_data-otfdata
           lines                       = lt_lines
         exceptions
           err_max_linewidth           = 1
           err_format                  = 2
           err_conv_not_possible       = 3
           err_bad_otf                 = 4
           others                      = 5
                  .
    if sy-subrc  0.
    *   error handling
      message id sy-msgid type sy-msgty number sy-msgno
              with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endif.

    DATA: cached_response TYPE REF TO if_http_response.
    DATA: guid TYPE guid_32.
    DATA: fileUpload TYPE REF TO CL_HTMLB_FILEUPLOAD.

    if sy-subrc EQ 0.

        CREATE OBJECT cached_response TYPE  CL_HTTP_RESPONSE EXPORTING add_c_msg = 1.

        l_pdf_len = xstrlen( l_pdf_xstring ).
        cached_response->set_data( data   = l_pdf_xstring
                            length = l_pdf_len ).

        cached_response->set_header_field( name  = if_http_header_fields=>content_type
                                           value = ‘application/pdf’ ).
        cached_response->set_status( code = 200 reason = ‘OK’ ).
        cached_response->server_cache_expire_rel( expires_rel = 180 ).

        CALL FUNCTION ‘GUID_CREATE’
          IMPORTING
            ev_guid_32 = guid.
        CONCATENATE runtime->application_url ‘/’ guid     ‘.pdf’INTO display_url.

        cl_http_server=>server_cache_upload( url      = display_url
                                             response = cached_response ).

      ENDIF.
      RETURN.

    I hope you can help me.

    Kind Regards

    (0) 
  11. Abhishek Periwal
    Hi Craig,
    I am having some problem in generating the cached response. I am writing my code in a method of a class which is triggered from Web UI. The object runtime is not defined here so it throws an error each time. Please let me know how should I proceed.
    Thanks,
    Abhishek
    (0) 
  12. Anton Wenzelhuemer

    too bad that this blog is nearly unreadable. it would still be very useful today and is cited on some pecial interest pages.

    good job done long time ago. and now back to the future 🙂

    (0) 

Leave a Reply