Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Thomas_Uhrig
Explorer
554

Hi community,

I would like to share with you some functionality I used in my last S/4HANA 2022 Assetmanagement Project to prevent the WDA-App for maintaining orders (EAMS_WDA_ORDNTF_OIF) to lead to an error-page after occuring of an exception in UserExit or BADI during saving of the order.

When using the WebDynpro-App EAMS_WDA_ORDNTF_OIF (Maintain PM-Order) - raising an exception or sending an error-message
in UserExit IWO10009 "PM Order: Customer check for 'Save' Event"
or
in BADI WORKORDER_UPDATE Methode AT_SAVE
is a showstopper and will lead the user to an "Error-Page", not allowing to come back and work on the same data. Instead, all changes the user made are lost and the user has to start the app from the beginning:

ok_01 Auftrag ändern - WebDynpro - Error-Page(AT_SAVE)(Fake-Nachrichten)(SWD)_angepasst.jpg

 (This issue was told to SAP, but we got a negative answer and the problem seems not to be resolved in near time.)
For more information and the reason for this behavior you can read the comments in attachement "IWO10009_sample.txt" of SAP-Note "3092671 - Customer ConnectionImprovement Request D9817 - Implementation Example for User Exit IWO10009".

 

In SAPgui and WebGui, when an error occurred during saving of an order, we are used to come back to the app, being able to correct our entries.
The challenge was to find a workaround, to get the same behavior in the WebDynpro-App:

When saving an order in WDA, the method CALL_TRANSACTION_SAVE of the FloorPlanManager (Class CL_FPM) is called. It is devided into two parts:

ok_02 WebDynpro - CALL_TRANSACTION_SAVE of FloorPlanManager(Class CL_FPM).jpg

First part: Standard-checks, making certain, that data is consistent.
Second part: Saving the order: BAPI "BAPI_ALM_ORDER_MAINTAIN" is called with method SAVE, that is calling UserExit IWO10009 and BADI WORKORDER_UPDATE Methode AT_SAVE. But this point is too late to come back to WDA-App, if a check fails.

Somewhere in or between these two parts, there is the "Point-Of-No-Return". If this is passed, a come back to the WDA-App is not possible:

ok_03 Übersichtsbild WDA SAVE.ppt.jpg

 

So the idea is, to additionally implement the customer own checks within the first part.
Therefor the method CHECK_BEFORE_SAVE of class CL_EAMS_BO_ORDER seems to be the right one.
We added a small enhancement there at the end:

 

ok_04 CL_EAMS_BO_ORDER~CHECK_BEFORE_SAVE --- ENH.jpg

We decided to call here (inside the enhancement-method) the UserExit IWO10009 and BADI WORKORDER_UPDATE Methode AT_SAVE in general.
We wanted to have the same logic and checks in all UIs and a central message-handling in the UserExits and BADIs.
(It would also be possible, to call here just the UserExit or the BADI only or only one BADI-Implementation or even only a special method with custom specific checks.)


Occuring Messages have to be given back from the enhancement to the caller through exporting-parameter ET_MESSAGE of method CHECK_BEFORE_SAVE.

 

