Skip to Content
Technical Articles

Sending Email from FINT

Introduction

 

FINT is a handy transaction for calculating of interest on customer items ( for vendor items FINTAP should be used). It is the successor of the old transactions F.2A/ F.2B/ F.2C and F.24 which were using program RFDUZI00 for calculation.

FINT works, like most of periodically scheduled programs in SAP, using a 2-step approach: first a proposal is created and then the production run can be executed. It is also possible to directly start a production run without seeing the proposal run but this approach is rather not used.

Whereas the transactions based on RFDUZI00 program supported Sap Script only, FINT supports Smartforms and Adobe PDF and has a BADI where all actions performed by the calculation program can be influenced.

There are already well-documented examples how to steer with email sending of different correspondence in different SAP forums on the Internet and OSS notes:

  • Payment Advice: OSS 1033893
  • Dunning: 1042992
  • Balance Confirmation: 1377820
  • Other correspondence: 1360070

In terms of FINT SAP only delivered note 956981, which by standard supports only email sending for forms created using Adobe PDF but not Smartforms

This gap in documentation made me write the blog to show you how you can archive the interest email sending and what to consider during the programming.

 

FINT Enhancement Possibilities

FINT, in opposite to classic transactions based on RFDUZI00, has a BADI where many of the interest parameters, including the whole output and calculation, can be adjusted to customer needs. The BADI name is FI_INT_CUS01 – in fact in the coding 2 BADIs can be found, the other one is FI_INT_SAP01, which rather should be used by SAP only. It only seems to be a mistake that SAP didn’t mark it as ‘To-be-used by SAP only’.

Anyway the processing of each method available in these BADIs is always called in sequence – first FI_INT_SAP01 and immediately below it FI_INT_CUS01.

Besides that the selection screen as well as ALV output and Functions can be enhanced via program RFINTITUSEREXT.

FINT Email sending: Logic

The code presented in further sections of this blog is based on assumption that interest notes are to be send out to a customer who has a main E-mail address provided. If the email is marked as ‘standard’ then such is set as email recipient, otherwise it is set as secondary recipient (carbon copy).

FINT Email Sending: Enhance Screen

At first, to make email sending controllable, the selection screen will be enhanced by a new field using the screen enhancement program.

Program RFINTITUSEREXT provides function to:

  • Add / delete fields in calculation and display structure
  • Add / delete custom parameters
  • Add / delete custom select-options

The parameters and select-options have a predefined naming convention – they must begin with ‘A_’.  Using data elements created in a customer namespace, like /SAP/ should not be be used for any kind of abovementioned screen enhancement – it happened to me several times that system adds it (at least it says so) but it cannot be named and stays only as an untranslated parameter. Therefore it is advisable to use only Z/Y for data elements used as base of new fields (besides of course the standard standard ones that can also be used).

A newly created data element can be added using following option:

By adding a new parameter system will modify the include RFINTITARUSEREXT and FI_INT_USEREXT so you will be prompted to provide an object key for modification.

Note that the description of the data element is not taken automatically over in the selection screen, so you need to adjust it in SE38 of program RFINTITAR by choosing Text Elements -> Selection Text.

FINT Email Sending: Methods used

This implementation is called only when productive run of interest calculation is done.

In implementation of BADI FI_INT_CUS01 email can be archived by using 2 methods:

  1. INT_PRINT_OPTIONS – determination of email recipients and conversion to OTF
  2. INT_PRINT_SPOOL_CLOSED – actual sending of emails

In this example the content and subject of email are hardcoded – this is only for presentation purposed – in your system do not follow this approach!

FINT Email Sending: Class Attributes

 

Method INT_PRINT_OPTIONS contains all data about the interest calculated, business partners and output options. It is called when sample or final printout is selected in FINT.

In this method parameters for email recipients etc. already exists but filling them does not have any effect when using Smartforms-based output. This means that the recipients need to be saved in  a class attribute. We will use attribute ‘mt_email_recipients’ for that.

