Showing posts with label function modules. Show all posts
Showing posts with label function modules. Show all posts

Wednesday, March 21, 2012

Update service in quotation document (RFQ)

A quotation document can have service lines instead of normal material lines. It is an external component of the document, here we will see how to update service line.

The functionality for managing services is in the function group MLSP. How service is integrated is described here.

These are following steps to update service line:

  1. Read service data in internal table of the function group. This is achieved by function module MS_GET_SERVICES.
  2. Set data in the internal table by calling function module MS_FILL_TABS_FROM_EXT_DATA and MS_CHANGE_SERVICE_PACKAGE.
  3. After that save by calling MS_SAVE_SERVICE_PACKAGE.

The function call requires communication structure COMSRV. This can be filled from the structure EKKO and EKPO. It is important that COMSRV-REF_BSTYP is set to ‘C’ (change). Refer function module BAPI_PO_CHANGE.

Friday, May 01, 2009

ALV Report: Show selection option

In previous post I mentioned about the function modules that can be used to display the selection options on the header of the report. Here I am going to give an example of the actual use of these function modules. I am going to start with the ALV report template that I have mentioned. I will be creating a private method to the class LCL_REPORT called BUILD_HEADER. This can display the header in either ALV or normal list output. I am going to read the KNA1 table and display the address of the customers. BTW there is a very good FM that will show the address if you pass the address number to it, the address is returned in a format that can be printed on a label. The function module is ADDRESS_INTO_PRINTFORM.

The class CL_SALV_FORM_LAYOUT_GRID will be used to define the layout and will be attached to the ALV object (class CL_SALV_TABLE) as top of list element. The function module that does the main work for us here is PRINT_SELECTIONS. It will return a table filed with preformatted lines. Here is screen shot of the table values from the debugger.

image

Now all we have to do is strip out unwanted lines and match the label against the values. The class CL_SALV_FORM_LAYOUT_GRID has 2 methods for this label and text creation, which are used in this case.

The selection screen of the report is:

image

In a list output it looks like this:

image

And in ALV output it looks like this.

image

Declaration of the method BUILD_HEADER:

    METHODS:
      build_header IMPORTING i_alv_table TYPE REF TO cl_salv_table.


And the code for the method BUILD_HEADER:



  METHOD build_header.
    TYPES:
     BEGIN OF l_ty_info,
             flag(1),
             olength(1) TYPE x,
             line  TYPE infoline,
           END OF l_ty_info.
    DATA:
       l_t_info TYPE TABLE OF l_ty_info,
       l_s_info TYPE l_ty_info,
       l_row TYPE i,
       l_o_uie TYPE REF TO cl_salv_form_layout_grid,
       l_o_any TYPE REF TO object,
       l_selection_flag,
       l_label_flag,
       l_str_report_by TYPE string,
       l_flag_report_by TYPE boolean.
    IF sy-repi2 IS INITIAL.
      sy-repi2 = sy-repid.
    ENDIF.
    CREATE OBJECT l_o_uie.
    CALL METHOD l_o_uie->create_header_information
      EXPORTING
        row     = 1
        column  = 1
        text    = sy-title
      RECEIVING
        r_value = l_o_any.
    CALL FUNCTION 'PRINT_SELECTIONS'
      EXPORTING
        rname     = sy-repi2
        rvariante = sy-slset
        mode      = 'TABLE'
      TABLES
        infotab   = l_t_info.
    DELETE l_t_info WHERE LINE = c_last_line.
    DELETE l_t_info WHERE LINE IS INITIAL.
    LOOP AT l_t_info INTO l_s_info.
      IF l_s_info-line+1(77) = c_last_line.
        EXIT.
      ENDIF.
      IF l_s_info-flag = 'D'.     " prg run Date and time
        l_row = sy-tabix.
        CALL METHOD l_o_uie->create_label
          EXPORTING
            row     = l_row
            column  = 1
            text    = l_s_info-line+1(77)
          RECEIVING
            r_value = l_o_any.
        l_row = l_row + 1.
        CALL METHOD l_o_uie->create_label
          EXPORTING
            row     = l_row
            column  = 1
            text    = c_last_line+1(20)
          RECEIVING
            r_value = l_o_any.
      ENDIF.
      IF l_s_info-flag <> 'H'.     " Header not encountered so far
        IF l_selection_flag IS INITIAL. " Wait for it
          CONTINUE.
        ELSE.
