SAP ABAP 基于 CL_BCS 发送邮件

目录

1.前言:

2.介绍:

3.正文:

3.1自开发邮件发送工具类的使用:

3.2邮件模板上传及调用:

3.2.1 SO10上传邮件模板

3.2.2 SMW0上传html模板

3.2.3 SE80->Email Template创建邮件模板

3.3.模板中图片的替换

3.3.1 直接指定图片Base64编码

3.3.2 使用SMW0上传图片

3.3.3 使用SO2_MIME_REPOSITORY上传图片

3.4.Smartforms转PDF并添加为邮件附件

3.4.1 PDF合并功能:

3.5.ALV转换为PDF并添加为邮件附件

3.6.添加文件扩展名后缀为4位的附件,如xlsx附件

3.6.1添加本地上传的文件至邮件附件

3.6.2将程序内表转换为xlsx内容并添加至附件 

3.7.框架源码及表结构信息

3.8.SE38 Demo程序源码


1.前言:

总结这边文章起因是近期碰到需要使用ABAP给客户发送邮件功能,需求只是简单的发送邮件并且将明细内容以表格形式置于邮件正文中,之前只是知道大概怎么发送邮件,没有自己完整的从头写过,所以借着这个机会把发送邮件这部分能想到的需求全部进行集中测试实现,以后就不用再到处搜了。


2.介绍:

发送邮件的API有很多种,但是SAP早在note190669中就提到,推荐使用CL_BCS来进行邮件发送,BCS(Business Communication Service)接口提供了一种舒适的、基于类的方法来发送文档,比起API1接口,更易使用,参数更加清晰和容易理解,也不在需要填充让人难以理解的装箱单参数,此外,CL_BCS还提供了更多选项。

比较旧的功能模块:

  • SO_DOCUMENT_SEND_API1
  • SO_NEW_DOCUMENT_ATT_SEND_API1
  • SO_NEW_DOCUMENT_SEND_API1
  • SO_OBJECT_SEND
  • EFG_GEN_SEND_EMAIL
  • SO_DOCUMENT_REPOSITORY_MANAGER

SAP针对于CL_BCS提供了以下示例程序可供参考,这些程序是模板程序,不能直接执行,因为有些内容是硬编码的:

  • BCS_EXAMPLE_1:发送文本内容
  • BCS_EXAMPLE_2:发送文本内容及附件
  • BCS_EXAMPLE_3:根据用户名发送邮件
  • BCS_EXAMPLE_4:在选择框中选择收件人并发送邮件
  • BCS_EXAMPLE_5:发送文本内容及Doc文件附件
  • BCS_EXAMPLE_6:发送PDF附件(AdobeFrom转PDF)
  • BCS_EXAMPLE_7:发送XLS附件
  • BCS_EXAMPLE_8:将假脱机请求列表中的PDF文件转为邮件附件发送

3.正文:

2023.12.08日更新,更新内容已在底部源码中添加

追加添加xlsx附件的实现:

        1.添加本地上传的xlsx附件;

        2.添加通过内表转换的xlsx附件。

基于平时开发习惯,我将邮件功能调用的部分基于CL_BCS封装成了一个自开发工具类,将一些通用功能进行封装,可以使代码调用时,可以减少重复的代码量,基于该封装类我同时创建了一份参考代码,其中包括以下功能:

  • 发送正文格式为普通文本格式的邮件
  • 发送正文格式为html的邮件(html部分由ABAP代码手工生成)
  • 发送正文格式基于电子邮件模板的邮件(SE80->Email Template,可与CDS关联)
  • 发送正文格式基于电子邮件模板的邮件(SMW0->上传HTML Template)
  • 在邮件正文中动态替换SMW0上传的图片
  • 在邮件正文中动态替换SO2_MIME_REPOSITORY上传的图片
  • 在邮件中添加.txt格式附件
  • 在邮件中添加.csv格式附件
  • 在邮件中添加.xlsx格式附件(本地上传&内表转换)
  • 在邮件中添加由Smartforms转换为PDF的附件(可进行多个PDF合并)
  • 在邮件中添加由ALV打印为表格格式PDF的附件

在实现这些功能的过程中,或多或少都碰到了一些问题,在后文中我会将解决方式详细补充。 

Demo程序效果:

 

3.1自开发邮件发送工具类的使用:

以下代码截图为封装的工具类的部分源码,完整源码会在最下面附上。

实例化邮件对象:

*       create instance of CL_BCS
        lo_send_request = cl_bcs=>create_persistent( ).

设置发件人:

*       Set sender email address
        lo_mail_from = cl_cam_address_bcs=>create_internet_address( iv_mail_from_address ).
        lo_send_request->set_sender( lo_mail_from ).

设置收件人及立即发送:

*       Set receiver email address
        LOOP AT it_mail_to_address INTO DATA(ls_mail_to_address).
          lo_mail_to = cl_cam_address_bcs=>create_internet_address( ls_mail_to_address ).

*         Send immediately
          lo_send_request->set_send_immediately( i_send_immediately = abap_true ).

*         Set address
          lo_send_request->add_recipient( i_recipient = lo_mail_to
                                          i_express   = abap_true ).
        ENDLOOP.

设置抄送人及立即发送,i_copy 参数指定为'X'即可:

*       Set CC email address
        LOOP AT it_mail_cc_address INTO DATA(ls_mail_cc_address).
          lo_mail_cc = cl_cam_address_bcs=>create_internet_address( ls_mail_cc_address ).

*         Send immediately
          lo_send_request->set_send_immediately( i_send_immediately = abap_true ).

*         Set address
          lo_send_request->add_recipient( i_recipient = lo_mail_cc
                                          i_copy      = abap_true
                                          i_express   = abap_true ).
        ENDLOOP.

文本类型正文,i_type 类型可以是 'RAW','TXT' 等:

          lt_mail_body = ls_body_in-body_tline-tline.

*         Create mail body document object
          lo_document = cl_document_bcs=>create_document(
                        i_type    = ls_body_in-body_tline-type
                        i_text    = lt_mail_body
                        i_subject = iv_title ).

HTML类型正文,i_type 类型为 'HTM':

*         Convert string to solitab
          lt_mail_body = cl_bcs_convert=>string_to_soli(
            EXPORTING
              iv_string = ls_body_in-body_html-html
          ).

*         Create mail body document object
          lo_document = cl_document_bcs=>create_document(
                        i_type    = ls_body_in-body_html-type
                        i_text    = lt_mail_body
                        i_subject = iv_title ).

SE80创建的邮件模板内容动态替换:

*       Standard Template ->SE80->Email Template
        IF ls_body_in-body_template IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_tline,
            ls_body_in-body_html,
            ls_body_in-body_temp_smw0.

*         Build document object with template
          build_document_with_template(
            EXPORTING
              is_body_temp = ls_body_in-body_template
            IMPORTING
              eo_document = lo_document
              es_return   = es_return
          ).

          CHECK es_return-type <> gc_type_e.
        ENDIF.

SMW0邮件模板内容动态替换:

*       Template ->SMW0
        IF ls_body_in-body_temp_smw0 IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_tline,
            ls_body_in-body_html,
            ls_body_in-body_template.

*         Build document object with template
          build_document_with_temp_smw0(
            EXPORTING
              is_body_temp = ls_body_in-body_temp_smw0
            IMPORTING
              eo_document = lo_document
              es_return   = es_return
          ).

          CHECK es_return-type <> gc_type_e.
        ENDIF.

添加邮件附件:

*       Add attachment
        IF it_attachment IS NOT INITIAL.
          LOOP AT it_attachment INTO DATA(ls_attachment).
            lo_document->add_attachment( i_attachment_type    = ls_attachment-type
                                         i_attachment_subject = ls_attachment-att_name
                                         i_attachment_size    = ls_attachment-size
                                         i_att_content_hex    = ls_attachment-body_content ).
          ENDLOOP.
        ENDIF.

构建邮件主体及邮件发送:

*       Binding mail body
        lo_send_request->set_document( lo_document ).

*       Send mail
        lv_result = lo_send_request->send( i_with_error_screen = abap_true ).

获取邮件UUID,用于检索SOST中的状态:

*       Get UUID
        lv_oid = lo_send_request->oid( ).

根据UUID检索邮件状态,因为CL_BCS类只负责发起邮件传输请求,无法立刻获取邮件的状态信息,虽然有函数 SX_SNDREC_SELECT 可以获取SOST的列表信息,但是该函数不能抓取到具体某一条记录,所以直接从底表抓取。(SAP发送邮件只负责将邮件推送至邮件服务器,然后再由邮件服务器发给收件人,至于收件人有没有收到该邮件,只有邮件服务器知道,SAP并不会接收到该反馈,所以SOST中状态成功只表明邮件已成功推送至邮件服务器)

此处使用时间戳来替代wait up to ** seconds的写法,使其只需要等待他真正所需要的时间,不需要浪费任何零点几秒,或者零点零几秒。

        IF lv_result = abap_true.
          COMMIT WORK AND WAIT.

          GET TIME STAMP FIELD ls_time-start.

          WHILE ls_time-elapsed < ls_time-limit.
