Tuesday, May 19, 2015

VDA Modulus 43 method of Data Matrix ECC200

From time to time we all have to fulfill some technical norm. Concerning Data Matrix code ECC200 - VDA label norm there is no exception. Once I had to code this norm requirement, simple task to get security sign of all DMC content. So why to discover a wheel again? :) Check my approach below.

VDA requirement says

The check digit is calculated with the Modulus 43 method:
For this purpose the numeric values of all characters transferred (without control characters) are
added and the sum is divided by 43.

The remaining balance is converted into a character again and transferred in the data record as a
check digit. 

Example: the “12345ABCDE” string makes the check digit W. 1+2+3+4+5+10+11+12+13+14 = 75 
--> 75 : 43 = 1 Rest 32 -> 32 equals the W character.



I put some simple subroutine into SF to add one DataMatrix code item.



Later on subroutine for modulus 43.




The actual coding looks like this


*&---------------------------------------------------------------------*
*&      Form  get_check_code
*&---------------------------------------------------------------------*
*       get VDA security check character
*----------------------------------------------------------------------*
*      -->LV_INPUTDATA_STR  text
*      -->LV_CHECK_CHAR     text
*----------------------------------------------------------------------*
FORM get_check_code
      USING
          lv_inputdata_str TYPE string
      CHANGING
          lv_check_char    TYPE /fit/lwert.

  TYPESBEGIN OF ty_translation,
            input TYPE c1,
            value TYPE i,
         END OF ty_translation.

  DATAlt_translations TYPE STANDARD TABLE OF ty_translation,
        ls_translation LIKE LINE OF lt_translations.

  CONSTANTS cv_diviser TYPE VALUE 43.

  ls_translation-input '0'.
  ls_translation-value 0.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '1'.
  ls_translation-value 1.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '2'.
  ls_translation-value 2.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '3'.
  ls_translation-value 3.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '4'.
  ls_translation-value 4.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '5'.
  ls_translation-value 5.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '6'.
  ls_translation-value 6.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '7'.
  ls_translation-value 7.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '8'.
  ls_translation-value 8.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '9'.
  ls_translation-value 9.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'A'.
  ls_translation-value 10.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'B'.
  ls_translation-value 11.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'C'.
  ls_translation-value 12.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'D'.
  ls_translation-value 13.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'E'.
  ls_translation-value 14.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'F'.
  ls_translation-value 15.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'G'.
  ls_translation-value 16.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'H'.
  ls_translation-value 17.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'I'.
  ls_translation-value 18.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'J'.
  ls_translation-value 19.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'K'.
  ls_translation-value 20.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'L'.
  ls_translation-value 21.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'M'.
  ls_translation-value 22.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'N'.
  ls_translation-value 23.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'O'.
  ls_translation-value 24.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'P'.
  ls_translation-value 25.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'Q'.
  ls_translation-value 26.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'R'.
  ls_translation-value 27.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'S'.
  ls_translation-value 28.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'T'.
  ls_translation-value 29.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'U'.
  ls_translation-value 30.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'V'.
  ls_translation-value 31.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'W'.
  ls_translation-value 32.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'X'.
  ls_translation-value 33.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'Y'.
  ls_translation-value 34.
  APPEND ls_translation TO lt_translations.

  ls_translation-input 'Z'.
  ls_translation-value 35.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '-'.
  ls_translation-value 36.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '.'.
  ls_translation-value 37.
  APPEND ls_translation TO lt_translations.

  ls_translation-input ' '.
  ls_translation-value 38.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '$'.
  ls_translation-value 39.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '/'.
  ls_translation-value 40.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '+'.
  ls_translation-value 41.
  APPEND ls_translation TO lt_translations.

  ls_translation-input '%'.
  ls_translation-value 42.
  APPEND ls_translation TO lt_translations.
*
  TRANSLATE lv_inputdata_str TO UPPER CASE.

  DATAlv_char   TYPE c,
        lv_offset TYPE syindex,
        lv_sum    TYPE i,
        lv_rest   TYPE i.

  " get sum of character values
  DO strlenlv_inputdata_str TIMES.
    lv_offset sy-index 1.
    lv_char lv_inputdata_str+lv_offset.

    IF lv_char IS NOT INITIAL.
      CLEAR ls_translation.
      READ TABLE lt_translations WITH KEY input lv_char INTO ls_translation.
      IF sy-subrc EQ 0.
        lv_sum lv_sum + ls_translation-value.
      ENDIF.
    ENDIF.
  ENDDO.

  " get proper 43 return code
  IF lv_sum NE 0.
    lv_rest lv_sum MOD cv_diviser.
    CLEAR ls_translation.
    READ TABLE lt_translations WITH KEY value lv_rest INTO ls_translation.
    IF sy-subrc EQ 0.
      lv_check_char ls_translation-input.
    ENDIF.
  ENDIF.