*       write text
        ENDIF.
      ELSE.                  " We have header so set the flag
        l_selection_flag = abap_true. " Set the flag
        CONTINUE.            " Data is in the next line
      ENDIF.
      IF l_s_info-line+3(1) <> space. " This is the Label
        l_label_flag = abap_true.
        l_row  = l_row + 1.
        CONDENSE l_s_info-line+1(32).
        CALL METHOD l_o_uie->create_label
          EXPORTING
            row     = l_row
            column  = 1
*           colspan = 30
            text    = l_s_info-line+1(32)
          RECEIVING
            r_value = l_o_any.
        IF l_s_info-line+1(32) = 'Report by'.
          l_flag_report_by = abap_true.
        ENDIF.
      ELSE. " This is the Value
        IF l_label_flag = abap_true.
          l_label_flag = abap_false.
        ELSE.
          l_row = l_row + 1.
        ENDIF.
        CONDENSE l_s_info-line+1(77).
        IF l_flag_report_by = abap_true.
          l_s_info-line+1(77) = l_str_report_by.
          l_flag_report_by = abap_false.
        ENDIF.
        CALL METHOD l_o_uie->create_text
          EXPORTING
            row     = l_row
            column  = 2
            text    = l_s_info-line+1(77)
*    TOOLTIP =
          RECEIVING
            r_value = l_o_any
            .
      ENDIF.
    ENDLOOP.
    CALL METHOD l_o_uie->create_label
      EXPORTING
        row     = l_row
        column  = 1
        text    = c_last_line+1(20)
      RECEIVING
        r_value = l_o_any.
    CALL METHOD i_alv_table->set_top_of_list
      EXPORTING
        value = l_o_uie.
  ENDMETHOD.                    "build_header

Wednesday, April 22, 2009

Check delivery status

To check the delivery status of an order the following code can be used:

*Get all the schedule details by doing
SELECT * INTO TABLE xvbap FROM vbap
  WHERE vbeln = '7500000028'
  AND posnr = '000010'.
SELECT * INTO TABLE xvbup FROM vbup
  WHERE vbeln = '7500000028'
  AND posnr = '000010'.
SELECT * INTO TABLE xvbfa FROM vbfa
  WHERE vbelv = '7500000028'
  AND posnv = '000010'
  AND vbtyp_n = 'J'.
SELECT * INTO TABLE da_vbep FROM vbep
  WHERE vbeln = '7500000028'
  AND posnr = '000010'.
CALL FUNCTION 'RV_SCHEDULE_CHECK_DELIVERIES'
  EXPORTING
    fbeleg = '7500000028'
    fposnr = '000010'
* FVERRECHNUNG = ' '
* FS073_ALT = ' '
* IF_NO_SORT = ' '
  TABLES
    fvbfa = xvbfa
    fvbup = xvbup
    fxvbep = da_vbep
* FVBLB =
    fvbap = xvbap
  EXCEPTIONS
    fehler_bei_lesen_fvbup = 1
    fehler_bei_lesen_fxvbep = 2
  OTHERS = 3.

Monday, March 02, 2009

Date related function modules

There are function modules related to date functionality in the function groups SCA*

Friday, February 27, 2009

Post Inbound IDoc

Use the FM IDOC_WRITE_AND_START_INBOUND to post an inbound IDoc. Just build the EDIDD and EDIDC tables and enter a profile for a inbound message type from a partner. It returns a IDoc number. Don't forget to do commit work.

Sunday, June 10, 2007

Post an IDoc from file and display its status

Many a times third parties send their data in a file that will update for example a material master. For these scenarios we can use the standard IDoc to post data. IDoc gives us detailed messages as well a good logging feature and if something goes wrong we can reprocess them.

We will do this in the following steps:

  1. Read file
  2. Validate file
  3. Build IDoc
  4. Post IDoc
  5. Display log/IDoc status

Technically we will touch upon these things:

  1. Reading a file from PC
  2. Building an IDoc
  3. Posting an IDoc
  4. Building log messages
  5. Displaying log messages
  6. Tab strip
  7. Hotspot in an ALV

The file that comes in will be uploaded by the user from her local PC so we will give an option of F4 on file location. For this the code will be:

* F4
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  PERFORM open_file.


FORM open_file .
  DATA:
      l_t_file_table TYPE TABLE OF file_table,
      l_s_file_table TYPE file_table.
  CALL METHOD cl_gui_frontend_services=>file_open_dialog
    CHANGING
      file_table              = l_t_file_table
      rc                      = v_subrc
    EXCEPTIONS
      file_open_dialog_failed = 1
      cntl_error              = 2
      error_no_gui            = 3
      not_supported_by_gui    = 4
      OTHERS                  = 5.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
  READ TABLE l_t_file_table INTO l_s_file_table INDEX 1.
  p_file = l_s_file_table-filename.


