Skip to Content

I try to blog. Some people will say most of it is not technical. And yes, they would be right. Today I’m issuing a challenge. It is specific to all those people who are out there writing ABAP. It could also be for non-ABAP languages. Get the theme? Technical blog.

My challenge: Write a blog about what you are working on!

Why? Because when I ask people why they don’t write blogs about ABAP, the answer is that it’s all been done. We don’t want to just repeat things. So if you are writing about your project you won’t be duplicating anything. AND we will get some new ABAP (technical type) blogs.  Heck, you can write about an old project, we wouldn’t know. It can also be an old project.

You can share as little or as much code as you want!

This is cool, because there is something in it for you!

Over one million users stop in to the SAP Community. If you aren’t doing something “right” then they will probably comment. Worried about that? Don’t be. I don’t do a lot of things “right”. That’s OK. I learn and get better. Note to those who comment constructive feedback is always welcome. Rude feedback is not welcome. An example would be you telling me that I’m an idiot. Yes, part of the rules. Sadly, people like me rarely read all of them.   (I did not either – but I’m going to go look at them today.)

Anyway Challenge time

So I thought – I’d just pull out a project that I worked on before.   I am on 4.6C. Yes, it’s still working great! That means I have limited access to classes/objects. That’s why I’ve been bookmarking so many things.

So I’m trying to decide what fun things to share from the project.    I think you may want to know the description. We wanted to save our “PDF” documents to a directory, be able to retrieve and mail them. This is a general area where we could put whatever documents we wanted.  I think we have more than 10 types of documents there. Some we create at the time we are using this, Some are uploaded from a directory, some are created via output types and/or messages.  It just depended on what we wanted.  And we could add or remove document types at a later date.

I decided to share the mailing piece of it because it could use some help with some of the newer ABAP objects that are available.

This is a function module that accepts the email name, the document and the body.  The document is actually a key for where we pull the information. It is also an RFM – it’s called from a webpage.

 LOOP AT gt_doc INTO gs_doc.
    IF gv_message IS INITIAL.
      PERFORM check_input.
    ELSE.
      message = gv_message.
      EXIT.
    ENDIF.
  ENDLOOP.
  IF gv_message IS INITIAL.
    PERFORM fill_receiver_table.
    gv_start = 1.
    gv_cnt = 1.
    LOOP AT gt_doc INTO gs_doc.
      PERFORM get_attachment.
    ENDLOOP.
    IF gt_contents_bin IS INITIAL.
      gv_message = 'No attachments selected.'.
      message = gv_message.
    ELSE.
      PERFORM email_create.
      PERFORM send_email.
    ENDIF.
    message = gv_message.
  ENDIF.

So this tells you next to nothing.  Here I loop through the receivers:

  LOOP AT gt_email INTO gs_email.
    CLEAR gs_receivers.
    gs_receivers-receiver = gs_email-email_add.
    gs_receivers-com_type = lc_send_internet.
    gs_receivers-rec_type = lc_internet.
    APPEND gs_receivers TO gt_receivers.
  ENDLOOP.

Easy! Now I’m pulling the “PDF” from our system:

 OPEN DATASET docs-file_name FOR INPUT IN BINARY MODE.

  IF sy-subrc <> 0.
    CONCATENATE 'Could not open file' docs-file_name
        INTO message SEPARATED BY space.
    PERFORM update_log USING imp
                             message
                             docs-file_name.
    EXIT.
  ENDIF.

  DO.
    READ DATASET docs-file_name INTO pdf LENGTH lv_size.
    IF sy-subrc <> 0.
      EXIT.
    ENDIF.
    pdf_size = pdf_size + lv_size.
    APPEND pdf.
  ENDDO.

Got it!  So now I get it ready!

