SAP Program/ABAP

SAP PO Multi 시 Ack 값 받아오기

유부사모 2017. 12. 1. 16:22

FUNCTION z_qm_if_lims_insp_type.
*"----------------------------------------------------------------------
*"*"Local interface:
*"  IMPORTING
*"     VALUE(I_DATE) TYPE  TAB_ISUR_DATUM OPTIONAL
*"     VALUE(I_SYSID) TYPE  STRING
*"  EXPORTING
*"     VALUE(E_RET) TYPE  ZIF_STATUS
*"     VALUE(E_MSG) TYPE  CHAR100
*"     VALUE(E_SCNT) TYPE  SATC_D_JOB_LIMIT_UPPER
*"     VALUE(E_ECNT) TYPE  SATC_D_JOB_LIMIT_UPPER
*"  TABLES
*"      LT_Z045 STRUCTURE  ZQMT_045
*"      LT_WERKS STRUCTURE  WERKS_RANG OPTIONAL
*"----------------------------------------------------------------------

  DATA lt_callstack TYPE sys_callst,
         ls_callstack LIKE LINE OF lt_callstack,
         lv_func_name TYPE dbglevent.


* 현재 function name 가져오기 시작
*** Get Stack
  CALL FUNCTION 'SYSTEM_CALLSTACK'
    EXPORTING
      max_level    0
    IMPORTING
      et_callstack lt_callstack.

  LOOP AT lt_callstack INTO ls_callstack
      WHERE eventtype 'FUNC'" Get Last FUNC Call
    EXIT.
  ENDLOOP.

*** Set Function Name
  lv_func_name ls_callstack-eventname.
* 현재 function name 가져오기 종료

  DATAls_z045      LIKE LINE OF lt_z045,
        lv_werks_set TYPE zqmt_045-werks,
        lv_werks     TYPE t001w-werks,
        ls_date      LIKE LINE OF i_date.


  DATABEGIN OF ls_cdhdr.
  DATA:
    tabkey   TYPE cdpos-tabkey,
    objectid TYPE cdpos-objectid,
    udate    TYPE cdhdr-udate,
    mpdau    TYPE qmat-mpdau.
  DATAEND OF ls_cdhdr,
  lt_cdhdr LIKE TABLE OF ls_cdhdr.

  DATABEGIN OF ls_coll.
  DATAart   TYPE qals-art,
        matnr TYPE qals-matnr,
        werks TYPE qals-werk,
        aktiv TYPE qmat-aktiv,
        mpdau TYPE qmat-mpdau,
        aedat TYPE cdhdr-udate.
  DATAEND OF ls_coll,
  lt_coll LIKE TABLE OF ls_coll.

  DATAgt_qmat TYPE TABLE OF zcl_dt_qm00820_serp_gt_qmat,
        gs_qmat LIKE LINE OF gt_qmat.

  DATAwerks_sql TYPE string.

  IF lt_werks[] IS NOT INITIAL.
    READ TABLE lt_werks INDEX 1.

    CONCATENATE 'pos~tabkey like ''' lt_werks-low '%''' INTO werks_sql.

    lv_werks_set lt_werks-low.

  ENDIF.