Before we start let’s open a log handle to a log so that any errors or success messages can be recorded.



FORM open_log .
* create a log
  g_s_log-extnumber  = 'Application Log in Subscreen'(001).
  CALL FUNCTION 'BAL_LOG_CREATE'
    EXPORTING
      i_s_log      = g_s_log
    IMPORTING
      e_log_handle = g_log_handle
    EXCEPTIONS
      OTHERS       = 1.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
             WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
  INSERT g_log_handle INTO TABLE g_t_log_handle.
ENDFORM.                    " open_log


We will have procedure that will add the messages in the log, before calling the procedure a MESSAGE statement will set the system message variables.



FORM msg_add  USING value(i_log_handle) TYPE balloghndl.
  DATA:
    l_s_msg   TYPE bal_s_msg.
* define data of message for Application Log
  l_s_msg-msgty     = sy-msgty.
  l_s_msg-msgid     = sy-msgid.
  l_s_msg-msgno     = sy-msgno.
  l_s_msg-msgv1     = sy-msgv1.
  l_s_msg-msgv2     = sy-msgv2.
  l_s_msg-msgv3     = sy-msgv3.
  l_s_msg-msgv4     = sy-msgv4.
* add this message to log file
  CALL FUNCTION 'BAL_LOG_MSG_ADD'
    EXPORTING
      i_log_handle = i_log_handle
      i_s_msg      = l_s_msg
    EXCEPTIONS
      OTHERS       = 1.
  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.                    " msg_add


Read the file from PC.



FORM read_pc CHANGING l_subrc.
  v_filename = p_file.
  CALL METHOD cl_gui_frontend_services=>gui_upload
    EXPORTING
      filename                = v_filename
    CHANGING
      data_tab                = it_recs
    EXCEPTIONS
      file_open_error         = 1
      file_read_error         = 2
      no_batch                = 3
      gui_refuse_filetransfer = 4
      invalid_type            = 5
      no_authority            = 6
      unknown_error           = 7
      bad_data_format         = 8
      header_not_allowed      = 9
      separator_not_allowed   = 10
      header_too_long         = 11
      unknown_dp_error        = 12
      access_denied           = 13
      dp_out_of_memory        = 14
      disk_full               = 15
      dp_timeout              = 16
      not_supported_by_gui    = 17
      error_no_gui            = 18
      OTHERS                  = 19.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO g_dummy.
    PERFORM msg_add USING g_log_handle.
    l_subrc = sy-subrc.
  ELSE.
    MESSAGE s100 INTO g_dummy. " File opened successfully
    PERFORM msg_add USING g_log_handle.
    PERFORM delimited_file.
  ENDIF.
ENDFORM.                    "read_pc


After reading you might have your own checks on the file contents. e.g. material type is incorrect or if the mandatory values are not coming, etc. Once the checks are done it is time to build the IDoc. For each material in our case we will send one IDoc. The IDoc consists of a control part and data part. The control part tells SAP what type of IDoc is (definition) and what to do with the IDoc. The data part stores the data in different segments. Let’s see first how the control is made. The IDoc types will obviously be different for different scenarios.



* Control is of type EDIDC  
edidc-mandt  = sy-mandt. " Client
edidc-doctyp = 'MATMAS01'. " IDoc type
edidc-idoctp = 'MATMAS01'. " Basic Type
edidc-cimtyp = 'ZMATMAS01'. " Extension
edidc-direct = '2'. " Inbound
edidc-mestyp = 'MATMAS'. " Message Type
edidc-sndpor = 'DUMMY'. " Sender Port
edidc-sndprn = 'DUMMY'. " Sender partner
edidc-sndprt = 'LS'. " Partner type


Now that control record is done let’s see how the data part is done. The data is stored in the EDIDD structure. First move the relevant data in the structure for the relevant segment and then the segment is moved to the EDIDD structure. So this is done in two steps. We will see this in example of filling segment E1MARAM. The code will be something like this.



PERFORM fill_e1maram CHANGING s_e1maram.
PERFORM add_idoc_segment USING 'E1MARAM'
                               s_e1maram.


FORM fill_e1maram CHANGING ch_e1maram.
  ch_e1maram-xxxxx = yyyyyyy.
  .
  .
  .