* Move the 134 character table to a 255 format need for PDF attachment
    CALL FUNCTION 'SX_TABLE_LINE_WIDTH_CHANGE'
         EXPORTING
              line_width_dst              = 255
         TABLES
              content_in                  = lt_pdf[]
              content_out                 = lt_contents_bin[]
         EXCEPTIONS
              err_line_width_src_too_long = 1
              err_line_width_dst_too_long = 2
              err_conv_failed             = 3
              OTHERS                      = 4.

* Add the contents to the table that will have all the attachments
    CLEAR ls_contents_bin.
    LOOP AT lt_contents_bin INTO ls_contents_bin.
      APPEND ls_contents_bin TO gt_contents_bin.
      CLEAR gs_contents_bin.
    ENDLOOP.

    CLEAR: lv_lines_bin, gs_packing_list.
* Set up the name & Description
    WRITE gs_doc-document TO lv_document NO-ZERO.
    WRITE gs_doc-document TO lv_document15 NO-ZERO.
    WRITE gs_doc-item TO lv_item NO-ZERO.
    WRITE gs_doc-item TO lv_item6 NO-ZERO.
    WRITE gv_cnt TO lv_cnt NO-ZERO.
    CONDENSE: lv_document NO-GAPS,
              lv_document15 NO-GAPS,
              lv_item NO-GAPS,
              lv_item6 NO-GAPS,
              lv_cnt NO-GAPS.
    CONCATENATE lv_document lv_item lv_cnt
                INTO gs_packing_list-obj_name.
    CONCATENATE lv_document15 lv_item6 lv_cnt
                INTO gs_packing_list-obj_descr
                SEPARATED BY space.

* Set up the packing list describint the current attachment

    DESCRIBE TABLE lt_contents_bin LINES lv_lines_bin.
    READ TABLE lt_contents_bin INTO ls_contents_bin INDEX lv_lines_bin.
    gs_packing_list-transf_bin = 'X'.
    gs_packing_list-head_start = gv_start.
    gs_packing_list-head_num = gv_start.
    gs_packing_list-body_start = gv_start.
    gs_packing_list-doc_type = 'PDF'.
    gs_packing_list-doc_size = lv_pdf_size.
    gs_packing_list-body_num = lv_lines_bin.
    APPEND gs_packing_list TO gt_packing_list.

* Set up start position for next attachment
    gv_start = gv_start + lv_lines_bin.
    gv_cnt = gv_cnt + 1.
  ENDIF.

Here’s the fun part – creating the attachment.

 CLEAR: gs_contents_txt, gs_packing_list.
  READ TABLE gt_doc INTO gs_doc INDEX 1.
  lv_numc = gs_doc-document.
  lv_vbeln = lv_numc.