In addition the processing sequence of each output is only available in this method so it is advisable to save it in an attribute as well. In this example it will be saved in attribute ‘mt_ipf_proc_seq’.

To determine proper language of email text the output language will be stored in attribute ‘mt_output_language’. It won’t actually be used in the class for determining the language of email and is included here only for demonstration purposes.

Additionally, as newly-added selection parameter ‘A_EMAIL’ is not available in INT_PRINT_SPOOL_CLOSED it will be saved as ‘mv_email’ attribute.

In the method INT_PRINT_SPOOL_CLOSED no information about customer etc. is available. It is only called for each global output table GT_IPF_DISP of the report (stored in function group SAPLFI_INT) transferring the output content itself.

At the end following attributes and types are defined in the implementation class:

public section.

  interfaces IF_EX_FI_INT_CUS01 .

  constants GC_ACCOUNT_TYPE_CUSTOMER type KOART value 'D' ##NO_TEXT.
  constants GC_INTEREST_STATUS_NOINT type INT_STATUS value 'NOINT' ##NO_TEXT.
  constants GC_INTEREST_STATUS_PROCESS type INT_STATUS value 'PROCESS' ##NO_TEXT.
  constants GC_INTEREST_STATUS_NEW type INT_STATUS value 'NEW' ##NO_TEXT.

private section.

  types:
    "Types
    " Key used to identity an interest package
    BEGIN OF tp_fint_key,
      bukrs TYPE bukrs,
      koart TYPE koart,
      konko TYPE konko,
    END OF tp_fint_key .
  types:
  "Language of printout info
    BEGIN OF tp_language_info.
          INCLUDE TYPE tp_fint_key.
  TYPES:
    spras TYPE spras,
    name1 TYPE name1,
    END OF tp_language_info .
  types:
    tt_language_info TYPE STANDARD TABLE OF tp_language_info WITH NON-UNIQUE KEY bukrs koart konko .
  types:
  "Email recipient list
    BEGIN OF tp_email_recipients.
          INCLUDE TYPE tp_fint_key.
  TYPES:
    receiver   TYPE ad_smtpadr,
    copy       TYPE so_snd_cp,
    blind_copy TYPE so_snd_bc,
    END OF tp_email_recipients .
  types:
    tt_email_recipients TYPE STANDARD TABLE OF tp_email_recipients WITH NON-UNIQUE KEY bukrs koart konko .
  types:
  "Processing sequence of output
    tt_ipf_sequence TYPE STANDARD TABLE OF intipf WITH DEFAULT KEY .

  "Contants for checks/ output info
  constants C_FINTSHOW type SY-TCODE value 'FINTSHOW' ##NO_TEXT.
  constants C_ATTACHMENT_TYPE_PDF type SO_OBJ_TP value 'PDF' ##NO_TEXT.
  "Data for email processing
  data MT_OUTPUT_LANGUAGE type TT_LANGUAGE_INFO .
  data MT_IPF_PROC_SEQ type TT_IPF_SEQUENCE .
  data MT_EMAIL_RECIPIENTS type TT_EMAIL_RECIPIENTS .
  data MV_EMAIL type Z_FINT_EMAIL_SEND .
  constants C_EMAIL type FIELDNAME value 'A_EMAIL' ##NO_TEXT.

 

FINT Email Sending: INT_PRINT_OPTIONS

This method is called in function module SF_PRINT_INTIT_NOTICE just before the SMARTFORM is called. The call happens in loop over T_IPF table storing each output line to be processed. T_IPF in the loop represents the same content as global table GT_IPF  of RFINTITAR.

Table GT_IPF contains all customers for which interest is to be created. Entries stored in the table show in which order the output is processed. Method INT_PRINT_OPTIONS is triggered for every single entry of GT_IPF.