ENDFORM.                    "get_check_code





Wednesday, November 26, 2014

Custom container + SALV - PBO runs twice under Resizing option or how to reach just one horizontal bar

SALV class is really handy, simple to use. No need of manual field catalog creation is super feature. But in some cases is does something you do not expect. This article describes one of this strange behavior.

Imagine such "uncommon" situation, you place your ALV inside custom container with some certain dimensions. There is no other vertical space, so we have fixed defined height of the container. On the other side, ALV can contain many columns. It causes later on two horizontal scroll bars. What is really annoying.

Overcome two scroll bars, but...




OK, no problem, there is a solution. We can just tick "Resizing" check box for automatic horizontal or vertical growth. We should have just one scroll bar. That's nice, But there is one quite interesting BUT.



Custom container/SALV shadow behavior


In this case PBO action is to be run twice. Why? Custom container resizing capability causes to trigger PAI immediately after SALV->display( ) method. Suddenly you can see in debug loading of method IF_SALV_DISPLAY_ADAPTER~GET_COLUMNS. Container reacts with it is own event on resizing option. One more note, here the automatic screen reload depends on amount of ALV data. If you have just few rows, nothing special would happen. But with growing number of SALV rows reload occurs.

Conclusion


Now we have to choose, to have just one scroll bar with side effect of one more automatic PAI/PBO loop on screen OR to have two bars and exactly one PBO action. Sometime it takes a time to discover such a secret behind. When you have some special logic in PBO, twice run could be unwanted behavior.


In my case I had to rewrite the PBO action to reach just one horizontal bar. I had to equip the PBO with some logic calculating with second PBO run. So some checks has to be added. The result is OK afterwards.






Friday, August 29, 2014

HTML Email with tables generated by SmartForm

Intro

There are various possibilities how to work with emails in SAP. Previously I used some function module. When I obtained a task to prepare an email message with some log info content e.g. this job passed the other failed. I decided to create a HTML email message with nice colors, green for passed, red for failed tasks.

At first I decided to use Nguyen Van Thao's pattern. It uses CL_BCS class and SF. I used it by a bit by my own way. So let me introduce a clone with tables inside the smart form + some my experience notes.

Content generator Class

There is class responsible for the filling out needed tables which should be displayed inside the email. I just took a real example from my work.

*----------------------------------------------------------------------*
*       CLASS lcl_manager_email DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_manager_email DEFINITION.
  PUBLIC SECTION.
    METHODSconstructor
              IMPORTING
                io_data_sel  TYPE REF TO lcl_data_sel
                io_data_user TYPE REF TO lcl_data_user,
             send_email_log
              IMPORTING iv_subject TYPE so_obj_des
              RAISING lcx_msg_exception.

  PRIVATE SECTION.
    DATAo_data_sel  TYPE REF TO lcl_data_sel,
          o_data_user TYPE REF TO lcl_data_user.

    METHODSget_mail_body
                RETURNING value(rt_soliTYPE soli_tab
                RAISING lcx_msg_exception" get mail body from Smart form

ENDCLASS.                    "lcl_manager_email DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_manager_email IMPLEMENTATION
*----------------------------------------------------------------------*
* Any email stuff
*----------------------------------------------------------------------*
CLASS lcl_manager_email IMPLEMENTATION.

  METHOD constructor.
    o_data_sel  io_data_sel.
    o_data_user io_data_user.
  ENDMETHOD.                    "constructor

  METHOD send_email_log.
    " Send message only in case of real action
    IF o_data_sel->v_locka IS NOT INITIAL )    " do admin lock
        OR o_data_sel->v_lockl IS NOT INITIAL )  " do local lock
        OR o_data_sel->v_vali  IS NOT INITIAL )" set validation

      DATAlo_send_request TYPE REF TO cl_bcs,
            lo_document     TYPE REF TO cl_document_bcs,
            lo_recipient    TYPE REF TO if_recipient_bcs,
            lo_sender       TYPE REF TO cl_sapuser_bcs,
            lt_soli         TYPE soli_tab,
            lv_sent_flag    TYPE abap_bool,
            lx_oref         TYPE REF TO lcx_msg_exception,
            lx_bcf          TYPE REF TO cx_bcs,
            lv_msg          TYPE string.

      lt_soli me->get_mail_body).

      " Instantinate CL_BCS and specify options
      TRY .
          " Create persistent
          lo_send_request cl_bcs=>create_persistent).

          " Email FROM
          lo_sender cl_sapuser_bcs=>createsy-uname ).
          " Add sender to send request
          CALL METHOD lo_send_request->set_sender
            EXPORTING
              i_sender lo_sender.

          " Email TO
          lo_recipient cl_cam_address_bcs=>create_internet_addresso_data_sel->v_email ).
          " Add recipient to send request
          CALL METHOD lo_send_request->add_recipient
            EXPORTING
              i_recipient lo_recipient
              i_express   'X'.

          " Email BODY from SmartForm
          lo_document cl_document_bcs=>create_document(
              i_type        'HTM'
              i_subject     iv_subject
              i_text        lt_soli ).
          " Add document to send request
          CALL METHOD lo_send_request->set_documentlo_document ).

          " Send email
          lo_send_request->set_send_immediatelyi_send_immediately abap_true ).

          lv_sent_flag lo_send_request->sendi_with_error_screen 'X' ).
          IF lv_sent_flag EQ abap_false.
            RAISE EXCEPTION TYPE lcx_msg_exception
              EXPORTING iv_text =  'Error Sending Email!'.
          ENDIF.

          "Commit to send email
          COMMIT WORK.

        CATCH cx_bcs INTO lx_bcf.
          RAISE EXCEPTION lx_bcf.
      ENDTRY.
    ENDIF.
  ENDMETHOD.                    "send_email_log

  METHOD get_mail_body.