* Get Code Group
  SELECT  pos~tabkey,
          pos~objectid,
          hdr~udate
    INTO  CORRESPONDING FIELDS OF TABLE @lt_cdhdr
    FROM  cdhdr AS hdr
   INNER JOIN cdpos AS pos
      ON pos~objectclas hdr~objectclas
     AND pos~objectid   hdr~objectid
     AND pos~changenr   hdr~changenr
   WHERE (werks_sql)
     AND hdr~objectclas 'MATERIAL'
     AND hdr~udate IN @i_date
     AND pos~tabname 'DQMAT'
    GROUP BY pos~tabkeypos~objectidhdr~udate.

  LOOP AT lt_cdhdr INTO ls_cdhdr.

    ls_coll-art   ls_cdhdr-tabkey+4(4).
    ls_coll-matnr ls_cdhdr-objectid.
    ls_coll-werks ls_cdhdr-tabkey+0(4).
    ls_coll-aedat ls_cdhdr-udate.

    SELECT SINGLE aktivmpdau
      INTO (@ls_coll-aktiv@ls_coll-mpdau)
      FROM qmat
     WHERE art   @ls_coll-art
       AND matnr @ls_coll-matnr
       AND werks @ls_coll-werks.

    COLLECT ls_coll INTO lt_coll.
    CLEAR  ls_coll.
  ENDLOOP.

  loop at lt_coll into ls_coll.
    MOVE-CORRESPONDING ls_coll to gs_qmat.

    append gs_qmat to gt_qmat.
    clear  gs_qmat.
  ENDLOOP.

  READ TABLE i_date INTO ls_date INDEX 1.

  IF gt_qmat[] IS INITIAL.
    ls_z045-i_object  lv_func_name.
    ls_z045-werks     lv_werks_set.
    ls_z045-idate_fr  ls_date-low.
    ls_z045-idate_to  ls_date-high.
    ls_z045-i_sysid   i_sysid.
    ls_z045-e_ret     'E'.
    ls_z045-e_scnt    0.
    ls_z045-e_ecnt    0.
    ls_z045-e_msg     'No Data'.
    ls_z045-ernam     sy-uname.
    ls_z045-erdat     sy-datlo.
    ls_z045-erzet     sy-timlo.

    APPEND ls_z045 TO lt_z045.

    e_msg ls_z045-e_msg.
    e_ret 'E'.
    EXIT.
  ENDIF.

  DATAev_ret  TYPE char1,
        ev_msg  TYPE zmesse,
        lv_date TYPE sy-datlo,
        lv_time TYPE sy-timlo.

  DATA lt_sysid   TYPE TABLE OF string,
         ls_sysid   TYPE string,
         lv_sys_cnt TYPE i,
         lv_sel_cnt TYPE i.

  SPLIT i_sysid  AT ',' INTO TABLE lt_sysid.
  LOOP AT lt_sysid INTO ls_sysid.
    IF ls_sysid IS INITIAL.
      DELETE lt_sysid.
    ENDIF.
  ENDLOOP.

  "전송하게 될 system 수량 계산
  lv_sys_cnt lineslt_sysid ).




  DATAlv_cnt1    TYPE i,
        lv_cnt2    TYPE i,
        lv_fr_num  TYPE i,
        lv_to_num  TYPE i,
        lv_total   TYPE i,
        lv_ava_cnt TYPE i,
        lv_xnum    TYPE i,
        lv_do_time TYPE i.

*  DATA: lo_proxy_lims TYPE REF TO zcl_co_qm00820_serp_ao.
*  DATA: lo_fault TYPE REF TO cx_ai_system_fault,
*        lv_emsg  TYPE string.
*  DATA: ls_proxy_out TYPE zcl_mt_qm00820_serp,
*        lv_cnt1      TYPE i,
*        lv_cnt2      TYPE i,
*        lv_fr_num    TYPE i,
*        lv_to_num    TYPE i,
*        lv_total     TYPE i,
*        lv_ava_cnt   TYPE i,
*        lv_xnum      TYPE i,
*        lv_do_time   TYPE i.


  CONSTANTS:
    gc_max_size TYPE VALUE '3072000',
    gc_size1    TYPE VALUE '64'.

  lv_cnt1 linesgt_qmat ).

  "전송되는 Table size 계산
  lv_total lv_cnt1 * gc_size1.
  "1번에 send 가능한 size 계산
  lv_ava_cnt gc_max_size / gc_size1.

  "나누어 전송해야 하는 Count 계산
  lv_do_time lv_total / gc_max_size + 1.

*  IF gc_max_size < lv_total.
*
*  ENDIF.

  "Code group 과 code를 LIMS에 전송
  CLEARe_scnte_ecnt.
  "처음에 Success로 setting 한 뒤
  "한번이라도 Error가 발생하면 Error로 setting
  e_ret 'S'.

  DATAlo_client_proxy TYPE REF TO zcl_co_qm00820_serp_ao,
        ls_proxy_out    TYPE zcl_mt_qm00820_serp.

  DATAlv_cs_root              TYPE REF TO cx_root,
        lo_fault                TYPE REF TO cx_ai_system_fault,
        lo_ai_application_fault TYPE REF TO cx_ai_application_fault,
        lv_send_emsg            TYPE string,
        lv_emsg                 TYPE string.

  DATAlo_msg_protocol     TYPE REF TO if_wsprotocol_message_id,
        l_msg_id            TYPE sxmsmguid,
        lo_ack              TYPE REF TO if_ws_acknowledgment,
        l_ack_status_simple TYPE prx_ack_status,
        l_ack_status_detail TYPE prx_ack_status_detail_table.

  DATAlo_async_messaging TYPE REF TO if_wsprotocol_async_messaging,
        lv_ack_request     TYPE prx_ack_request_details.


  CREATE OBJECT lo_client_proxy.

  lv_date sy-datlo.
  lv_time sy-timlo.

  lv_fr_num 1.
  DO lv_do_time TIMES.
    CLEAR ls_proxy_out.

    ls_proxy_out-mt_qm00820_serp-xnums lv_xnum.
    ls_proxy_out-mt_qm00820_serp-xdate lv_date.
    ls_proxy_out-mt_qm00820_serp-xtime lv_time.
    ls_proxy_out-mt_qm00820_serp-xsysid i_sysid.

    lv_to_num lv_to_num + lv_ava_cnt.
    CLEARls_proxy_out-mt_qm00820_serp-gt_qmat[]gs_qmat.
    LOOP AT gt_qmat INTO gs_qmat FROM lv_fr_num TO lv_to_num.
      CONDENSE gs_qmat-mpdau.
      APPEND gs_qmat TO ls_proxy_out-mt_qm00820_serp-gt_qmat.
      CLEAR  gs_qmat.
    ENDLOOP.

    lv_cnt1 linesls_proxy_out-mt_qm00820_serp-gt_qmat ).
    ls_proxy_out-mt_qm00820_serp-xrows lv_cnt1.

    CONDENSE ls_proxy_out-mt_qm00820_serp-xnums.
    CONDENSE ls_proxy_out-mt_qm00820_serp-xrows.


    TRY.
        CLEARlv_emsglv_send_emsg.