As soon as the spool is closed these entries are not available any more in the method INT_PRINT_SPOOL_CLOSED that is why we’re storing it in class attribute to use it later on and send email.

  METHOD if_ex_fi_int_cus01~int_print_options.
    DATA ls_cus_addrres TYPE szadr_addr1_complete.
    "Email in FINT

    TRY.
        mv_email = it_frange[ fieldname = c_email ]-selopt_t[ 1 ]-low.

      CATCH cx_sy_itab_line_not_found.
    ENDTRY.

    "no email sending from preview and print preview
    IF sy-tcode = c_fintshow OR control_parameters-preview IS NOT INITIAL OR mv_email IS INITIAL.
      RETURN.
    ENDIF.



    mt_ipf_proc_seq = VALUE #( BASE mt_ipf_proc_seq ( is_ipf ) ).

    "read main email address of customer - can be changed to other type of read

    "read email address from Customer master data
    CALL FUNCTION 'ADDR_GET_COMPLETE'
      EXPORTING
        addrnumber              = is_kna1-adrnr
      IMPORTING
        addr1_complete          = ls_cus_addrres
      EXCEPTIONS
        parameter_error         = 1
        address_not_exist       = 2
        internal_error          = 3
        wrong_access_to_archive = 4
        address_blocked         = 5
        OTHERS                  = 6.

    IF sy-subrc NE 0.
      RETURN.
    ENDIF.

    LOOP AT ls_cus_addrres-adsmtp_tab ASSIGNING FIELD-SYMBOL(<fs_adsmtp>) WHERE adsmtp-flg_nouse IS INITIAL AND adsmtp-smtp_addr IS NOT INITIAL.

      IF <fs_adsmtp>-adsmtp-flgdefault EQ abap_true.

        "add recipients
        mt_email_recipients = VALUE #( BASE mt_email_recipients ( bukrs = is_ipf-bukrs
                                                                  koart = is_ipf-koart
                                                                  konko = is_ipf-account
                                                                  receiver = <fs_adsmtp>-adsmtp-smtp_addr
                                                                   ) ).

      ELSE.
        mt_email_recipients = VALUE #( BASE mt_email_recipients ( bukrs = is_ipf-bukrs
                                                                  koart = is_ipf-koart
                                                                  konko = is_ipf-account
                                                                  receiver = <fs_adsmtp>-adsmtp-smtp_addr
                                                                  copy = abap_true
                                                                   ) ).
      ENDIF.

    ENDLOOP.

    IF line_exists( mt_email_recipients[ bukrs = is_ipf-bukrs
                                         koart = is_ipf-koart
                                         konko = is_ipf-account ] ).

      "prepare OTF data for PDF sending
      control_parameters-getotf = abap_true.
      output_options-tdnewid    = abap_true.

      IF line_exists( mt_output_language[ bukrs = is_ipf-bukrs
                                          koart = is_ipf-koart
                                          konko = is_ipf-account ] ).
      ELSE.
        "prepare list of output languages
        mt_output_language = VALUE #( BASE mt_output_language ( bukrs = is_ipf-bukrs
                                                                koart = is_ipf-koart
                                                                konko = is_ipf-account
                                                                spras = control_parameters-langu
                                                                name1 = is_kna1-name1 ) ).
      ENDIF.

    ENDIF.

  ENDMETHOD.

 

FINT Email Sending: INT_PRINT_SPOOL_CLOSED

At the point of time when this method is called the spool is already closed, interest tables are updated with proper statuses and now the email creation can happen undisturbed.

The logic is processed when the ‘preview’ option was not set and the status is not in process as well as the interest document number was assigned.

This option contains also a check if the data is delivered in OTF form.

As not further actions are executed after his method email sending is done using CL_BCS class.

METHOD if_ex_fi_int_cus01~int_print_spool_closed.
*------------------*
* Local Variables  *
*------------------*
    DATA: lv_dirty_assign_preview TYPE string VALUE '(SAPLFI_INT)GB_PREVIEW'. "holding print preview indicator
    DATA: lv_doc_size     TYPE so_obj_len. " PDF document size
    DATA: lv_pdf_xstring TYPE xstring. "PDF conversion into xstring
    DATA: ls_email_subject TYPE itcpo-tdtitle. "email subject