*---Data declaration
    DATAlt_lines TYPE TABLE OF tline,
          ls_line  TYPE tline,
          ls_soli  TYPE soli.
    DATAlv_fname      TYPE rs38l_fnam,
          ls_job_output TYPE ssfcrescl"Structure to return value at the end of form printing
    DATAls_ctrl_form  TYPE ssfctrlop"Smart Form Control Structure
          ls_output_opt TYPE ssfcompop"Smart Form Transfer Options

*---Pass data to Smartforms to receive itab of HTML Email

    "Get Smart Form Function Module Name
    CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
      EXPORTING
        formname           cv_sf_htm_mail
      IMPORTING
        fm_name            lv_fname
      EXCEPTIONS
        no_form            1
        no_function_module 2
        OTHERS             3.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Spool parameters
    ls_output_opt-tdimmed 'X'.      "Print Immediately (Print Parameters)
    ls_output_opt-tddelete 'X'.     "Delete After Printing (Print Parameters)
    ls_output_opt-tdlifetime 'X'.   "Spool Retention Period (Print Parameters)
    ls_output_opt-tddest 'LOCL'.    "Spool: Output device
    ls_output_opt-tdprinter 'SWIN'"Spool: Device type name
    ls_ctrl_form-no_dialog 'X'.     "SAP Smart Forms: General Indicator
    ls_ctrl_form-preview 'X'.       "Print preview
    ls_ctrl_form-getotf 'X'.        "Return of OTF table. No printing, display, or faxing
    ls_ctrl_form-langu 'EN'.        "Language key
    ls_ctrl_form-device 'PRINTER'.  "Output device

    "Call Smart Form Function Module
    CALL FUNCTION lv_fname
      EXPORTING
        control_parameters ls_ctrl_form
        output_options     ls_output_opt
      IMPORTING
        job_output_info    ls_job_output
      TABLES
        it_users1          o_data_user->t_users1
        it_users2          o_data_user->t_users2
        it_users3          o_data_user->t_users3
        it_users4          o_data_user->t_users4
        it_result_statuses o_data_user->t_result_statuses
        it_result_errors   o_data_user->t_result_errors

      EXCEPTIONS
        formatting_error   1
        internal_error     2
        send_error         3
        user_canceled      4
        OTHERS             5.
    IF ls_job_output-otfdata IS INITIAL.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Convert OTF to TLINE
    CALL FUNCTION 'CONVERT_OTF'
      EXPORTING
        format                'ASCII'
        max_linewidth         132
      TABLES
        otf                   ls_job_output-otfdata
        lines                 lt_lines
      EXCEPTIONS
        err_max_linewidth     1
        err_format            2
        err_conv_not_possible 3
        err_bad_otf           4
        OTHERS                5.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Remove empty lines
    DELETE lt_lines WHERE tdline EQ space.
    "Convert itab of HTML Email to itab of sending format in class CL_BCS
    LOOP AT lt_lines INTO ls_line.
      ls_soli ls_line-tdline.
      APPEND ls_soli TO rt_soli.
      CLEAR ls_soli.
    ENDLOOP.

  ENDMETHOD.                    "get_mail_body

ENDCLASS.                    "lcl_manager_email IMPLEMENTATION



Smart form

By above class we have some prepared data/tables which should be placed into email. Please acknowledge the data types transferred into SmartForm must be data dictionary based. Here I used also some our custom types. 



Tables