*           Get mail send status in SOST
            SELECT SINGLE
                   a~objtp,
                   a~objyr,
                   a~objno,
                   a~fortp,
                   a~foryr,
                   a~forno,
                   a~rectp,
                   a~recyr,
                   a~recno,
                   a~sndreq,
                   b~status,
                   b~msgid,
                   b~msgty,
                   b~msgv1,
                   b~msgv2,
                   b~msgv3,
                   b~msgv4
              INTO @DATA(ls_mail_status)
              FROM soos AS a
             INNER JOIN soes AS b
                ON a~rectp = b~rectp
               AND a~recyr = b~recyr
               AND a~recno = b~recno
             WHERE a~sndreq = @lv_oid.

            IF ls_mail_status-msgid IS NOT INITIAL.
              EXIT.
            ENDIF.

            GET TIME STAMP FIELD ls_time-now.

            ls_time-elapsed = cl_abap_tstmp=>subtract(
              tstmp1 = ls_time-now
              tstmp2 = ls_time-start
            ).
          ENDWHILE.

          IF ls_mail_status-status <> gc_success_status.
            es_return-type    = ls_mail_status-msgty.

            lv_msgno = ls_mail_status-status.

            CALL FUNCTION 'BAPI_MESSAGE_GETDETAIL'
              EXPORTING
                id         = ls_mail_status-msgid
                number     = lv_msgno
                textformat = gc_textformat
                message_v1 = ls_mail_status-msgv1
                message_v2 = ls_mail_status-msgv2
                message_v3 = ls_mail_status-msgv3
                message_v4 = ls_mail_status-msgv4
              IMPORTING
                message    = es_return-message.
          ELSE.
            es_return-type    = gc_type_s.
            es_return-message = 'Mail send success.'(002).
          ENDIF.
        ELSE.
          ROLLBACK WORK.
          es_return-type    = gc_type_e.
          es_return-message = 'Mail send failed, Please use tcode SOST to check detail.'(003).
        ENDIF.

具体实现细节可以阅读底部源码,下面只介绍其中一些功能的实现过程。

3.2邮件模板上传及调用:

SAP中目前我了解到的有以下三种方式来创建邮件模板:

3.2.1 SO10上传邮件模板

跟长文本一样的形式,通过READ_TEXT获取到长文本后,对某些变量进行替换,来构建正文内容,其实也可以直接维护一段html进去,在运行时替换到里面的某些标记字符,有些项目对邮件内容格式没有太多要求,且只有一些简单的文本内容时,会选择此方式进行邮件模板的维护。

在查阅相关资料时看到SO10似乎还支持上传一些具有富文本格式的RTF文件作为模板,配合READ_TEXT 和 CONVERT_ITF_TO_STREAM_TEXT 可以得到具有格式的邮件内容,不过我没有对此过多研究,具有复杂格式的邮件模板使用下面两种方式我觉得会更方便一些。

3.2.2 SMW0上传html模板

事先通过Vscode或者一些在线html编辑工具,构建好自己想要的效果的html文件,将其保存到本地,并通过SMW0上传,我这里用了一个在线网站去编写了html代码,因为可以即时生成预览画面,方便调整。

 

在模板中预留了一些占位符,在后续传值时会被程序传入的内容动态替换掉。


调用方式:

    key-objid = is_body_temp-id.

    IMPORT html TO lt_html_table FROM DATABASE wwwdata(ht) ID key.

    IF sy-subrc <> 0.
*     Object &1 does not exist in Web Repository
      MESSAGE s000(swww) WITH is_body_temp-id INTO es_return-message.
      es_return-type = gc_type_e.
      RETURN.
    ENDIF.

    lv_html_string = cl_bcs_convert=>txt_to_string( EXPORTING it_soli = lt_html_table ).

    LOOP AT is_body_temp-replace_info INTO DATA(ls_repace_info).
      REPLACE ALL OCCURRENCES OF ls_repace_info-mark_field
                              IN lv_html_string
                            WITH cl_bcs_convert=>txt_to_string( EXPORTING it_soli = ls_repace_info-body_html ).
    ENDLOOP.

    lt_html_table = cl_bcs_convert=>string_to_soli( EXPORTING iv_string = lv_html_string ).

    DATA(lo_multipart) = NEW cl_gbt_multirelated_service( ).

    lo_multipart->set_main_html(
      EXPORTING
        content = lt_html_table
    ).

先从 WWWDATA 表中取出html数据,转换为string后,根据传入的标记字段名mark_field去替换对应的内容,本来SAP提供了一个替换SMW0模板内容的函数 WWW_HTML_MERGER,但是该函数有个bug,由于他返回的html是CHAR255的表类型,而函数中替换逻辑是循环这个表去根据传入的内容进行替换,这就有可能会有两个问题:

问题1有可能解析出来模板里的标记字段刚好被分隔到了两行中,这样就无法检索到这个标记字段进行替换。

.......<!--Do
cument--> ......

问题2有可能我要替换的内容超过了255个长度,那么就会导致内容丢失。

<tr><td>Document</td>............<t

所以需要将html表转换为string类型后,再依次去替换内容。


3.2.3 SE80->Email Template创建邮件模板

以下是Email Template的一些特性:

1.可以关联CDS VIEW,使用CDS VIEW可以在调用时通过传入CDS KEY,来自动填充通过 {{}}包裹的字段变量,包括标题和正文,如上图中的{{banfn}},注意区分大小写,适合正文中只需要单条数据进行填充的邮件模板,因为框架源码中使用的是SELECT SINGLE来获取的CDS VIEW数据,此时代码中只需传入发件人,收件人,抄送人,CDS KEY即可生成邮件并发送,不需要额外代码。

2.支持多语言版本,调用时可以传入指定语言和默认语言,当指定语言版本的模板不存在时,会以默认语言版本生成邮件内容。 

3.可以直接进行内容预览,点击Preview按钮即可直接查看html预览画面,方便修正一些信息。

4.支持在右侧编辑区域构建html及纯文本格式的邮件内容,可以附加一些字体及样式等控制(最好使用内联方式指定样式,因为很多邮箱产品基于各种因素会对邮件内容进行截取,很多时候<body>标签之外的内容都会截取,所以style声明的一些样式控制在某些邮箱中可能不会生效)。

5.该应用在Fiori中比起SO10有更好的界面。


创建CDS:

普通CDS创建完成后填入邮件模板会报下面这个错误:

在CDS VIEW的属性中,进行发布后就可以消除这个提示:

创建Email Template内容:

除了手动编写,Vscode或者在线网站编写html外,还有一种方式也可以快速的生成html,借助word工具,将邮件需要内容填写好,包括字体样式颜色等,直接另存为.html格式,好处是借助这种方式生成的html的样式控制都是内联方式的,可以直接上传到邮件模板中去,不好的地方是,转换的html内容非常长,包含了一些无用信息。

同SMW0上传的模板一样,有些CDS VIEW不能获取的信息,html中仍需要留下标记字段,在代码中进行替换:

 


调用方式:

① 根据模板ID(SE80创建的模板名)获取模板对象实例。

② CDS KEY赋值,例:

namevalue
BANFN0010000129

③ 根据指定的模板语言及CDS KEY获取替换后内容的html内容及邮件标题。

④ 根据传入的替换信息,替换html模板中仍未填充的动态变量,例:

mark_fieldbody_html
<!--&APPROVER&-->MrMeng
<!--&TableContent&--><tr><td>物料A</td><td>12348523</td></tr>...

⑤ 将String类型html转换为类需要的类型。

⑥ 将最终完整的信息进行绑定。


3.3.模板中图片的替换

邮件正文中的图片可以有三种方式进行替换:

3.3.1 直接指定图片Base64编码

直接在src中指定图片的Base64编码,但是通常图片的Base64编码会非常长,会让你的html充满大量的字符,会显得很臃肿,如果某些图片是固定的,也可以使用这种方式去创建模板。

3.3.2 使用SMW0上传图片

需要注意的是,如果系统中没有分配图片类型对应的MIME TYPE,创建的时候需要注意,TYPE不能只填png,需要填写完整的类型名称 image/png,因为后续函数获取图片信息时,有一处硬编码,只填写png时会引发系统dump。

 获取图片信息:

    DATA:
      lt_query       TYPE STANDARD TABLE OF w3query,
      ls_query       TYPE w3query,
      lt_html        TYPE STANDARD TABLE OF w3html,
      lv_length      TYPE w3param-cont_len,
      lv_return_code TYPE w3param-ret_code.

    CHECK iv_smw0_name IS NOT INITIAL.

    ls_query-name  = gc_object_id.
    ls_query-value = iv_smw0_name.
    APPEND ls_query TO lt_query.

*   Get content from SMW0
*   This function is obsolete,MIME Repository is recommended
    CALL FUNCTION 'WWW_GET_MIME_OBJECT'
      TABLES
        query_string        = lt_query
        html                = lt_html
        mime                = et_solix
      CHANGING
        return_code         = lv_return_code
        content_type        = ev_type
        content_length      = lv_length
      EXCEPTIONS
        object_not_found    = 1
        parameter_not_found = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
*     Implement suitable error handling here
    ENDIF.

    ev_length = lv_length.

 Tips:该函数调用时会提示函数已弃用,所以不是很建议用这种方式。

替换模板中图片:

① 获取实例

② 将替换完毕的正文内容进行绑定

③ 获取图片信息

④ 绑定图片信息

⑤ 根据绑定了正文及图片信息的对象生成最终完整的邮件对象

3.3.3 使用SO2_MIME_REPOSITORY上传图片

使用事务代码 SO2_MIME_REPOSITORY 上传图片,或者从以下入口进入MIME Repository。

 

关于MIME Repository的更多信息,可以阅读Jerry老师的这篇文章。

SAP ABAP MIME Repository 和 API 介绍icon-default.png?t=N7T8https://blog.csdn.net/i042416/article/details/129785805?ops_request_misc=&request_id=c36bf275b8ae432e9b36e6ae3486f0d4&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~koosearch~default-1-129785805-null-null.268%5Ev1%5Econtrol&utm_term=MIME%20&spm=1018.2226.3001.4450 本例中我没有上传个人的图片,发现有现有的图片可以测试用,该图片在路径/SAP/PUBLIC下。

 获取图片信息:

    DATA:
      lo_mr_api  TYPE REF TO if_mr_api,
      lv_content TYPE xstring.

    CHECK iv_mime_path IS NOT INITIAL.

    lo_mr_api = cl_mime_repository_api=>get_api( ).

    lo_mr_api->get(
      EXPORTING
        i_url       = iv_mime_path
      IMPORTING
        e_content   = lv_content
        e_mime_type = ev_type
    ).

    et_solix = cl_bcs_convert=>xstring_to_solix( EXPORTING iv_xstring = lv_content ).