ENDFORM.
FORM add_idoc_segment USING i_segnam i_sdata.
*
  CLEAR s_edidd.
  CHECK NOT i_sdata IS INITIAL.
  s_edidd-mandt  = sy-mandt.
  s_edidd-segnam = i_segnam.
  s_edidd-docnum = edidd-docnum.
  s_edidd-sdata  = i_sdata.
  APPEND s_edidd TO t_edidd.
ENDFORM.                    "ADD_IDOC_SEGMENT


Once one material information is entered we should call the function module to create the IDoc. Along with posting we will also store the IDoc number and its status in out output structure S_OUTPUT.



FORM create_idoc.
  CALL FUNCTION 'IDOC_WRITE_AND_START_INBOUND'
    EXPORTING
      i_edidc                             = edidc
   IMPORTING
     docnum                              = v_idoc_num
    TABLES
      i_edidd                             = t_edidd
   EXCEPTIONS
     idoc_not_saved                      = 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.
    PERFORM msg_add USING g_log_handle.
  ELSE.
    COMMIT WORK AND WAIT.
    s_output-docnum = v_idoc_num.
* Check to see if IDOC posted successfully
    SELECT SINGLE teds2~status descrp
      INTO (s_output-status, s_output-descrp)
      FROM edidc
      JOIN teds2 ON teds2~status = edidc~status
      WHERE docnum = v_idoc_num
      AND   langua = sy-langu.
* Put lights in the row
    SELECT SINGLE stalight INTO s_output-traffic_light
       FROM stacust
       JOIN stalight ON stalight~statva = stacust~statva
       WHERE status = s_output-status.
    CASE s_output-traffic_light.
      WHEN '1'.
*      move icon_yellow_light to hugo.
        s_output-traffic_light = 2.
      WHEN '2'.
*      move icon_green_light to hugo.
        s_output-traffic_light = 3.
      WHEN '3'.
*      move icon_red_light to hugo.
        s_output-traffic_light = 1.
    ENDCASE.
  ENDIF.
ENDFORM.                    "CREATE_IDOC


IDoc posting is done now lets show the user what happened. Over the course of opening the file and creating the IDoc we logging whatever happened so we want to show those messages as well as the IDoc posted. For this a tabbed screen appropriate so that user can have the details easy accessible. SAP has a very good demo of how to show logs in a tabbed subscreen in the program SBAL_DEMO_04_SUBSCREEN. That has been the basis of this program as well. So just looks at how the IDoc is displayed with a link to its application log. Our output structure is something like this:



image



The column CELL_TYPE can be used to define how a particular cell should behave in the ALV output. For IDoc number (DOCNUM) we want to be of type hotspot so the following will set it of that type.



* Make the IDoc of type link
  l_s_salv_t_int4_column-columnname = 'DOCNUM'.
  l_s_salv_t_int4_column-value = if_salv_c_cell_type=>hotspot.
  APPEND l_s_salv_t_int4_column TO l_t_salv_t_int4_column.
  s_output-cell_type = l_t_salv_t_int4_column.
  MODIFY t_output FROM s_output TRANSPORTING cell_type
    WHERE cell_type IS INITIAL.


Make the container and create the ALV table object.



* Create holder container
  CREATE OBJECT l_r_cust_cont
    EXPORTING           =
      container_name              = 'G_CUST_CONTROL'
    EXCEPTIONS
      cntl_error                  = 1
      cntl_system_error           = 2
      create_error                = 3
      lifetime_error              = 4
      lifetime_dynpro_dynpro_link = 5
      OTHERS                      = 6
      .
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
*--------------------------------------------------------------------*
* Create AVL table
  TRY.
      cl_salv_table=>factory(
        EXPORTING
          r_container = l_r_cust_cont
        IMPORTING
          r_salv_table = l_r_table
        CHANGING
          t_table      = t_output ).
    CATCH cx_salv_msg.                                  "#EC NO_HANDLER
  ENDTRY.


Set the column CELL_TYPE as a cell definition column and we also plan to show the status with some traffic lights.



* Columns
  DATA:
    lr_columns TYPE REF TO cl_salv_columns_table,
    lr_column TYPE REF TO cl_salv_column.
  lr_columns = l_r_table->get_columns( ).
  lr_columns->set_optimize( abap_true ).
  TRY.
      CALL METHOD lr_columns->set_exception_column
        EXPORTING
          value     = 'TRAFFIC_LIGHT'
          group     = '2'
          condensed = if_salv_c_bool_sap=>false.
    CATCH cx_salv_data_error .
  ENDTRY.
  TRY.
      CALL METHOD lr_columns->set_cell_type_column
        EXPORTING
          value = 'CELL_TYPE'.
    CATCH cx_salv_data_error .
  ENDTRY.