*------------------*
* Local Structures *
*------------------*
    DATA: ls_ipf_global TYPE intipf.
*------------------*
*   Local Tables   *
*------------------*
    DATA: lt_pdf_lines    TYPE tline_tab. "converted lines to PDF
    DATA: lt_otf_lines    TYPE efg_tab_itcoo. "OTF lines delivered by smartforms
    DATA: lt_objbin   TYPE STANDARD TABLE OF solix. "PDF in HEX format



    "1.0 get global variables
    READ TABLE mt_ipf_proc_seq INTO ls_ipf_global INDEX 1. "processing one by one
    DELETE mt_ipf_proc_seq INDEX 1.
    ASSIGN (lv_dirty_assign_preview) TO FIELD-SYMBOL(<fs_preview>).
    IF sy-subrc NE 0.
      RETURN.
    ENDIF.

    "1.1 first check
    IF ( ls_ipf_global-int_status = gc_interest_status_process AND ls_ipf_global-form_to IS INITIAL ) " form number not generated yet
    OR ( ls_ipf_global-int_belnr IS INITIAL AND ls_ipf_global-int_gjahr IS INITIAL AND ls_ipf_global-form_to IS INITIAL ) "document not posted yet
    OR ( <fs_preview> EQ abap_true )
    OR ( mv_email IS INITIAL ). "print preview only
      RETURN.
    ENDIF.

    "1.2 - conditions for Email: no printout was generated
    IF job_output_info-otfdata IS NOT INITIAL.

      lt_otf_lines = job_output_info-otfdata.

      "2.0 Convert OTF data into PDF

      CALL FUNCTION 'CONVERT_OTF'
        EXPORTING
          format                = c_attachment_type_pdf
          max_linewidth         = 132
        IMPORTING
          bin_filesize          = lv_doc_size
          bin_file              = lv_pdf_xstring   " This is NOT Binary. This is Hexa
        TABLES
          otf                   = lt_otf_lines
          lines                 = lt_pdf_lines
        EXCEPTIONS
          err_max_linewidth     = 1
          err_format            = 2
          err_conv_not_possible = 3
          OTHERS                = 4.
      IF sy-subrc <> 0.
        RETURN.
      ENDIF.
      REFRESH lt_otf_lines.

      "2.1 prepare HEX for PDF as attachment
      CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
        EXPORTING
          buffer     = lv_pdf_xstring
        TABLES
          binary_tab = lt_objbin[].

      READ TABLE mt_output_language WITH TABLE KEY bukrs = ls_ipf_global-bukrs
                                              koart = ls_ipf_global-koart
                                              konko = ls_ipf_global-account
                                              ASSIGNING FIELD-SYMBOL(<fs_customer>).
      IF sy-subrc EQ 0.

        "2.3 Get email subject
        "additional actions on subject - add Customer number + name

        ls_email_subject = |{ 'Interest Email' } { ls_ipf_global-account ALPHA = OUT } { <fs_customer>-name1 }|.
      ELSE.

        ls_email_subject = |{ 'Interest Email' } { ls_ipf_global-account ALPHA = OUT }|.
      ENDIF.


      "2.4 Get email content
      DATA(lt_email_content) = VALUE soli_tab( ( |{ 'email text ' }| ) ).


      TRY.

          "3.0 Initiate object for email sending
          DATA(lo_send_email) = cl_bcs=>create_persistent( ).

          "3.1 Initialite attached document
          DATA(lo_email_attachment) = cl_document_bcs=>create_document( i_type    = 'RAW'
                                                                        i_text = lt_email_content
                                                                        i_subject = ls_email_subject ). "#EC NOTEXT

          "3.2 add the PDF as attachment to document object
          lo_email_attachment->add_attachment( i_attachment_type    = c_attachment_type_pdf
                                               i_attachment_subject = CONV so_obj_des( ls_email_subject )
                                               i_att_content_hex = lt_objbin
                                               ).

          "3.3 add document object to email
          lo_send_email->set_document( lo_email_attachment ).

          "3.4 add recipient
          LOOP AT mt_email_recipients ASSIGNING FIELD-SYMBOL(<fs_email_recipient>) WHERE koart = ls_ipf_global-koart
                                                                                     AND konko = ls_ipf_global-account.

            DATA(lo_email_recipient) = cl_cam_address_bcs=>create_internet_address( <fs_email_recipient>-receiver ).

            CASE abap_true.
              WHEN <fs_email_recipient>-copy.

                lo_send_email->add_recipient( i_recipient = lo_email_recipient
                                              i_copy = abap_true ).

              WHEN <fs_email_recipient>-blind_copy.

                lo_send_email->add_recipient( i_recipient = lo_email_recipient
                                              i_blind_copy = abap_true ).

              WHEN OTHERS.
                lo_send_email->add_recipient( lo_email_recipient ).
            ENDCASE.

          ENDLOOP.

          "3.5 Set status
          lo_send_email->set_status_attributes( i_requested_status = CONV bcs_rqst('N')  ).

          "3.6 send email
          DATA(ls_result) = lo_send_email->send( ).

          COMMIT WORK.

          "check the result of sending
          IF ls_result IS INITIAL.
            MESSAGE i500(sbcoms) WITH <fs_email_recipient>-receiver.
            ROLLBACK WORK.
          ELSE.
            MESSAGE s022(so).
          ENDIF.

        CATCH cx_bcs INTO DATA(lo_email_exception).
          MESSAGE i500(sbcoms) WITH <fs_email_recipient>-receiver.
      ENDTRY. " on email sending
    ENDIF. "on provided OTF data

  ENDMETHOD.