* Create Message Body Title and Description
  IF gs_imp-mail_mess IS INITIAL AND
     gt_email_body IS INITIAL.
    gs_contents_txt-line = 'See attachment.'.
    APPEND gs_contents_txt TO gt_contents_txt.
  ELSEIF NOT gs_imp-mail_mess IS INITIAL.
    ls_text-mail_mess = gs_imp-mail_mess.
    APPEND ls_text TO lt_text.
    CALL FUNCTION 'CONVERT_STREAM_TO_ITF_TEXT'
         EXPORTING
              language    = sy-langu
         TABLES
              text_stream = lt_text[]
              itf_text    = lt_mail_content[].

    LOOP AT lt_mail_content INTO ls_mail_content.
      gs_contents_txt-line = ls_mail_content-tdline.
      APPEND gs_contents_txt TO gt_contents_txt.
    ENDLOOP.
  ELSE.
    LOOP AT gt_email_body INTO gs_email_body.
      gs_contents_txt-line = gs_email_body-email.
      APPEND gs_contents_txt TO gt_contents_txt.
    ENDLOOP.
  ENDIF.

  IF gs_imp-doc_type IS INITIAL.
    READ TABLE gt_doc INTO gs_doc INDEX 1.
    IF sy-subrc = 0.
      gs_imp-doc_type = gs_doc-doc_type.
    ENDIF.
  ENDIF.

  IF gs_imp-doc_type = 'TD'.

    SELECT SINGLE vbeln INTO vbak FROM vbak       
    WHERE vbeln = lv_vbeln.                      
    IF sy-subrc = 0.
      CALL FUNCTION 'SD_SALES_DOCUMENT_READ'
           EXPORTING
                document_number      = lv_vbeln
                i_block              = ' '
                i_no_authority_check = 'X'
           IMPORTING
                ekuwev               = ls_ekuwev.
      IF NOT ls_ekuwev-name1 IS INITIAL.
        CONCATENATE 'Deliver to ' ls_ekuwev-name1
                     INTO lv_obj_descript
                     SEPARATED BY space.
      ENDIF.
    ELSE.
      SELECT SINGLE banfn INTO eban FROM eban        
      WHERE banfn = lv_vbeln.                       
      IF sy-subrc = 0.
        CONCATENATE 'Deliver to' 'Furst-McNess Company'
                     INTO lv_obj_descript
                     SEPARATED BY space.

      ENDIF.

    ENDIF.

  ENDIF.
  IF NOT gs_imp-doc_type IS INITIAL AND
         lv_obj_descript IS INITIAL.
    SELECT SINGLE description INTO lv_description
           FROM zdoc_types
             WHERE doc_type = gs_imp-doc_type.
    IF sy-subrc = 0.
      CONCATENATE 'McNess' lv_description 'Document'
            INTO lv_obj_descript
            SEPARATED BY space.
    ENDIF.
  ENDIF.
  IF lv_obj_descript IS INITIAL.
    gs_document_data-obj_descr = 'McNess Documents'.
  ELSE.
    gs_document_data-obj_descr = lv_obj_descript.
  ENDIF.
  gs_document_data-expiry_dat = sy-datum + 10.

  gs_document_data-sensitivty = 'F'.
  gs_document_data-doc_size = gv_total_size.

* Body of E-mail
  CLEAR gs_packing_list.
  gs_packing_list-head_start = 1.
  gs_packing_list-head_num = 0.
  gs_packing_list-body_start = 1.
  gs_packing_list-body_num = gv_start.
  gs_packing_list-doc_type = 'RAW'.
  INSERT gs_packing_list INTO gt_packing_list INDEX 1.

 

Finally Send it!

TYPES: BEGIN OF lty_obj,
         tp TYPE soos-objtp,
         yr TYPE soos-objyr,
         no TYPE soos-objno,
         END OF lty_obj.

  DATA: lv_objid TYPE sofolenti1-object_id,
        ls_obj TYPE lty_obj,
        lv_objtp TYPE soos-objtp.

  CALL FUNCTION 'SO_NEW_DOCUMENT_ATT_SEND_API1'
       EXPORTING
            document_data              = gs_document_data
            put_in_outbox              = ' '
            commit_work                = 'X'
       IMPORTING
            new_object_id              = lv_objid
       TABLES
            packing_list               = gt_packing_list[]
            contents_txt               = gt_contents_txt[]
            contents_bin               = gt_contents_bin[]
            receivers                  = gt_receivers[]
       EXCEPTIONS
            too_many_receivers         = 1
            document_not_sent          = 2
            document_type_not_exist    = 3
            operation_no_authorization = 4
            parameter_error            = 5
            x_error                    = 6
            enqueue_error              = 7
            OTHERS                     = 8.
  IF sy-subrc <> 0.
    CASE sy-subrc.
      WHEN 1.
        MESSAGE e007  INTO gv_message.
      WHEN 2.
        MESSAGE e008 INTO gv_message.
      WHEN 3.
        MESSAGE e009 INTO gv_message.
      WHEN 4.
        MESSAGE e010 INTO gv_message.
      WHEN OTHERS.
        MESSAGE e011 INTO gv_message.
    ENDCASE.
  ELSE.
    ls_obj = lv_objid.
    COMMIT WORK AND WAIT.