Define a event handler for the hotpot on IDoc number.



*--------------------------------------------------------------------*
* Events
  DATA:
    l_r_event_handler TYPE REF TO l_cl_event_handler,
    l_r_events TYPE REF TO cl_salv_events_table.
  l_r_events = l_r_table->get_event( ).
  CREATE OBJECT l_r_event_handler.
  SET HANDLER l_r_event_handler->on_link_click FOR l_r_events.


The handler for on_link_click event will be a local class.



CLASS l_cl_event_handler DEFINITION.
  PUBLIC SECTION.
    METHODS:
      on_link_click FOR EVENT link_click OF cl_salv_events_table
        IMPORTING row column.
  PRIVATE SECTION.
    METHODS:
      handle_idoc_click IMPORTING i_row TYPE salv_de_row.
ENDCLASS.                    "l_cl_event_handler DEFINITION


In the method handle_idoc_click we will read the IDoc messages that are written in SAP’s application log. The demo SBAL_DEMO_05 has some good examples to save logs in the database and read from it. We will use the POPUP profile of log to show the message for given IDoc.



CLASS l_cl_event_handler IMPLEMENTATION.
  METHOD on_link_click.
    CASE column.
      WHEN 'DOCNUM'.
        handle_idoc_click( EXPORTING i_row = row ).
      WHEN OTHERS.
    ENDCASE.
  ENDMETHOD.                    "on_click
  METHOD handle_idoc_click.
    DATA:
      l_s_object          TYPE bal_s_obj,
      l_s_extnumber       TYPE bal_s_extn,
      l_s_log_filter      TYPE bal_s_lfil,
      l_t_log_header      TYPE balhdr_t,
      l_s_display_profile TYPE bal_s_prof,
      l_s_log              TYPE bal_s_log,
      l_log_handle         TYPE balloghndl,
      l_t_log_handle       TYPE bal_t_logh,
      l_s_handle_filter    TYPE bal_s_logh,
      l_t_handle_filter    TYPE TABLE OF bal_s_logh.
* Don't show programs own log
    l_s_handle_filter-sign = 'E'.
    l_s_handle_filter-option = 'EQ'.
    l_s_handle_filter-low = g_log_handle.
    APPEND l_s_handle_filter TO l_t_handle_filter.
    l_s_log_filter-log_handle = l_t_handle_filter.
    READ TABLE t_output INTO s_output INDEX i_row.
*   create a filter with all relevant criteria:
    l_s_object-sign   = 'I'.
    l_s_object-option = 'EQ'.
    l_s_object-low    = 'MATU'.
    APPEND l_s_object TO l_s_log_filter-object.
    l_s_extnumber-sign   = 'I'.
    l_s_extnumber-option = 'EQ'.
    l_s_extnumber-low    = s_output-docnum.
    APPEND l_s_extnumber TO l_s_log_filter-extnumber.
*   search on DB for these logs
    CALL FUNCTION 'BAL_DB_SEARCH'
      EXPORTING
        i_s_log_filter = l_s_log_filter
      IMPORTING
        e_t_log_header = l_t_log_header
      EXCEPTIONS
        OTHERS         = 0.
*   load logs from DB
    CALL FUNCTION 'BAL_DB_LOAD'
      EXPORTING
        i_t_log_header = l_t_log_header
      EXCEPTIONS
        OTHERS         = 0.
* get a prepared profile
    CALL FUNCTION 'BAL_DSP_PROFILE_POPUP_GET'
      IMPORTING
        e_s_display_profile = l_s_display_profile
      EXCEPTIONS
        OTHERS              = 1.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.
    l_s_display_profile-disvariant-handle = 'LOG'.
    CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
     EXPORTING
       i_s_display_profile          = l_s_display_profile
       i_s_log_filter               = l_s_log_filter
     EXCEPTIONS
       profile_inconsistent         = 1
       internal_error               = 2
       no_data_available            = 3
       no_authority                 = 4
       OTHERS                       = 5.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE 'I' NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.
  ENDMETHOD.                    "handle_link_click
ENDCLASS.                    "l_cl_event_handler IMPLEMENTATION


The output will look something like this:



image