对于邮件中内容格式的各种转换,SAP提供了一个工具类,提供了丰富的内容格式转换方法,使用该工具类,基本可以完成使用过程中任意格式之间的转换。

替换模板中的图片:

3.4.Smartforms转PDF并添加为邮件附件

主要参数为以下三个参数:

no_dialog:       保证不显示弹窗

tdnewid:          设置创建假脱机请求

user_settings:置空,保证上面两个参数生效

调用CONVERT_OTFSPOOLJOB_2_PDF将打印池中的信息转换为PDF。

SAP标准参考程序:RSTXPDFT4。

 

3.4.1 PDF合并功能:

SAP提供了工具类CL_RSPO_PDF_MERGE,可以便捷的实现将多个PDF合并为同一个PDF。

SAP标准参考程序:RSPO_TEST_MERGE_PDF_FILES。

3.5.ALV转换为PDF并添加为邮件附件

主要问题点有以下三点:

PRINT = 'X' :保证ALV不显示,只作为后台打印。

GET_PRINT_PARAMETERS:通过设定好打印设备,格式化样式,不显示弹窗等参数,得到完整打印参数。

NEW-PAGE PRINT...: 保证打印时不会出现选打印设备的弹窗,不介意弹窗的可以不加这句代码,但是加了句代码会带来一个额外的问题,下面会说。

调用 CONVERT_ABAPSPOOLJOB_2_PDF 可以直接获取到 PDF 的 XSTRING 类型内容,后续可以自行选择是否删除打印池中的记录。

问题点

使用NEW-PAGE PRINT...带来的问题是,虽然弹窗没有了,但是调用ALV刷新方法时会引发系统dump。

原因是该语法之后调用ALV DISPLAY函数会产生一条新的屏幕堆栈记录,我没有详细追究其原理,只是确定了解决方式,在调用刷新之前,进行如下处理即可解决。

至此,一些特殊的问题点已补充完毕。下面是完整的框架源码及表结构信息。 


3.6.添加文件扩展名后缀为4位的附件,如xlsx附件

3.6.1添加本地上传的文件至邮件附件

BCS框架提供的文件扩展名是3位字符的,所以像xlsx,docx之类的内容将无法直接添附,如果需要添附4位扩展名的文件作为附件,需要使用关键字"&SO_FILENAME="来确定附件名称和类型。

更多信息可查阅note:1459896 - BCS:支持四位数文件扩展名 - SAP for Me

参考代码:

 

3.6.2将程序内表转换为xlsx内容并添加至附件 

核心方法是使用cl_salv_bs_lex=>export_from_result_data_table来进行内容格式转换,所需要的fieldcat也可以自己手动创建,这个有很多种方法,这里不做赘述。

3.7.框架源码及表结构信息:

 其他的系统标准结构在源码中都能看到。

CLASS zprbccl_send_mail DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CONSTANTS gc_type_e TYPE char1 VALUE 'E' ##NO_TEXT.
    CONSTANTS gc_type_s TYPE char1 VALUE 'S' ##NO_TEXT.
    CONSTANTS gc_state_a TYPE r3state VALUE 'A' ##NO_TEXT.
    CONSTANTS gc_object_id TYPE w3_qname VALUE '_OBJECT_ID' ##NO_TEXT.
    CONSTANTS gc_textformat TYPE bapi_tfrmt VALUE 'ASC' ##NO_TEXT.
    CONSTANTS gc_success_status TYPE so_rec_sta VALUE '073' ##NO_TEXT.
    CONSTANTS gc_command_r TYPE char1 VALUE 'R' ##NO_TEXT.

    CLASS-METHODS send_mail
      IMPORTING
        !iv_title             TYPE so_obj_des OPTIONAL
        !iv_mail_from_address TYPE ad_smtpadr
        !it_mail_to_address   TYPE zprbct_mail_address
        !it_mail_cc_address   TYPE zprbct_mail_address OPTIONAL
        !is_body              TYPE zprbcs_mail_body
        !it_attachment        TYPE zprbct_mail_attachment OPTIONAL
        !iv_commit_work       TYPE commitwork DEFAULT 'X'
      EXPORTING
        VALUE(es_return)      TYPE bapiret2 .
  PROTECTED SECTION.
  PRIVATE SECTION.

    CLASS-METHODS build_document_with_temp_smw0
      IMPORTING
        !is_body_temp TYPE zprbcs_mail_temp_smw0
      EXPORTING
        !es_return    TYPE bapiret2
        !eo_document  TYPE REF TO cl_document_bcs .
    CLASS-METHODS build_document_with_template
      IMPORTING
        !is_body_temp TYPE zprbcs_mail_template
      EXPORTING
        !es_return    TYPE bapiret2
        !eo_document  TYPE REF TO cl_document_bcs .
    CLASS-METHODS get_image_solix_smw0
      IMPORTING
        !iv_smw0_name TYPE w3objid
      EXPORTING
        !ev_type      TYPE w3conttype
        !et_solix     TYPE solix_tab
        !ev_length    TYPE so_obj_len .
    CLASS-METHODS get_image_solix_mime
      IMPORTING
        !iv_mime_path TYPE string
      EXPORTING
        !ev_type      TYPE w3conttype
        !ev_length    TYPE so_obj_len
        !et_solix     TYPE solix_tab .
ENDCLASS.



CLASS ZPRBCCL_SEND_MAIL IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZPRBCCL_SEND_MAIL=>BUILD_DOCUMENT_WITH_TEMPLATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IS_BODY_TEMP                   TYPE        ZPRBCS_MAIL_TEMPLATE
* | [<---] ES_RETURN                      TYPE        BAPIRET2
* | [<---] EO_DOCUMENT                    TYPE REF TO CL_DOCUMENT_BCS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD build_document_with_template.
    DATA:
      lo_email_api      TYPE REF TO if_smtg_email_api,
      lo_exception      TYPE REF TO cx_smtg_email_common,
      lv_subject        TYPE string,
      lv_title          TYPE so_obj_des,
      lv_body_html      TYPE string,
      lt_body_html_soli TYPE soli_tab,
      lt_image_solix    TYPE solix_tab,
      lv_image_type     TYPE w3conttype,
      lv_image_length   TYPE so_obj_len,
      lt_data_key       TYPE if_smtg_email_template=>ty_gt_data_key.

    DATA:
      lo_excep_smtg_email_common TYPE REF TO cx_smtg_email_common,
      lo_excep_document_bcs      TYPE REF TO cx_document_bcs,
      lo_excep_gbt_mime          TYPE REF TO cx_gbt_mime,
      lo_excep_bcom_mime         TYPE REF TO cx_bcom_mime.

    CHECK is_body_temp-id IS NOT INITIAL.

    TRY .
*       Get template object
        lo_email_api = cl_smtg_email_api=>get_instance( iv_template_id = is_body_temp-id  ).

        MOVE-CORRESPONDING is_body_temp-cds_key TO lt_data_key.

        TRY .
*           Get html body and replace parameters by cds key.
*           If a cds variable needs to be replaced, it should look like this {{BUKRS}}
            lo_email_api->render(
              EXPORTING
                iv_language = sy-langu
                it_data_key = lt_data_key
              IMPORTING
                ev_body_html = lv_body_html
                ev_subject   = lv_subject
            ).

            lv_title = lv_subject.

*           If the template include some content need to replace,
*           You should set the MARK_FIELD and BODY_HTML,
            LOOP AT is_body_temp-replace_info INTO DATA(ls_replace_info).
              REPLACE ls_replace_info-mark_field IN lv_body_html WITH ls_replace_info-body_html.
              REPLACE ls_replace_info-mark_field IN lv_title     WITH ls_replace_info-body_html.
            ENDLOOP.

            lt_body_html_soli = cl_bcs_convert=>string_to_soli( lv_body_html ).

            DATA(lo_multipart) = NEW cl_gbt_multirelated_service( ).

            lo_multipart->set_main_html(
              EXPORTING
                content     = lt_body_html_soli
            ).

*           If you want set some image,you must set value for 'CID',
*           you can only choose one parameter between 'SMW0_NAME' and 'MIME_PATH'.
            LOOP AT is_body_temp-image_info INTO DATA(ls_image_info).
              IF ls_image_info-cid IS INITIAL.
                CONTINUE.
              ENDIF.

              IF ls_image_info-smw0_name IS NOT INITIAL.
*               Get SMW0 object content
                get_image_solix_smw0(
                  EXPORTING
                    iv_smw0_name = ls_image_info-smw0_name
                  IMPORTING
                    et_solix  = lt_image_solix
                    ev_type   = lv_image_type
                    ev_length = lv_image_length
                ).

                lo_multipart->add_binary_part(
                  EXPORTING
                    content      = lt_image_solix
                    content_type = lv_image_type
                    length       = lv_image_length
                    content_id   = ls_image_info-cid
                ).
              ENDIF.

              IF ls_image_info-mime_path IS NOT INITIAL.
*               Get MIME object content
                get_image_solix_mime(
                  EXPORTING
                    iv_mime_path = ls_image_info-mime_path
                  IMPORTING
                    et_solix  = lt_image_solix
                    ev_type   = lv_image_type
                    ev_length = lv_image_length
                ).

*               Add image content
                lo_multipart->add_binary_part(
                  EXPORTING
                    content      = lt_image_solix
                    content_type = lv_image_type
                    length       = lv_image_length
                    content_id   = ls_image_info-cid
                ).
              ENDIF.

              CLEAR:
                lt_image_solix,
                lv_image_type,
                lv_image_length.
            ENDLOOP.

            TRY .