*** Try to verify the record is ready to send - wait only 100 times
    DO 100 TIMES.
      SELECT SINGLE  objtp INTO lv_objtp
        FROM soos
          WHERE objtp = ls_obj-tp AND
                objyr = ls_obj-yr AND
                objno = ls_obj-no.
      IF sy-subrc = 0.
        EXIT.
      ENDIF.
    ENDDO.

    SUBMIT rsconn01 WITH mode = 'INT' AND RETURN.
*    gv_message = 'Mail sent'.
  ENDIF.

 

This is the end of just a piece of that development.  We have screens where the user can enter requests for different documents.  If they double click then they have the PDF display so they can look at it prior to sending it. AND a co-worker put together a webpage that calls some of this code. That ways it can look pretty when they call it. And yes – this was 4.6C. She used JavaScript and Visual Basic. Cool. This is prior to even Webdynpro.

GUI Result:

 

Webpage result:

 

So my challenge is to share your project.  As much or as little code as you want. I promise we will be nice!

A side challenge – use objects to send the e-mail. I didn’t have them available. SO if someone could put them in the comments – that would be so nice.

Also anything else you would like to know about this? Hate the idea? Feel free to comment. I love responding to them.

To report this post you need to login first.

9 Comments

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

  1. Panda Cheng

    The interface of displaying PDF is really nice.

    I‘ll show this blog to my partner and tell him how to develop a nice display interface ^_^.

    Moreover, would you show more details about displaying PDF within a dialog screen?

     

    (1) 
  2. Jelena Perfiljeva

    There is a good old blog about the “new way” to send emails using CL_BCS class. It’s been a bit mangled by the new “world class” blog platform, unfortunately. Maybe a moderator could volunteer to fix and retag it?

    Considering the low version, I think it’s pretty cool, with web page and all. We’ve also used PDF documents and emails a lot in my old job. We used GOS attachments to make the documents available in the standard transactions. Of course, that’s not of use in 4.6 either. 🙂 If anything, I feel this makes me appreciate more what we have in ECC. And I imagine there are tons of things I don’t even know we have available.

    (3) 
    1. Michelle Crapo Post author

      Too true! A lot of advancement forward with the newer versions. I have to say I do miss 6.0 badly at times. Thank you for the CL_BCS class! I knew there was one.

      Yes – GOS, too new fangled for me. BUT it will be of use for people who read this, and want to do it in a different way.

      Thank you!

      (0) 
  3. Florian Henninger

    Hi Michelle,

    like the blog and like the challenge. Years ago, in my first project as an developer I also had to send mails and did it in a very similar way.

    Doing a blog about an ongoing project is a nice way to share something. Right at the moment I’m struggling putting an app to my Gateway, so this will be my blog for your challenge.

    Let’s see how long it takes to get it running 🙂

    ~Florian

     

    (1) 
  4. Florian Henninger

    Hi Michelle,

     

    here you got a codingline how to use the cl_bcs Jelena Perfiljeva mentioned.

    Some of those variables are selfmade, but I think everyone can get out how to use the class. I have wrapped it into a function to replace the call function easily.

    'SO_NEW_DOCUMENT_ATT_SEND_API1'
    DATA: lcl_send_request       TYPE REF TO cl_bcs.
      DATA: lt_text                TYPE bcsy_text.
      DATA: lcl_document           TYPE REF TO cl_document_bcs.
      DATA: lcl_sender             TYPE REF TO cl_sapuser_bcs.
      DATA: lcl_reply_guy          TYPE REF TO if_recipient_bcs.
      DATA: lcl_recipient          TYPE REF TO if_recipient_bcs.
      DATA: bcs_exception          TYPE REF TO cx_bcs.
      DATA: lv_sent_to_all         TYPE os_boolean.
      DATA: lv_in_updatetask       TYPE sysubrc.
    
      ls_mailbasics = is_email_basic.
      lt_attachments = it_attachments.
      lv_express = iv_express_sending.
      lv_errorscreen = iv_with_errorscreen.
    
      IF ls_mailbasics-recipienttab IS INITIAL.
        RAISE no_recipients.
      ENDIF.
    
      IF ls_mailbasics-subject IS INITIAL.
        RAISE no_subject.
      ENDIF.
    
    
      TRY.
    *     -------- create persistent send request ------------------------
          lcl_send_request = cl_bcs=>create_persistent( ).
    
    
    *     -------- create and set document -------------------------------
    *     create document from internal table with text (Bodytext)
          lcl_document = cl_document_bcs=>create_document(
                          i_type    = ls_mailbasics-type      "First step always RAW
                          i_text    = ls_mailbasics-chardata
                          i_length  = ls_mailbasics-length
                          i_subject = ls_mailbasics-subject ).
    
    *     -------- add attachment-documents -------------------------------
    *     put all attachments to the email
          LOOP AT lt_attachments INTO ls_attachment.
            CALL METHOD lcl_document->add_attachment
              EXPORTING
                i_attachment_type    = ls_attachment-type     "Should be always BIN in first release
                i_attachment_subject = ls_attachment-subject
                i_att_content_text   = ls_attachment-chardata
                i_att_content_hex    = ls_attachment-hexdata.
    
          ENDLOOP.
    
    *     add document to send request
          CALL METHOD lcl_send_request->set_document( lcl_document ).
    
    *     --------- set sender -------------------------------------------
    * We want another sender for this document!
          IF ls_mailbasics-sender IS NOT INITIAL.
            lcl_sender = cl_sapuser_bcs=>create( ls_mailbasics-sender ).
            CALL METHOD lcl_send_request->set_sender
              EXPORTING
                i_sender = lcl_sender.
          ENDIF.
    
    *     --------- set reply-recipient ----------------------------------
    * We need to get the reply to the given user!
          IF ls_mailbasics-reply_to_email IS NOT INITIAL.
            lcl_reply_guy = cl_cam_address_bcs=>create_internet_address(
                                                     ls_mailbasics-reply_to_email ).
    
    *     add reply-recipient with its respective attributes to send request
            CALL METHOD lcl_send_request->set_reply_to
              EXPORTING
                i_reply_to = lcl_reply_guy.
          ENDIF.
    *     --------- add recipient (e-mail address) -----------------------
    *     create recipient - please replace e-mail address !!!
    
          LOOP AT  ls_mailbasics-recipienttab INTO ls_recipient.
    
            lcl_recipient = cl_cam_address_bcs=>create_internet_address(
                                                                   ls_recipient ).
    
    *     add recipient with its respective attributes to send request
            CALL METHOD lcl_send_request->add_recipient
              EXPORTING
                i_recipient = lcl_recipient
                i_express   = lv_express.
    
          ENDLOOP.
    
    *     ---------- send document ---------------------------------------
          CALL METHOD lcl_send_request->send(
            EXPORTING
              i_with_error_screen = lv_errorscreen
            RECEIVING
              result              = lv_sent_to_all ).
          IF lv_sent_to_all = 'X'.
            WRITE text-003.
          ENDIF.
    
          CALL FUNCTION 'TH_IN_UPDATE_TASK'
            IMPORTING
              in_update_task = lv_in_updatetask.
    *         We are not in an Updatetask
          IF lv_in_updatetask = 0.
            COMMIT WORK.
          ENDIF.
    
    * -----------------------------------------------------------
    * *                     exception handling
    * -----------------------------------------------------------
    * * replace this very rudimentary exception handling
    * * with your own one !!!
    * But, if we get here, someone who wants to use this function
    * do not understand how this work!
    * So, a exception is quiet consequent!
    * -----------------------------------------------------------
        CATCH cx_bcs INTO bcs_exception.
    *      WRITE: text-001.
    *      WRITE: text-002, bcs_exception->error_type.
    *      EXIT.
    
          RAISE something_went_wrong.
    
      ENDTRY.
    (2) 

Leave a Reply