*     get protocol for asynchronous messaging
        lo_async_messaging ?=
         lo_client_proxy->get_protocolif_wsprotocol=>async_messaging ).

*     Ask for transport acknowledgment
        CLEAR lv_ack_request.
        lv_ack_request =
          if_wsprotocol_async_messaging=>co_transport_acknowledgment.
        lo_async_messaging->set_acknowledgment_requestedlv_ack_request ).

      CATCH cx_ai_system_fault cx_ai_application_fault INTO lv_cs_root.
        CALL METHOD lv_cs_root->if_message~get_text
          RECEIVING
            result lv_send_emsg.
    ENDTRY.



    TRY.

        CALL METHOD lo_client_proxy->qm00820_serp_ao
          EXPORTING
            output ls_proxy_out.

        COMMIT WORK AND WAIT.

      CATCH cx_ai_system_fault cx_ai_application_fault INTO lv_cs_root.
        CALL METHOD lv_cs_root->if_message~get_text
          RECEIVING
            result lv_send_emsg.
    ENDTRY.


    TRY.
* Ack Message 읽어오기
        lo_msg_protocol ?=
          lo_client_proxy->get_protocolif_wsprotocol=>message_id ).
        l_msg_id lo_msg_protocol->get_message_id).

        DO 10 TIMES.
          CLEARls_z045.

          SELECT  SINGLE st~msgguid,
                  st~ack_state,
                  CASE st~ack_state
                    WHEN '072' THEN 'S'
                    WHEN '077' THEN 'S'
                    WHEN '080' THEN 'A'
                    WHEN '000' THEN 'W'
                    ELSE 'E'
                  END,
                  err~errtxt
            INTO  (@ls_z045-ifkey@ls_z045-ack_state,
                   @ls_z045-e_ret@ls_z045-e_msg)
            FROM  sxmspmast AS st
            LEFT  OUTER JOIN sxmsperror AS err
              ON  err~msgguid st~msgguid
           WHERE  st~msgguid @l_msg_id.

          IF ls_z045-ack_state <> '000' AND
             ls_z045-ack_state <> '071'.
            EXIT.
          ENDIF.

          "ack_state 값이 늦게 들어오는 경우가 있어서 Wait 함
          IF ls_z045-ack_state '000' OR
             ls_z045-ack_state '071'.
            WAIT UP TO SECONDS.
          ENDIF.
        ENDDO.

*        lo_ack = cl_proxy_access=>get_acknowledgment( l_msg_id ).
*        l_ack_status_simple = lo_ack->get_status( ).

        "Ack Message가 여러개의 sub msg를 가지고 있는 경우
        "sxmspmast에서 sub msg의 ack status를 읽어서 처리함
        IF ls_z045-ack_state '080'.
          DO 10 TIMES.
            CLEARls_z045lt_z045.

            SELECT  st~msgguid AS ifkey,
                    st~ack_state,
                    CASE st~ack_state
                      WHEN '072' THEN 'S'
                      WHEN '077' THEN 'S'
                      WHEN '080' THEN 'A'
                      WHEN '000' THEN 'W'
                      ELSE 'E'
                    END AS e_ret,
                    CASE mas~ob_system  "PO xsysid 값이 있는 필드
                      WHEN 'ILIM_COM_D' THEN 'LM0'
                      WHEN 'ALIM_TJN_D' THEN 'LMC'
                      WHEN 'ALIM_DGN_D' THEN 'LMD'
                      WHEN 'ALIM_HUN_D' THEN 'LMH'
                      WHEN 'ALIM_MEX_D' THEN 'LMM'
                      WHEN 'ALIM_VNM_D' THEN 'LMV'
                    END AS i_sysid,
                    err~errtxt AS e_msg
              INTO  CORRESPONDING FIELDS OF TABLE @lt_z045