*               Generate email document object
                eo_document = cl_document_bcs=>create_from_multirelated(
                                                 EXPORTING
                                                   i_subject          = lv_title
                                                   i_multirel_service = lo_multipart ).
              CATCH cx_document_bcs INTO lo_excep_document_bcs.
                es_return-type    = gc_type_e.
                es_return-message = lo_excep_document_bcs->get_text( ).
                RETURN.
              CATCH cx_gbt_mime INTO lo_excep_gbt_mime.
                es_return-type    = gc_type_e.
                es_return-message = lo_excep_gbt_mime->get_text( ).
                RETURN.
              CATCH cx_bcom_mime INTO lo_excep_bcom_mime.
                es_return-type    = gc_type_e.
                es_return-message = lo_excep_bcom_mime->get_text( ).
                RETURN.
            ENDTRY.
          CATCH cx_smtg_email_common INTO lo_excep_smtg_email_common.
            es_return-type    = gc_type_e.
            es_return-message = lo_excep_smtg_email_common->get_text( ).
            RETURN.
        ENDTRY.
      CATCH cx_smtg_email_common INTO lo_excep_smtg_email_common.
        es_return-type    = gc_type_e.
        es_return-message = lo_excep_smtg_email_common->get_text( ).
        RETURN.
    ENDTRY.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZPRBCCL_SEND_MAIL=>GET_IMAGE_SOLIX_MIME
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_MIME_PATH                   TYPE        STRING
* | [<---] EV_TYPE                        TYPE        W3CONTTYPE
* | [<---] EV_LENGTH                      TYPE        SO_OBJ_LEN
* | [<---] ET_SOLIX                       TYPE        SOLIX_TAB
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_image_solix_mime.
    DATA:
      lo_mr_api  TYPE REF TO if_mr_api,
      lv_content TYPE xstring.

    CHECK iv_mime_path IS NOT INITIAL.

    lo_mr_api = cl_mime_repository_api=>get_api( ).

    lo_mr_api->get(
      EXPORTING
        i_url       = iv_mime_path
      IMPORTING
        e_content   = lv_content
        e_mime_type = ev_type
    ).

    et_solix = cl_bcs_convert=>xstring_to_solix( EXPORTING iv_xstring = lv_content ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZPRBCCL_SEND_MAIL=>GET_IMAGE_SOLIX_SMW0
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_SMW0_NAME                   TYPE        W3OBJID
* | [<---] EV_TYPE                        TYPE        W3CONTTYPE
* | [<---] ET_SOLIX                       TYPE        SOLIX_TAB
* | [<---] EV_LENGTH                      TYPE        SO_OBJ_LEN
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_image_solix_smw0.
    DATA:
      lt_query       TYPE STANDARD TABLE OF w3query,
      ls_query       TYPE w3query,
      lt_html        TYPE STANDARD TABLE OF w3html,
      lv_length      TYPE w3param-cont_len,
      lv_return_code TYPE w3param-ret_code.

    CHECK iv_smw0_name IS NOT INITIAL.

    ls_query-name  = gc_object_id.
    ls_query-value = iv_smw0_name.
    APPEND ls_query TO lt_query.

*   Get content from SMW0
*   This function is obsolete,MIME Repository is recommended
    CALL FUNCTION 'WWW_GET_MIME_OBJECT'
      TABLES
        query_string        = lt_query
        html                = lt_html
        mime                = et_solix
      CHANGING
        return_code         = lv_return_code
        content_type        = ev_type
        content_length      = lv_length
      EXCEPTIONS
        object_not_found    = 1
        parameter_not_found = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
*     Implement suitable error handling here
    ENDIF.

    ev_length = lv_length.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZPRBCCL_SEND_MAIL=>SEND_MAIL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_TITLE                       TYPE        SO_OBJ_DES(optional)
* | [--->] IV_MAIL_FROM_ADDRESS           TYPE        AD_SMTPADR
* | [--->] IT_MAIL_TO_ADDRESS             TYPE        ZPRBCT_MAIL_ADDRESS
* | [--->] IT_MAIL_CC_ADDRESS             TYPE        ZPRBCT_MAIL_ADDRESS(optional)
* | [--->] IS_BODY                        TYPE        ZPRBCS_MAIL_BODY
* | [--->] IT_ATTACHMENT                  TYPE        ZPRBCT_MAIL_ATTACHMENT(optional)
* | [--->] IV_COMMIT_WORK                 TYPE        COMMITWORK (default ='X')
* | [<---] ES_RETURN                      TYPE        BAPIRET2
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD send_mail.
    DATA:
      lo_send_request  TYPE REF TO cl_bcs,
      lo_mail_from     TYPE REF TO cl_cam_address_bcs,
      lo_mail_to       TYPE REF TO cl_cam_address_bcs,
      lo_mail_cc       TYPE REF TO cl_cam_address_bcs,
      lt_mail_body     TYPE soli_tab,
      lt_attc_body     TYPE solix_tab,
      ls_body_in       TYPE zprbcs_mail_body,
      lo_document      TYPE REF TO cl_document_bcs,
      lv_result        TYPE os_boolean,
      lo_bcs_exception TYPE REF TO cx_root,
      lv_oid           TYPE sysuuid_x,
      lv_msgno         TYPE symsgno,
      lt_att_head      TYPE soli_tab,
      lv_text_line     TYPE soli,
      lv_filename      TYPE string.

    DATA:
      BEGIN OF ls_time,
        start   TYPE timestampl,                                        "Start time
        now     TYPE timestampl,                                        "End time
        elapsed TYPE tzntstmpl,                                         "Elapsed time
        limit   TYPE tzntstmpl VALUE 3,                                 "Max seconds
      END OF ls_time.

    CLEAR es_return.

    TRY .
*       create instance of CL_BCS
        lo_send_request = cl_bcs=>create_persistent( ).

*       Set sender email address
        lo_mail_from = cl_cam_address_bcs=>create_internet_address( iv_mail_from_address ).
        lo_send_request->set_sender( lo_mail_from ).

*       Set receiver email address
        LOOP AT it_mail_to_address INTO DATA(ls_mail_to_address).
          IF ls_mail_to_address IS INITIAL.
            es_return-type    = gc_type_e.
            es_return-message = 'The email address cannot be empty.'(001).
            RETURN.
          ENDIF.
          lo_mail_to = cl_cam_address_bcs=>create_internet_address( ls_mail_to_address ).

*         Send immediately
          lo_send_request->set_send_immediately( i_send_immediately = abap_true ).

*         Set address
          lo_send_request->add_recipient( i_recipient = lo_mail_to
                                          i_express   = abap_true ).
        ENDLOOP.

*       Set CC email address
        LOOP AT it_mail_cc_address INTO DATA(ls_mail_cc_address).
          IF ls_mail_to_address IS INITIAL.
            es_return-type    = gc_type_e.
            es_return-message = 'The email address cannot be empty.'(001).
            RETURN.
          ENDIF.
          lo_mail_cc = cl_cam_address_bcs=>create_internet_address( ls_mail_cc_address ).

*         Send immediately
          lo_send_request->set_send_immediately( i_send_immediately = abap_true ).

*         Set address
          lo_send_request->add_recipient( i_recipient = lo_mail_cc
                                          i_copy      = abap_true
                                          i_express   = abap_true ).
        ENDLOOP.

        ls_body_in = is_body.

*       Text body
        IF ls_body_in-body_tline IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_html,
            ls_body_in-body_template,
            ls_body_in-body_temp_smw0.

          lt_mail_body = ls_body_in-body_tline-tline.

*         Create mail body document object
          lo_document = cl_document_bcs=>create_document(
                        i_type    = ls_body_in-body_tline-type
                        i_text    = lt_mail_body
                        i_subject = iv_title ).
        ENDIF.

*       HTML body
        IF ls_body_in-body_html IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_tline,
            ls_body_in-body_template,
            ls_body_in-body_temp_smw0.

*         Convert string to solitab
          lt_mail_body = cl_bcs_convert=>string_to_soli(
            EXPORTING
              iv_string = ls_body_in-body_html-html
          ).

*         Create mail body document object
          lo_document = cl_document_bcs=>create_document(
                        i_type    = ls_body_in-body_html-type
                        i_text    = lt_mail_body
                        i_subject = iv_title ).
        ENDIF.

*       Standard Template ->SE80->Email Template
        IF ls_body_in-body_template IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_tline,
            ls_body_in-body_html,
            ls_body_in-body_temp_smw0.

*         Build document object with template
          build_document_with_template(
            EXPORTING
              is_body_temp = ls_body_in-body_template
            IMPORTING
              eo_document = lo_document
              es_return   = es_return
          ).

          CHECK es_return-type <> gc_type_e.
        ENDIF.

*       Template ->SMW0
        IF ls_body_in-body_temp_smw0 IS NOT INITIAL.
          CLEAR:
            ls_body_in-body_tline,
            ls_body_in-body_html,
            ls_body_in-body_template.

*         Build document object with template
          build_document_with_temp_smw0(
            EXPORTING
              is_body_temp = ls_body_in-body_temp_smw0
            IMPORTING
              eo_document = lo_document
              es_return   = es_return
          ).

          CHECK es_return-type <> gc_type_e.
        ENDIF.

*       Add attachment
        IF it_attachment IS NOT INITIAL.
          LOOP AT it_attachment INTO DATA(ls_attachment).
            lv_filename = ls_attachment-att_name.
            CONCATENATE '&SO_FILENAME=' lv_filename INTO lv_text_line.
            APPEND lv_text_line TO lt_att_head.

            lo_document->add_attachment( i_attachment_type    = ls_attachment-type
                                         i_attachment_subject = ls_attachment-att_name
                                         i_attachment_size    = ls_attachment-size
                                         i_att_content_hex    = ls_attachment-body_content
                                         i_attachment_header  = lt_att_head ).
            CLEAR:
              lv_filename,
              lv_text_line,
              lt_att_head.
          ENDLOOP.
        ENDIF.

*       Binding mail body
        lo_send_request->set_document( lo_document ).

*       Send mail
        lv_result = lo_send_request->send( i_with_error_screen = abap_true ).

*       Get UUID
        lv_oid = lo_send_request->oid( ).


        IF lv_result = abap_true.
          IF iv_commit_work = abap_true.
            COMMIT WORK AND WAIT.

            GET TIME STAMP FIELD ls_time-start.

            WHILE ls_time-elapsed < ls_time-limit.
*           Get mail send status in SOST
              SELECT SINGLE
                     a~objtp,
                     a~objyr,
                     a~objno,
                     a~fortp,
                     a~foryr,
                     a~forno,
                     a~rectp,
                     a~recyr,
                     a~recno,
                     a~sndreq,
                     b~status,
                     b~msgid,
                     b~msgty,
                     b~msgv1,
                     b~msgv2,
                     b~msgv3,
                     b~msgv4
                INTO @DATA(ls_mail_status)
                FROM soos AS a
               INNER JOIN soes AS b
                  ON a~rectp = b~rectp
                 AND a~recyr = b~recyr
                 AND a~recno = b~recno
               WHERE a~sndreq = @lv_oid.

              IF ls_mail_status-msgid IS NOT INITIAL.
                EXIT.
              ENDIF.

              GET TIME STAMP FIELD ls_time-now.

              ls_time-elapsed = cl_abap_tstmp=>subtract(
                tstmp1 = ls_time-now
                tstmp2 = ls_time-start
              ).
            ENDWHILE.

            IF ls_mail_status-status <> gc_success_status.
              es_return-type    = ls_mail_status-msgty.

              lv_msgno = ls_mail_status-status.

              CALL FUNCTION 'BAPI_MESSAGE_GETDETAIL'
                EXPORTING
                  id         = ls_mail_status-msgid
                  number     = lv_msgno
                  textformat = gc_textformat
                  message_v1 = ls_mail_status-msgv1
                  message_v2 = ls_mail_status-msgv2
                  message_v3 = ls_mail_status-msgv3
                  message_v4 = ls_mail_status-msgv4
                IMPORTING
                  message    = es_return-message.
            ELSE.
              es_return-type    = gc_type_s.
              es_return-message = 'Mail send success.'(002).
            ENDIF.
          ELSE.
            es_return-type    = gc_type_s.
            es_return-message = 'Mail send success.'(002).
          ENDIF.
        ELSE.
          IF iv_commit_work = abap_true.
            ROLLBACK WORK.
          ENDIF.

          es_return-type    = gc_type_e.
          es_return-message = 'Mail send failed, Please use tcode SOST to check detail.'(003).
        ENDIF.
      CATCH cx_bcs INTO lo_bcs_exception.
        es_return-type    = gc_type_e.
        es_return-message = lo_bcs_exception->get_text( ).
    ENDTRY.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZPRBCCL_SEND_MAIL=>BUILD_DOCUMENT_WITH_TEMP_SMW0
* +-------------------------------------------------------------------------------------------------+
* | [--->] IS_BODY_TEMP                   TYPE        ZPRBCS_MAIL_TEMP_SMW0
* | [<---] ES_RETURN                      TYPE        BAPIRET2
* | [<---] EO_DOCUMENT                    TYPE REF TO CL_DOCUMENT_BCS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD build_document_with_temp_smw0.
    DATA:
      lt_html_table   TYPE swww_t_html_table,
      lv_html_string  TYPE string,
      lt_merge_table  TYPE swww_t_merge_table,
      ls_merge_table  TYPE swww_t_merge_item,
      lt_image_solix  TYPE solix_tab,
      lv_image_type   TYPE w3conttype,
      lv_image_length TYPE so_obj_len.

    DATA:
      key TYPE wwwdataid.

    DATA:
      lo_excep_smtg_email_common TYPE REF TO cx_smtg_email_common,
      lo_excep_document_bcs      TYPE REF TO cx_document_bcs,
      lo_excep_gbt_mime          TYPE REF TO cx_gbt_mime,
      lo_excep_bcom_mime         TYPE REF TO cx_bcom_mime.

    CHECK is_body_temp-id IS NOT INITIAL.

*   Set replace body
*    LOOP AT is_body_temp-replace_info INTO DATA(ls_repace_info).
*      ls_merge_table-name    = ls_repace_info-mark_field.
*      ls_merge_table-command = gc_command_r.
*      ls_merge_table-html[]  = ls_repace_info-body_html.
*      APPEND ls_merge_table TO lt_merge_table.
*      CLEAR ls_merge_table.
*    ENDLOOP.

*   Replace html body
*    CALL FUNCTION 'WWW_HTML_MERGER'
*      EXPORTING
*        template           = is_body_temp-id
**       MERGE_TEXTPOOL     =
**       TEMPLATE_TABLE     =
*      IMPORTING
*        html_table         = lt_html_table
*      CHANGING
*        merge_table        = lt_merge_table
*      EXCEPTIONS
*        template_not_found = 1
*        OTHERS             = 2.

    key-objid = is_body_temp-id.

    IMPORT html TO lt_html_table FROM DATABASE wwwdata(ht) ID key.

    IF sy-subrc <> 0.
*     Object &1 does not exist in Web Repository
      MESSAGE s000(swww) WITH is_body_temp-id INTO es_return-message.
      es_return-type = gc_type_e.
      RETURN.
    ENDIF.

    lv_html_string = cl_bcs_convert=>txt_to_string( EXPORTING it_soli = lt_html_table ).

    LOOP AT is_body_temp-replace_info INTO DATA(ls_repace_info).
      REPLACE ALL OCCURRENCES OF ls_repace_info-mark_field
                              IN lv_html_string
                            WITH cl_bcs_convert=>txt_to_string( EXPORTING it_soli = ls_repace_info-body_html ).
    ENDLOOP.

    lt_html_table = cl_bcs_convert=>string_to_soli( EXPORTING iv_string = lv_html_string ).

    DATA(lo_multipart) = NEW cl_gbt_multirelated_service( ).

    lo_multipart->set_main_html(
      EXPORTING
        content = lt_html_table
    ).

*   If you want set some image,you must set value for 'CID',
*   you can only choose one parameter between 'SMW0_NAME' and 'MIME_PATH'.
    LOOP AT is_body_temp-image_info INTO DATA(ls_image_info).
      IF ls_image_info-cid IS INITIAL.
        CONTINUE.
      ENDIF.

      IF ls_image_info-smw0_name IS NOT INITIAL.
*       Get SMW0 object content
        get_image_solix_smw0(
          EXPORTING
            iv_smw0_name = ls_image_info-smw0_name
          IMPORTING
            et_solix  = lt_image_solix
            ev_type   = lv_image_type
            ev_length = lv_image_length
        ).

        lo_multipart->add_binary_part(
          EXPORTING
            content      = lt_image_solix
            content_type = lv_image_type
            length       = lv_image_length
            content_id   = ls_image_info-cid
        ).
      ENDIF.

      IF ls_image_info-mime_path IS NOT INITIAL.
*       Get MIME object content
        get_image_solix_mime(
          EXPORTING
            iv_mime_path = ls_image_info-mime_path
          IMPORTING
            et_solix  = lt_image_solix
            ev_type   = lv_image_type
            ev_length = lv_image_length
        ).

*       Add image content
        lo_multipart->add_binary_part(
          EXPORTING
            content      = lt_image_solix
            content_type = lv_image_type
            length       = lv_image_length
            content_id   = ls_image_info-cid
        ).
      ENDIF.

      CLEAR:
        lt_image_solix,
        lv_image_type,
        lv_image_length.
    ENDLOOP.

    TRY .
*       Generate email document object
        eo_document = cl_document_bcs=>create_from_multirelated(
                                         EXPORTING
                                           i_subject          = is_body_temp-title
                                           i_multirel_service = lo_multipart ).
      CATCH cx_document_bcs INTO lo_excep_document_bcs.
        es_return-type    = gc_type_e.
        es_return-message = lo_excep_document_bcs->get_text( ).
        RETURN.
      CATCH cx_gbt_mime INTO lo_excep_gbt_mime.
        es_return-type    = gc_type_e.
        es_return-message = lo_excep_gbt_mime->get_text( ).
        RETURN.
      CATCH cx_bcom_mime INTO lo_excep_bcom_mime.
        es_return-type    = gc_type_e.
        es_return-message = lo_excep_bcom_mime->get_text( ).
        RETURN.
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

3.8.SE38 Demo程序源码:

CDS VIEW可自行换成自己需要的CDS VIEW名称

*&---------------------------------------------------------------------*
*& Report ZTEST_SEND_MAIL
*&---------------------------------------------------------------------*
*& Author: DeveloperMrMeng
*& Date:   2023/07/16
*&---------------------------------------------------------------------*
*& The sample program includes the following functions:
*& 1. send mail with txt body
*& 2. send mail with html body(use abap build body)
*& 3. send mail with template (SE80->create email template)
*&    3.1  replace fields with cds
*& 4. send mail with template (SMW0)
*& 5. add image with SMW0
*& 6. add image with SO2_MIME_REPOSITORY
*& 7. add attchment
*&    7.1  add .txt file
*&    7.2  add .csv file
*&    7.3  add .xlsx file
*&    7.4  add .pdf from smartforms
*&         7.4.1  Mergae PDF
*&    7.4  add .pdf from alv
*&---------------------------------------------------------------------*
REPORT ztest_send_mail.
TABLES:eban.

TYPES:
  ty_alv TYPE zstest_send_mail,
  tt_alv TYPE STANDARD TABLE OF ty_alv.

DATA:
  gt_alv    TYPE tt_alv,
  gs_alv    TYPE ty_alv,
  gt_sf_alv TYPE tt_alv.

DATA:
  go_alv_grid TYPE REF TO cl_gui_alv_grid,
  gt_fieldcat TYPE lvc_t_fcat,
  gs_layout   TYPE lvc_s_layo.

CONSTANTS:
  gc_temp_smw0 TYPE w3objid VALUE 'ZTEST_TEMP_SMW0'.

SELECT-OPTIONS:s_banfn FOR eban-banfn.

START-OF-SELECTION.

  PERFORM frm_get_data.

  PERFORM frm_show_alv.
*&---------------------------------------------------------------------*
*& Form frm_get_data
*&---------------------------------------------------------------------*
*& Get data
*&---------------------------------------------------------------------*
FORM frm_get_data .
* Get relevant data
  SELECT a~banfn,                                                       "Purchase Requisition Number
         a~bnfpo,                                                       "Item number of purchase requisition
         a~bsart,                                                       "Order Type (Purchasing)
         a~frgst,                                                       "Release strategy in the purchase requisition
         a~frggr,                                                       "Release group
         a~zrelcode_next,                                               "Release code(Next)
         b~approver,                                                    "Approver
         b~email,                                                       "Approver’s Email
         a~ekgrp,                                                       "Purchasing Group
         a~werks,                                                       "Plant
         a~ernam,                                                       "Name of Person who Created the Object
         a~afnam,                                                       "Name of requisitioner/requester
         a~matnr,                                                       "Material Number
         a~txz01,                                                       "Short Text
         a~menge,                                                       "Quantity
         a~meins,                                                       "Base Unit of Measure
         a~value_item,                                                  "Total value at time of release
         a~frgdt,                                                       "Purchase Requisition Release Date
         a~lfdat,                                                       "Delivery date
         a~webaz,                                                       "Goods receipt processing time in days
         a~matkl,                                                       "Material Group
         a~dispo,                                                       "MRP Controller
         a~lifnr                                                        "Account Number of Vendor or Creditor
    FROM zprmmt_relstat_pr AS a
   INNER JOIN zprmmtapprinfo AS b
      ON a~frggr = b~frggr
*     AND a~frgst = b~frgst
     AND a~zrelcode_next = b~frgco
   WHERE a~banfn IN @s_banfn
     AND b~email IS NOT INITIAL
     AND b~approver IS NOT INITIAL
    INTO TABLE @DATA(lt_data).

  IF lt_data IS INITIAL.
    MESSAGE 'No data' TYPE 'S'.
    LEAVE LIST-PROCESSING.
  ENDIF.

  SORT lt_data BY banfn ASCENDING
                  bnfpo ASCENDING.

  LOOP AT lt_data INTO DATA(ls_data).
    gs_alv-banfn      = ls_data-banfn.                                  "Purchase Requisition Number
    gs_alv-bnfpo      = ls_data-bnfpo.                                  "Item number of purchase requisition
    gs_alv-bsart      = ls_data-bsart.                                  "Order Type (Purchasing)
    gs_alv-frgst      = ls_data-frgst.                                  "Release strategy in the purchase requisition
    gs_alv-frggr      = ls_data-frggr.                                  "Release group
    gs_alv-frgco      = ls_data-zrelcode_next.                          "Release code(Next)
    gs_alv-approver   = ls_data-approver.                               "Approver
    gs_alv-email      = ls_data-email.                                  "Approver’s Email
    gs_alv-ekgrp      = ls_data-ekgrp.                                  "Purchasing Group
    gs_alv-werks      = ls_data-werks.                                  "Plant
    gs_alv-ernam      = ls_data-ernam.                                  "Name of Person who Created the Object
    gs_alv-afnam      = ls_data-afnam.                                  "Name of requisitioner/requester
    gs_alv-matnr      = ls_data-matnr.                                  "Material Number
    gs_alv-txz01      = ls_data-txz01.                                  "Short Text
    gs_alv-menge      = ls_data-menge.                                  "Quantity
    gs_alv-meins      = ls_data-meins.                                  "Base Unit of Measure
    gs_alv-value_item = ls_data-value_item.                             "Total value at time of release
    gs_alv-frgdt      = ls_data-frgdt.                                  "Purchase Requisition Release Date
    gs_alv-lfdat      = ls_data-lfdat.                                  "Delivery date
    gs_alv-webaz      = ls_data-webaz.                                  "Goods receipt processing time in days
    gs_alv-matkl      = ls_data-matkl.                                  "Material Group
    gs_alv-dispo      = ls_data-dispo.                                  "MRP Controller
    gs_alv-lifnr      = ls_data-lifnr.                                  "Account Number of Vendor or Creditor

    APPEND gs_alv TO gt_alv.
    CLEAR gs_alv.
  ENDLOOP.

  SORT gt_alv BY banfn ASCENDING
                 bnfpo ASCENDING
                 email ASCENDING.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_show_alv
*&---------------------------------------------------------------------*
*& Show ALV
*&---------------------------------------------------------------------*
FORM frm_show_alv .
* Set layout
  gs_layout-zebra      = 'X'.
  gs_layout-cwidth_opt = 'X'.
  gs_layout-box_fname  = 'CBOX'.
  gs_layout-sel_mode   = 'D'.

* Get fieldcat
  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE' ##FM_SUBRC_OK
    EXPORTING
      i_structure_name       = 'ZSTEST_SEND_MAIL'
      i_bypassing_buffer     = abap_true
    CHANGING
      ct_fieldcat            = gt_fieldcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.

* Hide checkbox
  READ TABLE gt_fieldcat ASSIGNING FIELD-SYMBOL(<fs_fieldcat>)
    WITH KEY fieldname = 'CBOX'.
  IF sy-subrc = 0.
    <fs_fieldcat>-no_out = 'X'.
    <fs_fieldcat>-tech   = 'X'.
  ENDIF.

* ALV display
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program       = syst-repid
      it_fieldcat_lvc          = gt_fieldcat
      i_callback_user_command  = 'FRM_USER_COMMAND'
      i_callback_pf_status_set = 'FRM_PF_STATUS_SET'
      is_layout_lvc            = gs_layout
      i_save                   = 'A'
    TABLES
      t_outtab                 = gt_alv
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_pf_status_set
*&---------------------------------------------------------------------*
*& Set status
*&---------------------------------------------------------------------*
FORM frm_pf_status_set USING rt_extab TYPE slis_t_extab.
  SET PF-STATUS 'STATUS'." EXCLUDING RT_EXTAB.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_user_command
*&---------------------------------------------------------------------*
*& Process user command
*&---------------------------------------------------------------------*
FORM frm_user_command USING r_ucomm LIKE sy-ucomm
                            rs_selfield TYPE slis_selfield.
  DATA:
    lo_grid   TYPE REF TO cl_gui_alv_grid,
    ls_stable TYPE lvc_s_stbl,
    ls_layout TYPE lvc_s_layo.

  DATA:
    lo_control TYPE REF TO cl_gui_control,
    lt_control TYPE cnto_control_list.

  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = lo_grid.

  CASE r_ucomm.
*   Send mail
    WHEN 'SEND'.
*     Send test email
      PERFORM frm_send_test_email.
    WHEN OTHERS.
  ENDCASE.

************************************************************************
* If you use NEW-PAGE to process ALV->PDF,you need to delete the subscriber index 1.
  cl_gui_cfw=>get_subscriber_by_id(
    EXPORTING
      shellid = 0
    IMPORTING
      subscriber = lo_control
    EXCEPTIONS
      cntl_error = 1
  ).

  IF lo_control IS NOT INITIAL.
    cl_gui_cfw=>unsubscribe( EXPORTING ref = lo_control ).
  ENDIF.
************************************************************************

  CALL METHOD lo_grid->get_frontend_layout
    IMPORTING
      es_layout = ls_layout.

  ls_layout-cwidth_opt = 'X'.

* Set Optimize column width
  CALL METHOD lo_grid->set_frontend_layout
    EXPORTING
      is_layout = ls_layout.

  ls_stable-row = 'X'.
  ls_stable-col = 'X'.

* Refresh ALV
  CALL METHOD lo_grid->refresh_table_display
    EXPORTING
      is_stable = ls_stable
    EXCEPTIONS
      finished  = 1
      OTHERS    = 2.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_send_test_email
*&---------------------------------------------------------------------*
*& Send test email
*&---------------------------------------------------------------------*
FORM frm_send_test_email .
  DATA:
    lt_alv_mail TYPE tt_alv,
    ls_alv_mail TYPE ty_alv.

* Email parameters
  DATA:
    lv_message         TYPE string,
    lv_html_string     TYPE string,
    ls_body            TYPE zprbcs_mail_body,
    lt_mail_to_address TYPE zprbct_mail_address,
    ls_mail_to_address TYPE ad_smtpadr,
    ls_mail_template   TYPE zprbcs_mail_template,
    ls_mail_temp_smw0  TYPE zprbcs_mail_temp_smw0,
    lt_cds_key         TYPE zprbct_mail_cds_key_value,
    ls_cds_key         TYPE zprbcs_mail_cds_key_value,
    lt_temp_replace    TYPE zprbct_mail_temp_replace,
    ls_temp_replace    TYPE zprbcs_mail_temp_replace,
    lt_temp_rep_smw0   TYPE zprbct_mail_temp_smw0_replace,
    ls_temp_rep_smw0   TYPE zprbcs_mail_temp_smw0_replace,
    lt_body_html_smw0  TYPE w3html_tab,
    ls_body_html_smw0  TYPE w3html,
    lv_html_str_smw0   TYPE string,
    lv_approver        TYPE string,
    lt_images          TYPE zprbct_mail_temp_img,
    ls_images          TYPE zprbcs_mail_temp_img,
    lt_attch           TYPE zprbct_mail_attachment,
    ls_attch           TYPE zprbcs_mail_attachment,
    ls_return          TYPE bapiret2.

  DATA:
    lo_bcs TYPE REF TO cx_bcs.

  DATA:
    lv_test_file TYPE string VALUE 'C:\Users\MrMeng\Desktop\EXPORT1.XLSX',
    lv_file_len  TYPE i,
    lt_solix_tab TYPE solix_tab.

  lt_alv_mail = gt_alv.
  DELETE lt_alv_mail WHERE cbox IS INITIAL.

  CHECK lt_alv_mail IS NOT INITIAL.

  SORT lt_alv_mail BY banfn ASCENDING
                      bnfpo ASCENDING
                      email ASCENDING.

  LOOP AT lt_alv_mail INTO ls_alv_mail
    GROUP BY ( banfn = ls_alv_mail-banfn
               email = ls_alv_mail-email ) ASCENDING
    REFERENCE INTO DATA(lo_mail_data).

    CLEAR gt_sf_alv.

    LOOP AT GROUP lo_mail_data ASSIGNING FIELD-SYMBOL(<fs_mail_data>).
**********************************************************************
*     Build html replace info ->SE80->Email template
**********************************************************************
*     Set CDS Key
      ls_cds_key-value = <fs_mail_data>-banfn.

*     Set approver
      lv_approver = <fs_mail_data>-approver.

*     Set receiver address
      ls_mail_to_address = <fs_mail_data>-email.

*     Dynamic HTML body: <tr/><td/>
      lv_html_string = lv_html_string &&
                       '<tr>' &&
                          '<td>' && <fs_mail_data>-banfn &&      '</td>' &&
                          '<td>' && <fs_mail_data>-bnfpo &&      '</td>' &&
                          '<td>' && <fs_mail_data>-bsart &&      '</td>' &&
                          '<td>' && <fs_mail_data>-frggr &&      '</td>' &&
                          '<td>' && <fs_mail_data>-frgst &&      '</td>' &&
                          '<td>' && <fs_mail_data>-frgco &&      '</td>' &&
                          '<td>' && <fs_mail_data>-ekgrp &&      '</td>' &&
                          '<td>' && <fs_mail_data>-werks &&      '</td>' &&
                          '<td>' && <fs_mail_data>-ernam &&      '</td>' &&
                          '<td>' && <fs_mail_data>-afnam &&      '</td>' &&
                          '<td>' && <fs_mail_data>-matnr &&      '</td>' &&
                          '<td>' && <fs_mail_data>-txz01 &&      '</td>' &&
                          '<td>' && <fs_mail_data>-menge &&      '</td>' &&
                          '<td>' && <fs_mail_data>-meins &&      '</td>' &&
                          '<td>' && <fs_mail_data>-value_item && '</td>' &&
                          '<td>' && <fs_mail_data>-frgdt &&      '</td>' &&
                          '<td>' && <fs_mail_data>-lfdat &&      '</td>' &&
                          '<td>' && <fs_mail_data>-webaz &&      '</td>' &&
                          '<td>' && <fs_mail_data>-matkl &&      '</td>' &&
                          '<td>' && <fs_mail_data>-dispo &&      '</td>' &&
                          '<td>' && <fs_mail_data>-lifnr &&      '</td>' &&
                       '</tr>'.
      APPEND <fs_mail_data> TO gt_sf_alv.
    ENDLOOP.

*   Set template replace content --Approver
    ls_temp_replace-mark_field = '<!--&APPROVER&-->'.
    ls_temp_replace-body_html  = lv_approver.
    APPEND ls_temp_replace TO lt_temp_replace.

*   Set template replace content --Table
    ls_temp_replace-mark_field = '<!--&TableContent&-->'.
    ls_temp_replace-body_html  = lv_html_string.
    APPEND ls_temp_replace TO lt_temp_replace.

*   Set template replace content --System Date
    ls_temp_replace-mark_field = '<!--&SystemDate&-->'.
    ls_temp_replace-body_html  = sy-datlo.
    APPEND ls_temp_replace TO lt_temp_replace.

    SORT lt_temp_replace BY mark_field ASCENDING.
    DELETE ADJACENT DUPLICATES FROM lt_temp_replace COMPARING mark_field.

*   CDS Key
    ls_cds_key-name = 'BANFN'.
    APPEND ls_cds_key TO lt_cds_key.

**********************************************************************
*   Build html replace info ->SMW0
**********************************************************************
    ls_temp_rep_smw0-mark_field = '<!--&DocNumber&-->'.

    ls_body_html_smw0-line = <fs_mail_data>-banfn.
    APPEND ls_body_html_smw0 TO lt_body_html_smw0.

    ls_temp_rep_smw0-body_html = lt_body_html_smw0.
    APPEND ls_temp_rep_smw0 TO lt_temp_rep_smw0.

    ls_temp_rep_smw0-mark_field = '<!--&TableContent&-->'.
    ls_temp_rep_smw0-body_html = cl_bcs_convert=>string_to_soli( EXPORTING iv_string = lv_html_string ).
    APPEND ls_temp_rep_smw0 TO lt_temp_rep_smw0.

**********************************************************************
*   Email Address info
**********************************************************************
    APPEND ls_mail_to_address TO lt_mail_to_address.
    SORT lt_mail_to_address ASCENDING.

    DELETE ADJACENT DUPLICATES FROM lt_mail_to_address COMPARING ALL FIELDS.

**********************************************************************
*   Email Image with SMW0
**********************************************************************
    ls_images-cid       = 'SAP_LOGO_SMW0'.
    ls_images-smw0_name = 'ZSAP_LOGO'.
    APPEND ls_images TO lt_images.
    CLEAR ls_images.

**********************************************************************
*   Email Image with SO2_MIME_REPOSITORY
**********************************************************************
    ls_images-cid       = 'SAP_LOGO_MIME'.
    ls_images-mime_path = '/SAP/PUBLIC/SAPLOGO_TR.bmp'.
    APPEND ls_images TO lt_images.
    CLEAR ls_images.

**********************************************************************
*   Email Attchment - txt
**********************************************************************
    ls_attch-type     = 'TXT'.
    ls_attch-att_name = 'TestTXT.txt'.

    TRY .
        cl_bcs_convert=>string_to_solix(
          EXPORTING
            iv_string = 'Hello word'
          IMPORTING
            et_solix = ls_attch-body_content
            ev_size  = ls_attch-size
        ).

        APPEND ls_attch TO lt_attch.
        CLEAR ls_attch.
      CATCH cx_bcs INTO lo_bcs.

    ENDTRY.

**********************************************************************
*   Email Attchment - csv
**********************************************************************
    ls_attch-type     = 'CSV'.
    ls_attch-att_name = 'TestCSV.csv'.

    DATA(lv_string) = 'Hello' && ',' && 'World' && cl_abap_char_utilities=>cr_lf &&
                      'Hello' && ',' && 'DeveloperMrMeng'.

    TRY .
        cl_bcs_convert=>string_to_solix(
          EXPORTING
            iv_string = lv_string
          IMPORTING
            et_solix = ls_attch-body_content
            ev_size  = ls_attch-size
        ).

        APPEND ls_attch TO lt_attch.
        CLEAR ls_attch.
      CATCH cx_bcs INTO lo_bcs.

    ENDTRY.

**********************************************************************
*   Email Attchment - xlsx ->from upload file
**********************************************************************
    ls_attch-type     = 'BIN'.
    ls_attch-att_name = 'TestXLSX.xlsx'.

    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename   = lv_test_file
        filetype   = 'BIN'
      IMPORTING
        filelength = lv_file_len
      CHANGING
        data_tab   = lt_solix_tab.

    ls_attch-body_content = lt_solix_tab.
    ls_attch-size         = lv_file_len.
    CONDENSE ls_attch-size NO-GAPS.
    APPEND ls_attch TO lt_attch.
    CLEAR ls_attch.

**********************************************************************
*   Email Attchment - xlsx ->from internal table
**********************************************************************

    ls_attch-type     = 'BIN'.
    ls_attch-att_name = 'TestXLSX_InternalTable.xlsx'.

*   Internal table to xlsx
    PERFORM frm_get_it_xlsx_solix CHANGING ls_attch-body_content
                                           ls_attch-size.
    APPEND ls_attch TO lt_attch.
    CLEAR ls_attch.

**********************************************************************
*   Email Attchment - Smartform to PDF
**********************************************************************
    ls_attch-type     = 'PDF'.
    ls_attch-att_name = 'TestPDF_Smartforms.pdf'.

*   Smartform convert to PDF
    PERFORM frm_get_sf_pdf_solix CHANGING ls_attch-body_content
                                          ls_attch-size.
    APPEND ls_attch TO lt_attch.
    CLEAR ls_attch.

**********************************************************************
*   Email Attchment - ALV to PDF
**********************************************************************
    ls_attch-type     = 'PDF'.
    ls_attch-att_name = 'TestPDF_ALV.pdf'.

*   ALV convert to PDF
    PERFORM frm_get_alv_pdf_solix CHANGING ls_attch-body_content
                                           ls_attch-size.
    APPEND ls_attch TO lt_attch.
    CLEAR ls_attch.

**********************************************************************
*   Email template ->SE80->Email template
**********************************************************************
    ls_mail_template-id           = 'ZTEST_TEMP_DEMO'.
    ls_mail_template-cds_key      = lt_cds_key.
    ls_mail_template-replace_info = lt_temp_replace.
    ls_mail_template-image_info   = lt_images.

    ls_body-body_template  = ls_mail_template.
**********************************************************************
*   Email template ->SMW0
**********************************************************************
*    ls_mail_temp_smw0-id           = 'ZTEMP_SMW0'.
*    ls_mail_temp_smw0-title        = 'This is a test title'.
*    ls_mail_temp_smw0-replace_info = lt_temp_rep_smw0.
*    ls_mail_temp_smw0-image_info   = lt_images.
*
*    ls_body-body_temp_smw0 = ls_mail_temp_smw0.

*   Send Mail
    zprbccl_send_mail=>send_mail(
      EXPORTING
        iv_mail_from_address = 'tian.meng@hand-china.com'
        it_mail_to_address   = lt_mail_to_address
        is_body              = ls_body
        it_attachment        = lt_attch
      IMPORTING
        es_return            = ls_return
    ).

    IF sy-batch = abap_true.
      ASSIGN COMPONENT 'BANFN' OF STRUCTURE lo_mail_data TO FIELD-SYMBOL(<fs_banfn>).

*     &1 send mail success.
      MESSAGE s057(zprbcmsg) WITH <fs_banfn>.
    ELSE.
      LOOP AT GROUP lo_mail_data ASSIGNING <fs_mail_data>.
        READ TABLE gt_alv ASSIGNING FIELD-SYMBOL(<fs_alv>)
          WITH KEY banfn = <fs_mail_data>-banfn
                   bnfpo = <fs_mail_data>-bnfpo
                   email = <fs_mail_data>-email
                   BINARY SEARCH.
        IF ls_return-type = 'S'.
          <fs_alv>-icon = icon_led_green.
        ELSE.
          <fs_alv>-icon = icon_led_red.
        ENDIF.
        <fs_alv>-msg = ls_return-message.
      ENDLOOP.
    ENDIF.

    CLEAR:
      lv_html_string,
      lt_mail_to_address,
      ls_mail_to_address,
      ls_body,
      lt_cds_key,
      ls_cds_key,
      ls_temp_replace,
      lt_temp_replace,
      lt_temp_rep_smw0,
      ls_temp_rep_smw0,
      lt_body_html_smw0,
      ls_body_html_smw0,
      ls_return.
  ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_sf_pdf_solix
*&---------------------------------------------------------------------*
*& Smartform convert to PDF
*&---------------------------------------------------------------------*
*&      <-- CS_ATTCH_BODY_CONTENT
*&      <-- CS_ATTCH_SIZE
*&---------------------------------------------------------------------*
FORM frm_get_sf_pdf_solix  CHANGING cs_attch_body_content TYPE solix_tab
                                    cs_attch_size TYPE so_obj_len.
  DATA:
    lv_fname TYPE rs38l_fnam.

  DATA:
    ls_control_para    TYPE ssfctrlop,
    ls_output_option   TYPE ssfcompop,
    ls_job_output_info TYPE ssfcrescl,
    lv_spoolid         TYPE rspoid.

  DATA:
    lv_size    TYPE i,
    lv_xstring TYPE xstring.

* Get dynamic runtime function name
  CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
    EXPORTING
      formname           = 'ZTEST_SF2PDF'
*     VARIANT            = ' '
*     DIRECT_CALL        = ' '
    IMPORTING
      fm_name            = lv_fname
    EXCEPTIONS
      no_form            = 1
      no_function_module = 2
      OTHERS             = 3.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
  ENDIF.

*  ls_control_para-getotf    = 'X'.
  ls_control_para-no_dialog = 'X'.

  ls_output_option-tddest   = 'LP01'.
  ls_output_option-tdnewid  = 'X'.

* Call Smartforms
  CALL FUNCTION lv_fname
    EXPORTING
      control_parameters = ls_control_para
      output_options     = ls_output_option
      user_settings      = ''
    IMPORTING
      job_output_info    = ls_job_output_info
    EXCEPTIONS
      formatting_error   = 1
      internal_error     = 2
      send_error         = 3
      user_canceled      = 4
      OTHERS             = 5.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
  ENDIF.

  CHECK ls_job_output_info-spoolids IS NOT INITIAL.

  READ TABLE ls_job_output_info-spoolids INTO DATA(ls_spoolids) INDEX 1.
  lv_spoolid = ls_spoolids.

* Convert OTF to PDF
  CALL FUNCTION 'CONVERT_OTFSPOOLJOB_2_PDF'
    EXPORTING
      src_spoolid              = lv_spoolid
*     NO_DIALOG                = 'X'
*     DST_DEVICE               =
      pdf_destination          = 'X'
      no_background            = 'X'
*     USE_CASCADING            = ' '
*     MODIFIED_PARAM_TABLE     =
    IMPORTING
      pdf_bytecount            = lv_size
*     PDF_SPOOLID              =
*     OTF_PAGECOUNT            =
*     BTC_JOBNAME              =
*     BTC_JOBCOUNT             =
      bin_file                 = lv_xstring
*   TABLES
*     PDF                      =
    EXCEPTIONS
      err_no_otf_spooljob      = 1
      err_no_spooljob          = 2
      err_no_permission        = 3
      err_conv_not_possible    = 4
      err_bad_dstdevice        = 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.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
  ENDIF.

  TRY .
      DATA(lo_pdf_merge) = NEW cl_rspo_pdf_merge( ).

      lo_pdf_merge->check_document(
        EXPORTING
          document   = lv_xstring
        IMPORTING
          error_text = DATA(error_text)
          rc         = DATA(rc)
      ).

      lo_pdf_merge->add_document( lv_xstring ).
      lo_pdf_merge->add_document( lv_xstring ).

      lo_pdf_merge->merge_documents(
        IMPORTING
          merged_document = DATA(lv_new_xstring)
      ).
    CATCH cx_rspo_pdf_merge.

  ENDTRY.

  lv_size = xstrlen( lv_new_xstring ).
  cs_attch_body_content = cl_bcs_convert=>xstring_to_solix( EXPORTING iv_xstring = lv_new_xstring ).
  cs_attch_size         = lv_size.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_alv_pdf_solix
*&---------------------------------------------------------------------*
*& ALV convert to PDF
*&---------------------------------------------------------------------*
*&      <-- CS_ATTCH_BODY_CONTENT
*&      <-- CS_ATTCH_SIZE
*&---------------------------------------------------------------------*
FORM frm_get_alv_pdf_solix  CHANGING cs_attch_body_content TYPE solix_tab
                                     cs_attch_size TYPE so_obj_len.
  DATA:
    ls_print       TYPE lvc_s_prnt,
    lv_spoolid     TYPE rspoid,
    lv_spoolid_del TYPE rqident,
    lt_pdf_tab     TYPE STANDARD TABLE OF tline,
    lv_pdf_xstring TYPE xstring,
    lv_pdf_size    TYPE i.

  ls_print-print = 'X'.

* Set print no dialog
  CALL FUNCTION 'GET_PRINT_PARAMETERS'
    EXPORTING
      destination            = 'LP01'
      immediately            = 'X'
      layout                 = 'X_65_255'
      mode                   = 'BATCH'
      no_dialog              = 'X'
    IMPORTING
      out_parameters         = ls_print-print_ctrl-pri_params
*     VALID                  =
*     VALID_FOR_SPOOL_CREATION       =
    EXCEPTIONS
      archive_info_not_found = 1
      invalid_print_params   = 2
      invalid_archive_params = 3
      OTHERS                 = 4.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
  ELSE.
    ls_print-print                  = 'X'.
    ls_print-no_change_print_params = 'X'.

    NEW-PAGE PRINT ON NEW-SECTION PARAMETERS ls_print-print_ctrl-pri_params NO DIALOG.

*   ALV display
    CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
      EXPORTING
*       i_callback_program = syst-repid
        it_fieldcat_lvc = gt_fieldcat
        is_layout_lvc   = gs_layout
        is_print_lvc    = ls_print
      TABLES
        t_outtab        = gt_sf_alv
      EXCEPTIONS
        program_error   = 1
        OTHERS          = 2.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ELSE.
      CHECK sy-spono IS NOT INITIAL.

      lv_spoolid = sy-spono.

*     Get PDF content
      CALL FUNCTION 'CONVERT_ABAPSPOOLJOB_2_PDF'
        EXPORTING
          src_spoolid              = lv_spoolid
          pdf_destination          = 'X'
*         NO_DIALOG                =
        IMPORTING
          pdf_bytecount            = lv_pdf_size
          bin_file                 = lv_pdf_xstring
        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.

      IF sy-subrc <> 0.
*       Implement suitable error handling here
      ENDIF.

      cs_attch_body_content = cl_bcs_convert=>xstring_to_solix( EXPORTING iv_xstring = lv_pdf_xstring ).
      cs_attch_size         = lv_pdf_size.

      lv_spoolid_del = lv_spoolid.

      CALL FUNCTION 'RSPO_R_RDELETE_SPOOLREQ'
        EXPORTING
          spoolid = lv_spoolid_del.
    ENDIF.

    NEW-PAGE PRINT OFF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_it_xlsx_solix
*&---------------------------------------------------------------------*
*& Convert internal table to xlsx
*&---------------------------------------------------------------------*
*&      <-- CS_ATTCH_BODY_CONTENT
*&      <-- CS_ATTCH_SIZE
*&---------------------------------------------------------------------*
FORM frm_get_it_xlsx_solix CHANGING cs_attch_body_content TYPE solix_tab
                                    cs_attch_size TYPE so_obj_len.

  TYPES:
    BEGIN OF ty_test,
      userid   TYPE string,
      username TYPE string,
    END OF ty_test,
    tt_test TYPE STANDARD TABLE OF ty_test.

  DATA:
    lt_test     TYPE tt_test,
    lv_xstring  TYPE xstring,
    lv_string   TYPE string,
    lv_codepage TYPE cpcodepage.

  DATA:
    lo_bcs TYPE REF TO cx_bcs.

  lt_test = VALUE #( ( userid = 'DeveloperMrMeng' username = 'Hello World' )
                     ( userid = 'DeveloperMrMeng' username = 'Hello ABAP'  ) ).

  DATA(lt_data) = REF #( lt_test ).

  FIELD-SYMBOLS: <tab> TYPE STANDARD TABLE.
  ASSIGN lt_data->* TO <tab>.
  TRY.
      cl_salv_table=>factory(
        EXPORTING
          list_display = abap_false
        IMPORTING
          r_salv_table = DATA(salv_table)
        CHANGING
          t_table      = <tab>
      ).

      DATA(lt_fcat) = cl_salv_controller_metadata=>get_lvc_fieldcatalog(
                        r_columns      = salv_table->get_columns( )
                        r_aggregations = salv_table->get_aggregations( )
                      ).
    CATCH cx_salv_msg.
      RETURN.
  ENDTRY.

* Convert table to xstring
  cl_salv_bs_lex=>export_from_result_data_table(
    EXPORTING
      is_format            = if_salv_bs_lex_format=>mc_format_xlsx
      ir_result_data_table = cl_salv_ex_util=>factory_result_data_table(
                              r_data         = lt_data
                              t_fieldcatalog = lt_fcat
                             )
    IMPORTING
      er_result_file       = lv_xstring ).

  TRY .
      cl_bcs_convert=>xstring_to_solix(
        EXPORTING
          iv_xstring = lv_xstring
        RECEIVING
          et_solix = cs_attch_body_content
      ).

      cs_attch_size = xstrlen( lv_xstring ).
    CATCH cx_bcs INTO lo_bcs.

  ENDTRY.
ENDFORM.

以上。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeveloperMrMeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值