I had a bit bad experience with SmartForm's TABLE elements. The text inside the SOLI table was truncated and useless for HTML content. So I decided to use simple LOOP instead of table. Inside the loop you can achieve the same functionality. In connection with IF conditions inside the loop it gives you quite powerful tool for email generation.



In text element you can place your HTML code with inside CSS style. Inside text element you may work normally with variables as usual e.g. &GS_RESULT_STATUS-STATUS_LOCKED&.




Together it produces following tables within email. Now email dynamically shows the result of the last taken action according to the conditions within table loops inside the SmartForm.



As you see, it's some mix up of SmartForm's elements and HTML/CSS styles inside texts elements and that's all. So now is your turn...









Friday, August 1, 2014

Handy local exception class

During my exception exploration I came to such conclusion, within local local exception class is sometime handy to have both input parameters, at first message with all its attributes or simple string. Below class fulfill both cases. Below exception class have two optional input parameters, so it's up to programmer what to choose. See below usage examples.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor
      IMPORTING
        iv_text     TYPE clike       OPTIONAL  " simple text input
        is_t100_key TYPE scx_t100key OPTIONAL" message input
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).

    " simple string input
    IF iv_text IS NOT INITIAL.
      cl_message_helper=>set_msg_vars_for_clikeiv_text ).
      if_t100_message~t100key-attr1 sy-msgv1.
      if_t100_message~t100key-attr2 sy-msgv2.
      if_t100_message~t100key-attr3 sy-msgv3.
      if_t100_message~t100key-attr4 sy-msgv4.
    ENDIF.

    " message input
    IF is_t100_key IS NOT INITIAL.
      MOVE-CORRESPONDING is_t100_key TO if_t100_message~t100key.
    ENDIF.

    " special cases
    IF if_t100_message~t100key-msgid IS INITIAL )
      AND  if_t100_message~t100key-msgno IS INITIAL )
      AND  if_t100_message~t100key-attr1 IS NOT INITIAL ).
      if_t100_message~t100key-msgid '00'.
      if_t100_message~t100key-msgno '001'.
    ENDIF.

    " set message attributes
    msgv1 if_t100_message~t100key-attr1.
    msgv2 if_t100_message~t100key-attr2.
    msgv3 if_t100_message~t100key-attr3.
    msgv4 if_t100_message~t100key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.

  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg  TYPE scx_t100key.

* example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

* example 3 - simple error text message
  DATAlv_text TYPE string.
  TRY.
      " ...some coding raising custom exception
      lv_text 'Some ugly error occcured in program 1! Some stupid error occcured in program 2! Some silly error occcured in program 3!'.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          iv_text lv_text.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

Wednesday, July 2, 2014

Local Exception class & Message


Once I decided to a bit improve my simple custom exception object and equip it with message attributes. I needed local class not global one where you can just click checkbox "With message class". Many functions within SAP works with return attributes like sy-msgv1, sy-msgv2... as e.g. function module 'ENQUEUE_EVVBLKE'. Messages are well designed for this purpose. So why to discover wheel once again.

Note: For final solution roll down till the end :)

I knew exceptions and messages work with interface if_t100_message. I read some articles on net, I looked at James Wood book.  The closest one was on Naimesh Patel site. Btw this site is always helpful.

What I looked for was this, just one filled structure scx_t100key as constructor parameter and nothing else. I did not want to use inside the exception class hardcoded constants with prepared messages key/text.

At first I tried below simple solution

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
     INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


The usage:


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg TYPE scx_t100key.

* test example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* test example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

OK, it's pretty easy, everything looks very well unless you do not try to involve attributes 1-4 of the message. If you do so, it looks strange. Attributes are placed at proper places but surrounded by ampersand characters '&'. Ouu, it does not look very well. Hmm, what to do now?



I debugged the part of SAP code responsible for displaying the message and discovered what's wrong.

There is used below method of the class CL_MESSAGE_HELPER.

SET_MSG_VARS_FOR_IF_T100_MSG (CL_MESSAGE_HELPER)
    CALL METHOD set_single_msg_var
      EXPORTING
        arg    = text->t100key-attr1
        obj    = text
      IMPORTING
        target = sy-msgv1.

The wrong thing is done inside the method  SET_SINGLE_MSG_VAR (CL_MESSAGE_HELPER).



I realized, it looks just for exception attribute inside the class and nothing else. It's pretty clear, that below code would not work any more. There is no attribute named with the vbeln number or username.

Working sample code


Finally I did small modification of my exception class to destroy unwanted ampersands. And voila, it works! Look at the below code.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
    msgv1 is_t100_key-attr1.
    msgv2 is_t100_key-attr2.
    msgv3 is_t100_key-attr3.
    msgv4 is_t100_key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


Now the result looks as follows.