Here is the complete idea in steps:

  1. Create a custom class, e.g. "ZNIBADISEXITS".
  2. Within this class create a global attribut 'GT_RETURN' type bapirettab for passing the occuring messages from the UserExit and BADI to the WDA-App. 
    ok_05 Globales Attribut 'GT_RETURN' in Klasse ZNIBADISEXITS.JPG
  3. Create the following methods in your class, e.g. "ZNIBADISEXITS":
    • ENH_EAMSORDER__CHCKBEFSAVE_END (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    MIT_NODE_DATA TYPE EAMS_T_BO_ORD_HEADER
*"  Changing
*"    MCT_MESSAGE TYPE /PLMB/T_SPI_MSG
*"----------------------------------------------------------------------

  METHOD enh_eamsorder__chckbefsave_end.
* Aufruf in CL_EAMS_BO_ORDER~CHECK_BEFORE_SAVE (Ende):
* Beim Sichern in der WebDynpro-Applikation zur Auftragsbearbeitung
* VOR Aufruf der Sicherungsroutinen.
* Funktionsweise:
* Aufruf des UserExits und des BADIs beim Sichern,
* um dortige kundeneigenen Prüfungsroutinen VOR und nicht erst
* innerhalb der Sicherungsroutinen auszuführen.
* Fehlernachrichten können somit noch an die Applikation gereicht werden,
* ohne dass diese abbricht (auf die Error-Page führt). Benutzer können
* dadurch ihre eingegebenen Daten noch korrigieren und erneut sichern.

    DATA: lt_caufvdb_new TYPE STANDARD TABLE OF caufvdb.
    DATA: lt_caufvdb_old TYPE STANDARD TABLE OF caufvdb.
    DATA: ls_caufvd_new  TYPE caufvd.
    DATA: ls_caufvd_old  TYPE caufvd.
    DATA: lv_trtyp       TYPE tc10-trtyp.
    DATA: lv_subrc       TYPE sy-subrc.
    DATA: lt_message     TYPE /plmb/t_spi_msg.

    FIELD-SYMBOLS <ls_node_data>     LIKE LINE OF mit_node_data.
    FIELD-SYMBOLS: <ls_caufvdb_new>  LIKE LINE OF lt_caufvdb_new.
    FIELD-SYMBOLS: <ls_caufvdb_old>  LIKE LINE OF lt_caufvdb_old.

***--- Aufträge aus Belegtabellen einlesen
    cl_co_fm_access_factory=>cobh( )->co_bh_caufv_bt_fetch(
      IMPORTING
        et_caufv_bt     = lt_caufvdb_new
        et_caufv_bt_old = lt_caufvdb_old ).

***--- Auftragsweise Abarbeitung
    LOOP AT mit_node_data ASSIGNING <ls_node_data>.
**-- Aktuelle Auftragsdaten lesen
      READ TABLE lt_caufvdb_new ASSIGNING <ls_caufvdb_new> WITH KEY aufnr = <ls_node_data>-eams_aufnr.
      CHECK: sy-subrc IS INITIAL AND ( <ls_caufvdb_new>-vbkz = 'U' OR <ls_caufvdb_new>-vbkz = 'I' ).
      MOVE-CORRESPONDING <ls_caufvdb_new> TO ls_caufvd_new.
**-- "Alte" Auftragsdaten einlesen, falls vorhanden
      READ TABLE lt_caufvdb_old ASSIGNING <ls_caufvdb_old> WITH KEY aufnr = <ls_node_data>-eams_aufnr.
      IF sy-subrc IS INITIAL.
        MOVE-CORRESPONDING <ls_caufvdb_old> TO ls_caufvd_old.
      ELSE.
        MOVE-CORRESPONDING <ls_caufvdb_new> TO ls_caufvd_old.
      ENDIF.
**-- Bestimmung des Transaktionstyps je Auftrag aus dem Verbuchungskennzeichen
      CASE <ls_caufvdb_new>-vbkz.
        WHEN 'I'.
          lv_trtyp = 'H'.
        WHEN 'U'.
          lv_trtyp = 'V'.
      ENDCASE.
**-- Aufruf "UserExit beim Sichern"
      PERFORM user_exits_save IN PROGRAM saplcoih USING ls_caufvd_new ls_caufvd_old lv_trtyp lv_subrc.
*- Nachrichtenverarbeitung aus UserExit
      IF lv_subrc IS NOT INITIAL.
        CLEAR: lt_message.
        /plmb/cl_spi_appl_access_utils=>add_syst_message(
          CHANGING
            ct_message = lt_message ).
        APPEND LINES OF lt_message TO mct_message.
          CLEAR: lt_message.
          lt_message = znibadisexits=>glob_mess_give_2_spi( EXPORTING miv_do_init = 'X' ).
          APPEND LINES OF lt_message TO mct_message.
      ENDIF.
**-- Aufruf BADI "WORKORDER_UPDATE" Methode AT_SAVE
      DATA: lp_badi_if TYPE REF TO if_ex_workorder_update.
      CALL FUNCTION 'CO_BADI_GET_BUSINESS_ADD_IN'
        EXPORTING
          i_badi_name     = 'WORKORDER_UPDATE'
        CHANGING
          c_badi_instance = lp_badi_if
        EXCEPTIONS
          not_active      = 1
          OTHERS          = 2.
      IF sy-subrc IS INITIAL.
        CALL METHOD lp_badi_if->at_save
          EXPORTING
            is_header_dialog   = ls_caufvd_new
          EXCEPTIONS
            error_with_message = 1
            OTHERS             = 2.
*- Nachrichtenverarbeitung aus BADI
        IF sy-subrc <> 0.
          CLEAR: lt_message.
          /plmb/cl_spi_appl_access_utils=>add_syst_message(
            CHANGING
              ct_message = lt_message ).
          APPEND LINES OF lt_message TO mct_message.
          CLEAR: lt_message.
          lt_message = znibadisexits=>glob_mess_give_2_spi( EXPORTING miv_do_init = 'X' ).
          APPEND LINES OF lt_message TO mct_message.
        ENDIF.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.​
  • GLOB_MESS_GIVE_2_SPI  (Static and Protected)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    MIV_DO_INIT TYPE FLAG
*"  Returning
*"     VALUE(MRT_MESSAGES_SPI) TYPE /PLMB/T_SPI_MSG
*"----------------------------------------------------------------------

  METHOD GLOB_MESS_GIVE_2_SPI.

    DATA: lt_message TYPE /plmb/t_spi_msg.

    FIELD-SYMBOLS: <fs_s_return> LIKE LINE OF gt_return.

    LOOP AT gt_return ASSIGNING <fs_s_return>.
      MESSAGE ID <fs_s_return>-id TYPE <fs_s_return>-type NUMBER <fs_s_return>-number
      WITH <fs_s_return>-message_v1 <fs_s_return>-message_v2
           <fs_s_return>-message_v3 <fs_s_return>-message_v4
      INTO sy-lisel.
      /plmb/cl_spi_appl_access_utils=>add_syst_message(
        EXPORTING
          iv_msg_index = <fs_s_return>-row
          iv_fieldname = <fs_s_return>-field
        CHANGING
          ct_message   = lt_message ).
    ENDLOOP.

    APPEND LINES OF lt_message TO mrt_messages_spi.

    CHECK: miv_do_init IS NOT INITIAL.
    CLEAR: gt_return.

  ENDMETHOD.​
  • ORDER_MESS_SHOW  (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    MIT_RETURN TYPE BAPIRETTAB
*"----------------------------------------------------------------------

  METHOD ORDER_MESS_SHOW.

    FIELD-SYMBOLS: <fs_v_log_handle> TYPE balloghndl.
    FIELD-SYMBOLS: <fs_s_return> TYPE bapiret2.

    DATA: ls_keys_order TYPE cno1keys.

*- Nur wenn Nachrichten auszugeben sind
    CHECK: mit_return IS NOT INITIAL.

*- GUI-Typ ermitteln
    DATA(ls_gui) = znibadisexits=>xx_get_ui_type( ).
*- Wenn Order-BAPI aktiv ist, geht dessen Message-Handling vor, egal welcher GUI-Typ!
    CALL FUNCTION 'IBAPI_Z_GET_BAPI_FLAG'
      EXCEPTIONS
        bapi_active     = 1
        bapi_not_active = 2
        OTHERS          = 3.
    IF sy-subrc = 1.
      ls_gui-name = 'BAPI'.
    ENDIF.

    CASE ls_gui-name.
      WHEN 'WGU' OR 'HGU' OR 'BAT'.
        znibadisexits=>xx_mess_show_gui(
          EXPORTING
            mit_return = mit_return ).

      WHEN 'WDA' OR 'ODA' OR 'BSP' OR 'BAPI'.
***--- Prüfungen
*- Prüfen, ob Order-BAPI aktiv ist
        CALL FUNCTION 'IBAPI_Z_GET_BAPI_FLAG' "muss hier erneut geprüft werden,
          EXCEPTIONS                          "da ENH CHECK_BEFORE_SAVE für WebDynpro
            bapi_active     = 1               "außerhalb des BAPIs läuft.
            bapi_not_active = 2               "Dort wird dann gt_return mit Methode
            OTHERS          = 3.              "GLOB_MESS_GIVE_2_SPI genutzt.
        IF sy-subrc = 1.
*- Prüfen, ob Message-Handling des BAPIs aktiv ist
          ASSIGN ('(SAPLIBAPI_Z)GV_LOG_HANDLE') TO <fs_v_log_handle>.
          IF sy-subrc IS INITIAL AND <fs_v_log_handle> IS NOT INITIAL.
***--- Ausführung
*- Übergeben der Messages aus SYST an das Appl.Log des BAPIs
            LOOP AT mit_return ASSIGNING <fs_s_return>.
              CLEAR: ls_keys_order.
              IF <fs_s_return>-parameter IS NOT INITIAL.
                IF <fs_s_return>-parameter(4) = 'AUFK'.
                  ls_keys_order = <fs_s_return>-parameter+4.
                ENDIF.
              ENDIF.
              MESSAGE ID <fs_s_return>-id TYPE <fs_s_return>-type NUMBER <fs_s_return>-number
              WITH <fs_s_return>-message_v1 <fs_s_return>-message_v2
                   <fs_s_return>-message_v3 <fs_s_return>-message_v4
              INTO sy-lisel.
              CALL FUNCTION 'IBAPI_Z_MSG_STORE'
                EXPORTING
                  iv_aufnr = ls_keys_order-aufnr
                  iv_vornr = ls_keys_order-activity
                  iv_uvorn = ls_keys_order-sub_activity
                  iv_repid = sy-repid.
            ENDLOOP.
          ENDIF.
        ENDIF.
        IF <fs_v_log_handle> IS NOT ASSIGNED.      "BAPI-Flag ist nicht aktiv oder LOG_HANDLE war nicht gesetzt
          APPEND LINES OF mit_return TO gt_return. "=> Nachrichten global speichern, können dann abgeholt werden,
        ENDIF.                                     " z.B. bzw. siehe Methode GLOB_MESS_GIVE_2_SPI

      WHEN 'BNP'.
        LOOP AT mit_return ASSIGNING <fs_s_return>.
          MESSAGE ID <fs_s_return>-id TYPE <fs_s_return>-type NUMBER <fs_s_return>-number
          WITH <fs_s_return>-message_v1 <fs_s_return>-message_v2
               <fs_s_return>-message_v3 <fs_s_return>-message_v4.
        ENDLOOP.

      WHEN OTHERS.
    ENDCASE.

  ENDMETHOD.​
  • XX_GET_UI_TYPE  (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Returning
*"     VALUE(MES_GUI) TYPE IHTTPNVP
*"----------------------------------------------------------------------

  METHOD xx_get_ui_type.

*-- HGU - Html SAP GUI
    DATA: lv_its_active TYPE flag.
    CALL FUNCTION 'GUI_IS_ITS'
      IMPORTING
        return = lv_its_active.
    IF lv_its_active IS NOT INITIAL.
      mes_gui-name  = 'HGU'.
      mes_gui-value = 'Html SAP GUI' ##NO_TEXT.
      RETURN.
    ENDIF.

*- BatchInput (muss vor WGU stehen!)
    IF sy-binpt IS NOT INITIAL.
      mes_gui-name  = 'BNP'.
      mes_gui-value = 'BatchInput' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- WGU - Windows SAP GUI
    DATA: lv_gui_active TYPE flag.
    CALL FUNCTION 'GUI_IS_AVAILABLE'
      IMPORTING
        return = lv_gui_active.
    IF lv_gui_active IS NOT INITIAL.
      mes_gui-name  = 'WGU'.
      mes_gui-value = 'Windows SAP GUI' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- BSP - Business Server Pages
    DATA(lr_bsp_server) = cl_bsp_runtime=>if_bsp_runtime~server.
    IF lr_bsp_server IS BOUND.
      mes_gui-name  = 'BSP'.
      mes_gui-value = 'Business Server Pages' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- WDA - WebDynpro for ABAP
    DATA(lr_wd_server) = wdr_task=>server.
    IF lr_wd_server IS BOUND.
      mes_gui-name  = 'WDA'.
      mes_gui-value = 'WebDynpro ABAP' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- ODA - oData (Fiori, ...)
    DATA(lo_batch_helper) = /iwfnd/cl_mgw_batch_helper=>get_batch_helper( ). "wird angelegt, wenn nicht aktiv!
    lo_batch_helper->batch_get_service_name_version(                         "Daher keine Prüfung 'IS BOUND'nötig
      IMPORTING
        ev_service_name    = DATA(lv_service_name)
        ev_service_version = DATA(lv_service_version)
    ).
    IF lv_service_name IS NOT INITIAL.
      mes_gui-name  = 'ODA'.
      mes_gui-value = 'oData (Fiori, ...)' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- Hintergrundverarbeitung (Job/...)
    IF sy-batch IS NOT INITIAL.
      mes_gui-name  = 'BAT'.
      mes_gui-value = 'batch / background' ##NO_TEXT.
      RETURN.
    ENDIF.

*-- damit Exporting-Parameter immer gefüllt ist und mit Offset(3) abgefragt werden kann
    mes_gui-name  = 'OTH'.
    mes_gui-value = 'others / unknown' ##NO_TEXT.

  ENDMETHOD.​
  • XX_MESS_SHOW_GUI  (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    MIT_RETURN TYPE BAPIRETTAB
*"----------------------------------------------------------------------

  METHOD xx_mess_show_gui.

    DATA: lv_mess_ident TYPE sy-uzeit.

    FIELD-SYMBOLS: <fs_s_return> TYPE bapiret2.
    FIELD-SYMBOLS: <fs_v_ident>  TYPE sy-uzeit.

***--- StartChecks
*- Nur wenn Nachrichten auszugeben sind
    CHECK: mit_return IS NOT INITIAL.
*- Nicht bei BatchInput
    CHECK: sy-binpt IS INITIAL.
*- GUI-Typ ermitteln -> Nur bei WinGUI und HtmlGUI Nachrichten hier anzeigen.
    DATA(ls_gui) = znibadisexits=>xx_get_ui_type( ).
    CHECK: ls_gui-name = 'WGU' OR ls_gui-name = 'HGU' OR ls_gui-name = 'BAT'.

***--- Preparation
*- Prüfen, ob Message-Handler bereits aktiv ist
    CALL FUNCTION 'MESSAGES_ACTIVE'
      EXCEPTIONS
        not_active = 1
        OTHERS     = 2.
    IF sy-subrc <> 0.
      ASSIGN ('(SAPLSMSG)GD_IDENT') TO <fs_v_ident>.
      IF sy-subrc IS INITIAL.
        lv_mess_ident = <fs_v_ident>.
      ENDIF.
*- Message-Handler ggf. aktivieren
      CALL FUNCTION 'MESSAGES_INITIALIZE'
        EXPORTING
          i_store_duplicates    = 'X'
          i_identification      = lv_mess_ident
          i_allow_foreign_reset = 'X'
        IMPORTING
          e_identification      = lv_mess_ident
        EXCEPTIONS
          log_not_active        = 1
          wrong_identification  = 2
          OTHERS                = 0.
      IF sy-subrc <> 0.
*        nothing to do here
      ENDIF.
    ENDIF.

***--- Execution
*- Message an Message-Handler geben
    LOOP AT mit_return ASSIGNING <fs_s_return>.
      CALL FUNCTION 'MESSAGE_STORE'
        EXPORTING
          arbgb                   = <fs_s_return>-id
          exception_if_not_active = ' '
          msgty                   = <fs_s_return>-type
          msgv1                   = <fs_s_return>-message_v1
          msgv2                   = <fs_s_return>-message_v2
          msgv3                   = <fs_s_return>-message_v3
          msgv4                   = <fs_s_return>-message_v4
          txtnr                   = <fs_s_return>-number
        EXCEPTIONS
          message_type_not_valid  = 1
          not_active              = 2
          OTHERS                  = 3.
      IF sy-subrc <> 0.
*        nothing to do here
      ENDIF.
    ENDLOOP.
*- Messages ausgeben
    CALL FUNCTION 'MESSAGES_SHOW'
      EXCEPTIONS
        inconsistent_range = 1
        no_messages        = 2
        OTHERS             = 3.
    IF sy-subrc <> 0.
*        nothing to do here
    ENDIF.

***--- PostProcessing
*- Sammeln von Nachrichten beenden
    IF lv_mess_ident IS NOT INITIAL.
      CALL FUNCTION 'MESSAGES_STOP'
        EXPORTING
          i_identification  = lv_mess_ident
          i_reset_messages  = 'X'
        EXCEPTIONS
          a_message         = 1
          e_message         = 2
          w_message         = 3
          i_message         = 4
          s_message         = 5
          deactivated_by_md = 6
          OTHERS            = 7.
      IF sy-subrc <> 0.
*        nothing to do here
      ENDIF.
    ENDIF.

  ENDMETHOD.​
  • BADI_WUPD__AT_SAVE  (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Changing
*"    MCS_CAUFVD TYPE CAUFVD
*"  Exception 
*"    ERROR_WITH_MESSAGE
*"----------------------------------------------------------------------

  METHOD badi_wupd__at_save.
DATA: lt_return TYPE bapirettab.


* ...
* Implement your custom checks here and collect messages in table lt_return,
* you can use CALL FUNCTION 'BALW_BAPIRETURN_GET2' ... to do that.
* ...


**-- Message-Handling
    znibadisexits=>order_mess_show( EXPORTING mit_return = lt_return ).
    TRY.
        DATA(ls_return) = lt_return[ type = 'E' ].
        MESSAGE e005(zli_iwoc) RAISING error_with_message.
*      "Beim Speichern wurde ein Fehler gefunden"
      CATCH cx_sy_itab_line_not_found.
    ENDTRY.

  ENDMETHOD.​
  • USEREXIT_IWO10009 (Static and Public)
*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    MIS_CAUFVD TYPE CAUFVD
*"    MIV_TRTYP TYPE TRTYP
*"  Changing
*"    MCV_RELEASE_ORDER TYPE XFLAG
*"  Exception
*"    ERROR_WITH_MESSAGE 
*"----------------------------------------------------------------------

  METHOD userexit_iwo10009.
    DATA:       lt_return TYPE bapirettab.


* ...
* Implement your custom checks here and collect messages in table lt_return,
* you can use CALL FUNCTION 'BALW_BAPIRETURN_GET2' ... to do that.
* ...


*- Nachrichten- und Ausnahmen-Handling
    znibadisexits=>order_mess_show( EXPORTING mit_return = lt_return ).
    IF line_exists( lt_return[ type = 'E' ] ).
      CHECK: mis_caufvd-abruf_flag IS INITIAL AND ( mis_caufvd-wo_flag IS INITIAL OR miv_trtyp = 'V' ).
      MESSAGE e084(iw) RAISING error_with_message.
*     "Der Auftrag soll nicht gesichert werden (festgelegt durch Customer-Exit)"
    ENDIF.
  ENDMETHOD.​

 

Additionally implement the following:

  • Implement Include ZXWOCU07 (UserExit IWO10009)
*&---------------------------------------------------------------------*
*& Include          ZXWOCU07
*&---------------------------------------------------------------------*
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     VALUE(CAUFVD_IMP) LIKE  CAUFVD STRUCTURE  CAUFVD
*"     VALUE(TRTYP) LIKE  TC10-TRTYP
*"  EXPORTING
*"     REFERENCE(RELEASE_ORDER) TYPE  XFLAG
*"----------------------------------------------------------------------
znibadisexits=>userexit_iwo10009( EXPORTING  mis_caufvd         = caufvd_imp
                                             miv_trtyp          = trtyp
                                  CHANGING   mcv_release_order  = release_order
                                  EXCEPTIONS error_with_message = 1
                                             OTHERS             = 2 ).
IF sy-subrc <> 0.
  IF sy-msgid IS NOT INITIAL AND sy-msgty IS NOT INITIAL.
    RAISE error_with_message.
  ELSE.
    MESSAGE e079(iw) RAISING error_with_message.
*     "Sichern wurde vom System zurückgewiesen"
  ENDIF.
ENDIF.​
  • Implement Method IF_EX_WORKORDER_UPDATE~AT_SAVE in your own Implementation of BADI WORKORDER_UPDATE.
  METHOD if_ex_workorder_update~at_save.
*@78\QImporting@	IS_HEADER_DIALOG	TYPE COBAI_S_HEADER_DIALOG	Auftragskopf in Dialogstruktur
*@03\QException@	ERROR_WITH_MESSAGE		Fehlermeldung aufgetreten

    DATA: ls_caufvd TYPE caufvd.

    MOVE-CORRESPONDING is_header_dialog TO ls_caufvd.

    znibadisexits=>badi_wupd__at_save(
      CHANGING
        mcs_caufvd         = ls_caufvd
      EXCEPTIONS
        error_with_message = 1
        OTHERS             = 2 ).
    IF sy-subrc <> 0.
      IF sy-msgid IS NOT INITIAL AND sy-msgty IS NOT INITIAL.
        RAISE error_with_message.
      ELSE.
        MESSAGE e079(iw) RAISING error_with_message.
*       "Sichern wurde vom System zurückgewiesen"
      ENDIF.
    ENDIF.

  ENDMETHOD.​
  • Implement an enhancement at the end of Method CHECK_BEFORE_SAVE of class CL_EAMS_BO_ORDER
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""$"$\SE:(1) Klasse CL_EAMS_BO_ORDER, Methode CHECK_BEFORE_SAVE, Ende                                                                                          A
*$*$-Start: (1)---------------------------------------------------------------------------------$*$*
ENHANCEMENT 1  ZNIEAMSORDER_CHECKBEFSAVE.    "active version
    znibadisexits=>enh_eamsorder__chckbefsave_end(
      EXPORTING
        mit_node_data = lt_node_data
      CHANGING
        mct_message   = et_message ).
ENDENHANCEMENT.
*$*$-End:   (1)---------------------------------------------------------------------------------$*$*
​

 

As a result, when errors occur during saving of an order in WDA, the user is led back to the WDA-App and the messages are displayed:

ok_06 Auftrag ändern - WebDynpro - Fehlerprotokoll(ENH AT_SAVE)(Fake-Nachrichten)(SWD)_angepasst.jpg

 The UserExit and the BADI are now called once within the first part of saving (before POINT OF NO RETURN) by custom logic and once after it by SAP-Standard logic:

ok_06 Übersichtsbild WDA SAVE.ppt(nach Lösungsimplementierung).jpg

 


Important point:
As we decided later, not to use WDA-Apps in productive system at all due to several reasons, this solution is not deeply testet, yet.
Please be careful and check each and every step to meet your requirements.

Another important point:
Due to SAP-Note 3092671, it is possible, to change the order within UserExit IWO10009 during saving by using function modules IBAPI_.... . If you already do that and as this UserExit and BADI WORKORDER_UPDATE~AT_SAVE are now passed at least two times during one save from WDA, you should carefully review your custom logic regarding this. 

 

Here are two articles I wrote some time ago regarding two methods that I use above:

"How to identify the actually used UserInterface Technology from ABAP"
https://community.sap.com/t5/blogs/blogworkflowpage/blog-id/technology-blog-members/article-id/16695...

"How to pass multiple messages from ABAP (Exit/BADI) to the UserInterfaces in S/4HANA-Assetmanagement"
https://community.sap.com/t5/blogs/blogworkflowpage/blog-id/technology-blog-members/article-id/16695...

Maybe these articles are of interest for you, too.

1 Comment
stephan_bantlin
Product and Topic Expert
Product and Topic Expert
0 Likes

Hello Thomas,

thanks a lot for providing this level of detail, thanks for the effort to list all this in detail.
This helps a lot  to understand how you achieved a beahviour change in the message handling, how you determine which UI is used etc.
best regards

Stephan