*              INTO  (@ls_z045-ifkey, @ls_z045-ack_state,
*                     @ls_z045-e_ret, @ls_z045-i_sysid,
*                     @ls_z045-e_msg)
              FROM  sxmspmast AS st
             INNER  JOIN sxmspemas AS mas
                ON  mas~msgguid st~msgguid
             LEFT  OUTER JOIN sxmsperror AS err
                ON  err~msgguid mas~msgguid
             WHERE  st~parentmsg @l_msg_id.


            LOOP AT lt_z045 INTO ls_z045.

              ls_z045-i_object  lv_func_name.
              ls_z045-werks     lv_werks_set.
              ls_z045-idate_fr  ls_date-low.
              ls_z045-idate_to  ls_date-high.
              IF ls_z045-e_ret 'S'.
                ls_z045-e_scnt    lv_cnt1.
              ELSE.
                ls_z045-e_ecnt    lv_cnt1.
              ENDIF.
              ls_z045-ernam     sy-uname.
              ls_z045-erdat     lv_date.
              ls_z045-erzet     lv_time.

              MODIFY lt_z045 FROM ls_z045 INDEX sy-tabix.
            ENDLOOP.

            lv_sel_cnt lineslt_z045 ).

            "ack_state 값이 늦게 들어오는 경우가 있어서 Wait 함
            IF sy-subrc <> OR
               ls_z045-ack_state '000' OR
               ls_z045-ack_state '071' OR
              "insert 가 늦게 되어서 전송한 system 전체 값이 나오지
              "않는 경우가 발생하여 전송한 count 와 비교함
               lv_sel_cnt < lv_sys_cnt.
              WAIT UP TO SECONDS.
              CONTINUE.
            ENDIF.

            IF sy-subrc AND
*               ls_z045-ack_state <> '000' AND
               ls_z045-ack_state <> '071'.
              EXIT.
            ENDIF.

          ENDDO.
          "1개의 system에 전송한 경우
        ELSE.

          ls_z045-i_object  lv_func_name.
          ls_z045-werks     lv_werks_set.
          ls_z045-idate_fr  ls_date-low.
          ls_z045-idate_to  ls_date-high.
          ls_z045-i_sysid   i_sysid.
          IF ls_z045-e_ret  'S'.
            ls_z045-e_scnt    lv_cnt1.
          ELSE.
            ls_z045-e_ecnt    lv_cnt1.
          ENDIF.
*          ls_z045-e_msg     = e_msg.
          ls_z045-ernam     sy-uname.
          ls_z045-erdat     lv_date.
          ls_z045-erzet     lv_time.

          APPEND ls_z045 TO lt_z045.

*            lo_ack->get_status_detail( IMPORTING  ack_status_detail_table = l_ack_status_detail ).
        ENDIF.

      CATCH cx_ai_system_fault cx_ai_application_fault INTO lv_cs_root.
        CALL METHOD lv_cs_root->if_message~get_text
          RECEIVING
            result lv_send_emsg.

    ENDTRY.

    ADD TO lv_xnum.
    lv_fr_num lv_to_num + 1.

    IF lv_send_emsg IS INITIAL.
      e_ret ls_z045-e_ret.

      IF ls_z045-e_ret 'S'.
        e_scnt e_scnt + lv_cnt1.
      ELSE.
        e_ecnt e_ecnt + lv_cnt1.
      ENDIF.
    ELSE.
      ls_z045-i_object  lv_func_name.
      ls_z045-werks     lv_werks_set.
      ls_z045-i_sysid   i_sysid.
      ls_z045-idate_fr  ls_date-low.
      ls_z045-idate_to  ls_date-high.
      ls_z045-e_ret     'E'.
      ls_z045-e_ecnt    lv_cnt1.
      ls_z045-e_msg     lv_send_emsg.
      ls_z045-ernam     sy-uname.
      ls_z045-erdat     lv_date.
      ls_z045-erzet     lv_time.

      APPEND ls_z045 TO lt_z045.

      e_msg lv_emsg.
      "처음에 Success로 setting 한 뒤
      "한번이라도 Error가 발생하면 Error로 setting
      e_ret 'F'.
      e_ecnt e_ecnt + lv_cnt1.
    ENDIF.
  ENDDO.

ENDFUNCTION.