This method ends the required implementation.

 

Example of use

To show how the solution works 3 customers were defined of which 2 only have email addresses updated.

Several invoices were posted and paid with some days in arrears:

Executing FINT shows the new field is available:

Executing FINT with ‚test run’ marked provides a list of selected and calculated interest. If this is not selected then the update of master data and printout will be triggered automatically.

For test purposes I run the report with test run enabled to see the proposal first.

Final processing is done with button

Then:

Items were processed successfully:

At the end 2 emails should be send out to customers – they can be visible in SOST:

With PDF attached to email:

Direct processing (without test run) is also supported:

At the end the result is the same – emails are generated and visible in SOST:

 

Thank you for reading – in next blog I will show how to enhance FINT output by custom fields like customer name.

Marek

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

    Hi Marek

    Thanks! I assume the three invoices in your example must trigger three different spools? How do you achieve that? If I set “new spool request” and “do not append print jobs” in the print pop-up I still get only one spool for all invoices. I guess that would then not work for your email solution?

    BR
    Magnus

    • Hi Magnus,

       

      actually the opening on new spool job is controlled in my solution in this part:

          "prepare OTF data for PDF sending
            control_parameters-getotf = abap_true.
            output_options-tdnewid    = abap_true.

       

      The parameter TDNEWID controls that a new spool job is opened each time for each customer. This is a prerequisite for sending the emails separately per customer in my solution. By this each output is handled separately and we can clearly steer email sending.

      The settings of “new spool request” and “do not append print jobs” actually mean a double negative and in result give = “append print jobs”.

      This results in what you see – getting only one spool job – by this my solution will not really work because it sends the printouts at the end of spool job after database is updated with interest data (for consistency reasons). If you do not wish to keep this consistency but also use these 2 options together then you might go for using method INT_PRINT_RESULTS to send emails.

      This method is called after each loop over T_IPF table (function module SF_PRINT_INTIT_NOTICE) which contains all customers for which interests are to be printed. There you have also direct access to importing parameter JOB_OUTPUT_INFO from which you can read the OTF data and send the email and still get only one spool output.

      Regards,

      Marek