IT WORK/SAP FI and ABAP

[FI/ABAP] 선급금 진행 현황 REPORT

Bathildis 2026. 5. 4. 16:37
반응형

여기는 선급금요청GL, 선급금GL, 은행GL이 1개씩이라 하드코딩 했으나 각자 사정에 맞춰서 수정하시고...

po/item별로 선급금을 1개만 요청하는 경우도 있고 2개 이상 요청하는 경우도 있고 선급금 100%인 곳도 있고 선급금 30%인 곳도 있고... 선급금 전표도 쪼갰다 붙였다 송장도 쪼갰다 붙였다 지급도 쪼갰다 붙였다 ㅠㅠ

왠만한 케이스는 다 잡은거 같은데 아닐수도......

그리고 송장을 여러개의 po/item 합쳐서 하는 케이스가 있기 때문에 외상매출금에 대한 실제 은행 지급 금액을 비율로 쪼개서 금액 차이가 좀 발생함. -1~1달러 차이는 정상으로 처리 했음.

 

 

REPORT ZFIR9998.

TYPE-POOLS: SLIS.
TABLES: BSEG, BKPF, RSEG, RBKP, BSE_CLR, ZIMTP00, ZIMTP01.

*=====================================================================
*STEP 1. 조회 조건 정의
*회사코드, 전기일, 선급금 요청 GL계정(기본:0099040101), PO 조건 입력
*=====================================================================
*1.조회 조건
SELECTION-SCREEN BEGIN OF BLOCK B1 WITH FRAME TITLE TEXT-T01.
  PARAMETERS: P_BUKRS TYPE BUKRS DEFAULT '1000' OBLIGATORY.
  SELECT-OPTIONS: S_BUDAT FOR BKPF-BUDAT DEFAULT '20250701' TO '99991231' NO-EXTENSION.
  PARAMETERS: P_HKONT TYPE HKONT DEFAULT '0099040101' OBLIGATORY.
  SELECT-OPTIONS: S_PO FOR BKPF-BKTXT NO INTERVALS.
SELECTION-SCREEN END OF BLOCK B1.

*=====================================================================
*STEP 2. 출력/집계용 내부 테이블 및 구조 정의
*=====================================================================
*2. 데이터 구조 정의
TYPES: BEGIN OF TY_OUT,
         LIFNR       TYPE BSEG-LIFNR,
         NAME1       TYPE LFA1-NAME1,
         EBELN       TYPE BSEG-EBELN,
         EBELP       TYPE BSEG-EBELP,
         REQ_BELNR   TYPE STRING,
         REQ_AMT     TYPE BSEG-WRBTR,
         PRE_BELNR   TYPE STRING,
         PRE_AMT     TYPE BSEG-WRBTR,
         CLR_PRE_BEL TYPE STRING,
         CLR_PRE_AMT TYPE BSEG-WRBTR,
         BAL_PRE_AMT TYPE BSEG-WRBTR,
         AP_FI_BELNR TYPE STRING,
         AP_AMT      TYPE BSEG-WRBTR,
         BANK_BELNR  TYPE STRING,
         BANK_AMT    TYPE BSEG-WRBTR,
         OFF_AMT     TYPE BSEG-WRBTR,
         VAL_AMT     TYPE BSEG-WRBTR,
         WAERS       TYPE BKPF-WAERS,
         REMARK      TYPE CHAR100,
         LINE_COLOR  TYPE CHAR4,
       END OF TY_OUT.

TYPES: BEGIN OF TY_RSEG_TOT,
         BELNR TYPE RSEG-BELNR,
         GJAHR TYPE RSEG-GJAHR,
         WRBTR TYPE RSEG-WRBTR,
       END OF TY_RSEG_TOT.

TYPES: BEGIN OF TY_CBO_MAP,
         ZCLNO  TYPE BELNR_D,
         ZCLYR  TYPE GJAHR,
         ZIMPNO TYPE ZIMPNO,
       END OF TY_CBO_MAP.

TYPES: BEGIN OF TY_CBO_ITEM,
         ZIMPNO TYPE ZIMPNO,
         EBELN  TYPE EBELN,
         EBELP  TYPE EBELP,
       END OF TY_CBO_ITEM.

DATA: LT_OUTPUT   TYPE TABLE OF TY_OUT,
      LT_FCAT     TYPE SLIS_T_FIELDCAT_ALV,
      LT_RSEG_TOT TYPE TABLE OF TY_RSEG_TOT,
      LT_CBO_HEAD TYPE TABLE OF TY_CBO_MAP,
      LT_CBO_ITEM TYPE TABLE OF TY_CBO_ITEM.

DATA: LV_INV_BANK_TOT      TYPE BSEG-WRBTR,
      LV_INV_TOT           TYPE BSEG-WRBTR,
      LV_TOT_ALLOCATED_CLR TYPE BSEG-WRBTR,
      LV_TMP_BANK_BELNR    TYPE STRING.

DATA: BEGIN OF LT_PAY OCCURS 0,
        EBELN LIKE BSEG-EBELN,
        EBELP LIKE BSEG-EBELP,
        BELNR LIKE BSEG-BELNR,
        GJAHR LIKE BSEG-GJAHR,
        BUZEI LIKE BSEG-BUZEI,
        WRBTR LIKE BSEG-WRBTR,
      END OF LT_PAY.

START-OF-SELECTION.

  DATA: LT_WHERE_CLAUSES TYPE STANDARD TABLE OF STRING,
        LV_WHERE_LINE    TYPE STRING.

  DATA: LV_LEN   TYPE I,
        LV_EBELN TYPE EKPO-EBELN,
        LV_EBELP TYPE STRING.

  DATA: LS_BUDAT LIKE LINE OF S_BUDAT.

  CLEAR: LT_WHERE_CLAUSES.

  " 1. 회사코드
  CONCATENATE 'A~BUKRS =''' P_BUKRS '''' INTO LV_WHERE_LINE.
  APPEND LV_WHERE_LINE TO LT_WHERE_CLAUSES.

  " 2. G/L 계정
  CONCATENATE 'AND A~HKONT =''' P_HKONT '''' INTO LV_WHERE_LINE.
  APPEND LV_WHERE_LINE TO LT_WHERE_CLAUSES.

  " 3. 역분개 여부
  APPEND 'AND B~STBLG =''''' TO LT_WHERE_CLAUSES.

  " 4. 전기일
  IF S_BUDAT[] IS NOT INITIAL.
    LOOP AT S_BUDAT INTO LS_BUDAT.
      CASE LS_BUDAT-OPTION.
        WHEN 'EQ'.
          CONCATENATE 'AND B~BUDAT =''' LS_BUDAT-LOW '''' INTO LV_WHERE_LINE.
          APPEND LV_WHERE_LINE TO LT_WHERE_CLAUSES.
        WHEN 'BT'.
          CONCATENATE 'AND B~BUDAT BETWEEN''' LS_BUDAT-LOW ''' AND ''' LS_BUDAT-HIGH '''' INTO LV_WHERE_LINE.
          APPEND LV_WHERE_LINE TO LT_WHERE_CLAUSES.
      ENDCASE.
    ENDLOOP.
  ENDIF.

  " 5. PO/ITEM 정보
  IF S_PO[] IS NOT INITIAL.

    DATA: LT_PO_TMP TYPE STANDARD TABLE OF STRING,
          LV_PO_TMP TYPE STRING.

    LOOP AT S_PO.
      CLEAR: LV_EBELN, LV_EBELP, LV_PO_TMP.
      CONDENSE S_PO-LOW NO-GAPS.
      LV_LEN = STRLEN( S_PO-LOW ).

      IF LV_LEN > 10.
        " PO 10자리 + 아이템 번호 패턴
        LV_EBELN = S_PO-LOW+0(10).
        LV_EBELP = S_PO-LOW+10.

        CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
          EXPORTING
            INPUT  = LV_EBELP
          IMPORTING
            OUTPUT = LV_EBELP.

        IF LT_PO_TMP IS INITIAL.
          CONCATENATE '( A~EBELN = ''' LV_EBELN ''' AND A~EBELP = ''' LV_EBELP ''' )' INTO LV_PO_TMP.
        ELSE.
          CONCATENATE 'OR ( A~EBELN = ''' LV_EBELN ''' AND A~EBELP = ''' LV_EBELP ''' )' INTO LV_PO_TMP.
        ENDIF.
        APPEND LV_PO_TMP TO LT_PO_TMP.

      ELSEIF LV_LEN > 0 AND LV_LEN <= 10.
        " 아이템 번호 없이 PO만 넣었을 때
        LV_EBELN = S_PO-LOW.

        IF LT_PO_TMP IS INITIAL.
          CONCATENATE '( A~EBELN = ''' LV_EBELN ''' )' INTO LV_PO_TMP.
        ELSE.
          CONCATENATE 'OR ( A~EBELN = ''' LV_EBELN ''' )' INTO LV_PO_TMP.
        ENDIF.
        APPEND LV_PO_TMP TO LT_PO_TMP.
      ENDIF.
    ENDLOOP.

    " 메인 조건 텍스트 뒤에 'AND (' 와 ')'로 감쌈
    IF LT_PO_TMP IS NOT INITIAL.
      INSERT 'AND (' INTO LT_PO_TMP INDEX 1.
      APPEND ')' TO LT_PO_TMP.
      APPEND LINES OF LT_PO_TMP TO LT_WHERE_CLAUSES.
    ENDIF.

  ENDIF.

* =====================================================================
* STEP 3. 선급금 요청 조회 " GL 0099040101 : 선급금_요청 " 선급 요청
* 전표를 PO/Item 기준 집계의 시작 데이터로 사용
* =====================================================================
*3. 선급요청 조회
  SELECT A~LIFNR,
         C~NAME1,
         A~EBELN,
         A~EBELP,
         A~BELNR,
         A~WRBTR,
         B~WAERS,
         A~GJAHR
    FROM BSEG AS A INNER JOIN BKPF AS B ON A~BUKRS = B~BUKRS
                                       AND A~BELNR = B~BELNR
                                       AND A~GJAHR = B~GJAHR
              LEFT OUTER JOIN LFA1 AS C ON A~LIFNR EQ C~LIFNR
    INTO TABLE @DATA(LT_DP_REQUEST)
   WHERE (LT_WHERE_CLAUSES).

  IF LT_DP_REQUEST IS INITIAL.
    MESSAGE '조회된 데이터가 없습니다.' TYPE 'S' DISPLAY LIKE 'E'. EXIT.
  ENDIF.

*=====================================================================
*STEP 4. PO/Item 단위 집계 " 동일 PO/Item의 여러 요청 전표를 하나로 집계
*=====================================================================
*4. PO/ITEM 그룹핑
  LOOP AT LT_DP_REQUEST INTO DATA(LS_REQ).
    READ TABLE LT_OUTPUT ASSIGNING FIELD-SYMBOL(<FS_OUT>)
      WITH KEY EBELN = LS_REQ-EBELN EBELP = LS_REQ-EBELP.
    IF SY-SUBRC <> 0.
      APPEND INITIAL LINE TO LT_OUTPUT ASSIGNING <FS_OUT>.
      <FS_OUT>-LIFNR = LS_REQ-LIFNR. <FS_OUT>-NAME1 = LS_REQ-NAME1.
      <FS_OUT>-EBELN = LS_REQ-EBELN. <FS_OUT>-EBELP = LS_REQ-EBELP.
      <FS_OUT>-WAERS = LS_REQ-WAERS.
    ENDIF.
    IF NOT <FS_OUT>-REQ_BELNR CS LS_REQ-BELNR.
      IF <FS_OUT>-REQ_BELNR IS INITIAL.
        <FS_OUT>-REQ_BELNR = |{ LS_REQ-BELNR }({ LS_REQ-GJAHR })|.
      ELSE.
        <FS_OUT>-REQ_BELNR = |{ <FS_OUT>-REQ_BELNR }, { LS_REQ-BELNR }({ LS_REQ-GJAHR })|.
      ENDIF.
    ENDIF.
    <FS_OUT>-REQ_AMT = <FS_OUT>-REQ_AMT + LS_REQ-WRBTR.
  ENDLOOP.

*=====================================================================
*STEP 5. 선급금 지급 조회 " GL 0011050102 : 선급금_수입 " 차변(SHKZG='S')
*기준 실제 지급액 집계
*=====================================================================
*5. 선급지급 정보 조회
  SELECT A~EBELN,
         A~EBELP,
         A~WRBTR,
         A~BELNR,
         A~GJAHR,
         A~BUZEI
    FROM BSEG AS A INNER JOIN BKPF AS B ON A~BUKRS = B~BUKRS
                                       AND A~BELNR = B~BELNR
                                       AND A~GJAHR = B~GJAHR
     FOR ALL ENTRIES IN @LT_OUTPUT
   WHERE A~BUKRS = @P_BUKRS
     AND A~HKONT = '0011050102'
     AND A~EBELN = @LT_OUTPUT-EBELN
     AND A~EBELP = @LT_OUTPUT-EBELP
     AND B~STBLG = ''
     AND A~SHKZG = 'S'
    INTO TABLE @DATA(LT_PAY_PRE_RAW).

  LOOP AT LT_PAY_PRE_RAW INTO DATA(LS_PRE).
    MOVE-CORRESPONDING LS_PRE TO LT_PAY. COLLECT LT_PAY.
  ENDLOOP.

*=====================================================================
*STEP 6. 선금반제(F-54) 및 CBO 검증 " GL 0011050102 대변 반제내역과
*ZIMTP00/01 매핑 확인
*=====================================================================
*6. 선급금 반제 정보 및 CBO 데이터 수집
  IF LT_OUTPUT IS NOT INITIAL.
    SELECT A~EBELN,
           A~EBELP,
           A~BELNR,
           A~GJAHR,
           A~WRBTR,
           A~BUZEI
      FROM BSEG AS A INNER JOIN BKPF AS B ON A~BUKRS = B~BUKRS
                                         AND A~BELNR = B~BELNR
                                         AND A~GJAHR = B~GJAHR
       FOR ALL ENTRIES IN @LT_OUTPUT
     WHERE A~BUKRS = @P_BUKRS
       AND A~HKONT = '0011050102'
       AND A~EBELN = @LT_OUTPUT-EBELN
       AND A~EBELP = @LT_OUTPUT-EBELP
       AND B~STBLG = ''
       AND A~SHKZG = 'H'
      INTO TABLE @DATA(LT_PRE_OFFSET).

    IF LT_PRE_OFFSET IS NOT INITIAL.
      SELECT ZCLNO,
             ZCLYR,
             ZIMPNO
       FROM ZIMTP00
         FOR ALL ENTRIES IN @LT_PRE_OFFSET
       WHERE ZCLNO = @LT_PRE_OFFSET-BELNR
         AND ZCLYR = @LT_PRE_OFFSET-GJAHR
        INTO TABLE @LT_CBO_HEAD.

      IF LT_CBO_HEAD IS NOT INITIAL.
        SELECT ZIMPNO,
               EBELN,
               EBELP
          FROM ZIMTP01
           FOR ALL ENTRIES IN @LT_CBO_HEAD
         WHERE ZIMPNO = @LT_CBO_HEAD-ZIMPNO
          INTO TABLE @LT_CBO_ITEM.
      ENDIF.
    ENDIF.
  ENDIF.

*=====================================================================
*STEP 7. MM/FI 송장 조회 " RBKP-VGART = 'RD' => 물류송장만 조회
*=====================================================================
*7. MM/FI 송장 연계 조회
  SELECT A~EBELN,
         A~EBELP,
         A~BELNR,
         A~GJAHR,
         A~WRBTR
    FROM RSEG AS A INNER JOIN RBKP AS B ON A~BELNR = B~BELNR
                                       AND A~GJAHR = B~GJAHR
     FOR ALL ENTRIES IN @LT_OUTPUT
    WHERE A~EBELN = @LT_OUTPUT-EBELN
      AND A~EBELP = @LT_OUTPUT-EBELP
      AND B~VGART = 'RD'
      AND A~KSCHL = ''
      AND B~STBLG = ''
     INTO TABLE @DATA(LT_MM_INV).

  IF LT_MM_INV IS NOT INITIAL.
    TYPES: BEGIN OF TY_AWKEY,
             AWKEY TYPE BKPF-AWKEY,
           END OF TY_AWKEY.
    DATA: LT_AWKEY TYPE TABLE OF TY_AWKEY.

    LOOP AT LT_MM_INV INTO DATA(LS_MI).
      APPEND VALUE #( AWKEY = |{ LS_MI-BELNR }{ LS_MI-GJAHR }| ) TO LT_AWKEY.
    ENDLOOP.
    SORT LT_AWKEY BY AWKEY. DELETE ADJACENT DUPLICATES FROM LT_AWKEY.

    SELECT BELNR,
           GJAHR,
           AWKEY
      FROM BKPF
       FOR ALL ENTRIES IN @LT_AWKEY
     WHERE BUKRS = @P_BUKRS
       AND AWKEY = @LT_AWKEY-AWKEY
       AND STBLG = ''
      INTO TABLE @DATA(LT_FI_DOCS).

    IF LT_FI_DOCS IS NOT INITIAL.
      SELECT BELNR,
             GJAHR,
             BUZEI,
             WRBTR
        FROM RSEG
         FOR ALL ENTRIES IN @LT_MM_INV
       WHERE BELNR = @LT_MM_INV-BELNR
         AND GJAHR = @LT_MM_INV-GJAHR
         AND KSCHL = ''
        INTO TABLE @DATA(LT_RSEG_RAW).
      LOOP AT LT_RSEG_RAW INTO DATA(LS_RRAW).
        COLLECT VALUE TY_RSEG_TOT( BELNR = LS_RRAW-BELNR GJAHR = LS_RRAW-GJAHR WRBTR = LS_RRAW-WRBTR ) INTO LT_RSEG_TOT.
      ENDLOOP.

      SELECT BELNR,
             GJAHR,
             BUZEI,
             AUGBL
        FROM BSEG
         FOR ALL ENTRIES IN @LT_FI_DOCS
       WHERE BUKRS = @P_BUKRS
         AND BELNR = @LT_FI_DOCS-BELNR
         AND GJAHR = @LT_FI_DOCS-GJAHR
         AND KOART = 'K'
        INTO TABLE @DATA(LT_FI_VEND).
    ENDIF.
  ENDIF.

*=====================================================================
*STEP 8. 은행 지급 확인 " 보통예금_외화 GL(0011010202) 지급 여부 확인
*=====================================================================
*8. 은행 지급용 BSE_CLR 조회
  IF LT_FI_VEND IS NOT INITIAL.
    SELECT A~BUKRS,
           A~BELNR,
           A~GJAHR,
           A~BUZEI,
           A~BELNR_CLR,
           A~GJAHR_CLR,
           A~WRBTR,
           A~DIFFW,
           A~CLRIN
      FROM BSE_CLR AS A INNER JOIN BKPF AS B ON A~BUKRS = B~BUKRS
                                            AND A~BELNR_CLR = B~BELNR
                                            AND A~GJAHR_CLR = B~GJAHR
       FOR ALL ENTRIES IN @LT_FI_VEND
     WHERE A~BUKRS = @P_BUKRS
       AND A~BELNR = @LT_FI_VEND-BELNR
       AND A~GJAHR = @LT_FI_VEND-GJAHR
       AND A~BUZEI = @LT_FI_VEND-BUZEI
       AND B~STBLG = ''
      INTO TABLE @DATA(LT_BSE_CLR).

    IF LT_BSE_CLR IS NOT INITIAL.
      SELECT BELNR AS BELNR_CLR,
             GJAHR AS GJAHR_CLR
        FROM BSEG
         FOR ALL ENTRIES IN @LT_BSE_CLR
       WHERE BUKRS = @P_BUKRS
         AND BELNR = @LT_BSE_CLR-BELNR_CLR
         AND GJAHR = @LT_BSE_CLR-GJAHR_CLR
         AND HKONT = '0011010202'
        INTO TABLE @DATA(LT_BANK_CHK).
      SORT LT_BANK_CHK BY BELNR_CLR GJAHR_CLR.
    ENDIF.
  ENDIF.

*=====================================================================
*STEP 9. 최종 집계 및 검증
*선급/반제/송장/은행지급을 비교하여 상태(REMARK) 결정
*=====================================================================
*9. 최종 집계 및 비고 판단
  LOOP AT LT_OUTPUT ASSIGNING <FS_OUT>. " 선급금 지급 집계
    LOOP AT LT_PAY WHERE EBELN = <FS_OUT>-EBELN AND EBELP = <FS_OUT>-EBELP.
      <FS_OUT>-PRE_AMT = <FS_OUT>-PRE_AMT + LT_PAY-WRBTR.
      IF NOT <FS_OUT>-PRE_BELNR CS LT_PAY-BELNR.
        IF <FS_OUT>-PRE_BELNR IS INITIAL.
          <FS_OUT>-PRE_BELNR = |{ LT_PAY-BELNR }({ LT_PAY-GJAHR })|.
        ELSE.
          <FS_OUT>-PRE_BELNR = |{ <FS_OUT>-PRE_BELNR }, { LT_PAY-BELNR }({ LT_PAY-GJAHR })|.
        ENDIF.
      ENDIF.
    ENDLOOP.

    " CBO Mismatch 검증
    DATA: LV_ZIMP_LIST TYPE STRING, LV_CBO_ERROR TYPE STRING.
    CLEAR: LV_ZIMP_LIST, LV_CBO_ERROR.

    LOOP AT LT_PRE_OFFSET INTO DATA(LS_OFF) WHERE EBELN = <FS_OUT>-EBELN AND EBELP = <FS_OUT>-EBELP.
      <FS_OUT>-CLR_PRE_AMT = <FS_OUT>-CLR_PRE_AMT + LS_OFF-WRBTR.
      IF NOT <FS_OUT>-CLR_PRE_BEL CS LS_OFF-BELNR.
        IF <FS_OUT>-CLR_PRE_BEL IS INITIAL.
          <FS_OUT>-CLR_PRE_BEL = |{ LS_OFF-BELNR }({ LS_OFF-GJAHR })|.
        ELSE.
          <FS_OUT>-CLR_PRE_BEL = |{ <FS_OUT>-CLR_PRE_BEL }, { LS_OFF-BELNR }({ LS_OFF-GJAHR })|.
        ENDIF.
      ENDIF.

      " 해당 전표와 연결된 수입 번호를 뒤져서 현재 PO 항목이 없는지 체크
      LOOP AT LT_CBO_HEAD INTO DATA(LS_HEAD) WHERE ZCLNO = LS_OFF-BELNR AND ZCLYR = LS_OFF-GJAHR.
        IF NOT LV_ZIMP_LIST CS LS_HEAD-ZIMPNO.
          IF LV_ZIMP_LIST IS INITIAL.
            LV_ZIMP_LIST = LS_HEAD-ZIMPNO.
          ELSE.
            LV_ZIMP_LIST = |{ LV_ZIMP_LIST }, { LS_HEAD-ZIMPNO }|.
          ENDIF.
        ENDIF.

        " 하나라도 매칭되지 않는 전표가 발견되면 즉시 에러
        READ TABLE LT_CBO_ITEM WITH KEY ZIMPNO = LS_HEAD-ZIMPNO EBELN = <FS_OUT>-EBELN EBELP = <FS_OUT>-EBELP TRANSPORTING NO FIELDS.
        IF SY-SUBRC <> 0.
          LV_CBO_ERROR = |{ LS_HEAD-ZIMPNO }에 { <FS_OUT>-EBELN }/{ <FS_OUT>-EBELP }이 없습니다.|.
          EXIT. " 헤더 루프 탈출
        ENDIF.
      ENDLOOP.
      IF LV_CBO_ERROR IS NOT INITIAL. EXIT. ENDIF. " 오프셋 루프 탈출
    ENDLOOP.

    IF LV_CBO_ERROR IS NOT INITIAL.
      <FS_OUT>-REMARK = LV_CBO_ERROR.
      <FS_OUT>-LINE_COLOR = 'C610'.
    ENDIF.

    " 송장 및 은행 지급액 배분
    DATA: LV_HAS_OPEN(1), LV_HAS_CLEARED(1).
    CLEAR: LV_TOT_ALLOCATED_CLR, LV_TMP_BANK_BELNR, LV_HAS_OPEN, LV_HAS_CLEARED.

    LOOP AT LT_MM_INV INTO DATA(LS_INV) WHERE EBELN = <FS_OUT>-EBELN AND EBELP = <FS_OUT>-EBELP.
      <FS_OUT>-AP_AMT = <FS_OUT>-AP_AMT + LS_INV-WRBTR.
      READ TABLE LT_FI_DOCS INTO DATA(LS_FI) WITH KEY AWKEY = |{ LS_INV-BELNR }{ LS_INV-GJAHR }|.
      IF SY-SUBRC = 0.
        IF NOT <FS_OUT>-AP_FI_BELNR CS LS_FI-BELNR.
          IF <FS_OUT>-AP_FI_BELNR IS INITIAL.
            <FS_OUT>-AP_FI_BELNR = |{ LS_FI-BELNR }({ LS_FI-GJAHR })|.
          ELSE.
            <FS_OUT>-AP_FI_BELNR = |{ <FS_OUT>-AP_FI_BELNR }, { LS_FI-BELNR }({ LS_FI-GJAHR })|.
          ENDIF.
        ENDIF.

        CLEAR: LV_INV_BANK_TOT, LV_INV_TOT.
        READ TABLE LT_RSEG_TOT INTO DATA(LS_RTOT) WITH KEY BELNR = LS_FI-AWKEY(10) GJAHR = LS_FI-AWKEY+10(4).
        IF SY-SUBRC = 0. LV_INV_TOT = LS_RTOT-WRBTR. ENDIF.

        LOOP AT LT_FI_VEND INTO DATA(LS_VEND) WHERE BELNR = LS_FI-BELNR AND GJAHR = LS_FI-GJAHR.
          IF LS_VEND-AUGBL IS INITIAL.
            LV_HAS_OPEN = 'X'. " 미반제 건 존재
          ELSE.
            LV_HAS_CLEARED = 'X'. " 정상 반제 됨
          ENDIF.

          LOOP AT LT_BSE_CLR INTO DATA(LS_CLR) WHERE BELNR = LS_VEND-BELNR AND GJAHR = LS_VEND-GJAHR AND BUZEI = LS_VEND-BUZEI.
            READ TABLE LT_BANK_CHK TRANSPORTING NO FIELDS WITH KEY BELNR_CLR = LS_CLR-BELNR_CLR GJAHR_CLR = LS_CLR-GJAHR_CLR BINARY SEARCH.
            IF SY-SUBRC = 0.
              DATA(LV_CB) = COND BSEG-WRBTR( WHEN LS_CLR-CLRIN = SPACE THEN LS_CLR-WRBTR ELSE LS_CLR-WRBTR - LS_CLR-DIFFW ).
              LV_INV_BANK_TOT = LV_INV_BANK_TOT + LV_CB.
              IF NOT LV_TMP_BANK_BELNR CS LS_CLR-BELNR_CLR.
                IF LV_TMP_BANK_BELNR IS INITIAL.
                  LV_TMP_BANK_BELNR = |{ LS_CLR-BELNR_CLR }({ LS_CLR-GJAHR_CLR })|.
                ELSE.
                  LV_TMP_BANK_BELNR = |{ LV_TMP_BANK_BELNR }, { LS_CLR-BELNR_CLR }({ LS_CLR-GJAHR_CLR })|.
                ENDIF.
              ENDIF.
            ENDIF.
          ENDLOOP.
        ENDLOOP.
        IF LV_INV_BANK_TOT > 0 AND LV_INV_TOT > 0.
          LV_TOT_ALLOCATED_CLR = LV_TOT_ALLOCATED_CLR + ( LV_INV_BANK_TOT * ( LS_INV-WRBTR / LV_INV_TOT ) ).
        ENDIF.
      ENDIF.
    ENDLOOP.

    " 잔액 및 추가 비고
    IF LV_TOT_ALLOCATED_CLR > 0.
      DATA(LV_R) = LV_TOT_ALLOCATED_CLR - <FS_OUT>-PRE_AMT.
      IF LV_R <= 0.
        LV_R = 0. CLEAR <FS_OUT>-BANK_BELNR.
      ELSE.
        <FS_OUT>-BANK_BELNR = LV_TMP_BANK_BELNR.
      ENDIF.
      <FS_OUT>-BANK_AMT = LV_R.
    ENDIF.

    <fS_OUT>-BAL_PRE_AMT = <fS_OUT>-PRE_AMT - <fS_OUT>-CLR_PRE_AMT.
    <FS_OUT>-VAL_AMT = <FS_OUT>-AP_AMT - <FS_OUT>-PRE_AMT - <FS_OUT>-BANK_AMT.

    " 비고 덮어쓰기 방지
    IF <FS_OUT>-REMARK IS NOT INITIAL. CONTINUE. ENDIF.

    IF <FS_OUT>-AP_AMT = 0.
      IF <FS_OUT>-REQ_AMT > 0.
        IF <FS_OUT>-PRE_AMT >= <FS_OUT>-REQ_AMT.
          <FS_OUT>-REMARK = '선급지급완료 (송장대기)'.
        ELSE.
          <FS_OUT>-REMARK = '선급지급중'.
        ENDIF.
      ENDIF.
    ELSE.
      IF <FS_OUT>-CLR_PRE_AMT > <FS_OUT>-PRE_AMT.
        <FS_OUT>-REMARK = '!! 선금반제 오류 (선급금 초과) !!'. <FS_OUT>-LINE_COLOR = 'C610'.
      ELSEIF <FS_OUT>-PRE_AMT > 0 AND <FS_OUT>-CLR_PRE_BEL IS INITIAL.
        <FS_OUT>-REMARK = '!! 선금반제(F-54) 처리 누락 !!'. <FS_OUT>-LINE_COLOR = 'C610'.
      ELSEIF <FS_OUT>-VAL_AMT BETWEEN -1 AND 1.
        IF <FS_OUT>-CLR_PRE_AMT < <FS_OUT>-PRE_AMT.
          <FS_OUT>-REMARK = '!! 선금반제 오류 (선급금 미달) !!'. <FS_OUT>-LINE_COLOR = 'C610'.
        ELSE.
          IF <FS_OUT>-BANK_AMT = 0.
            <FS_OUT>-REMARK = '정상 처리 완료 (상계완료)'.
          ELSE.
            <FS_OUT>-REMARK = '정상 처리 완료 (추가지급완료)'.
          ENDIF.
        ENDIF.
      ELSEIF <FS_OUT>-VAL_AMT > 1.

        IF LV_HAS_OPEN = 'X' AND LV_HAS_CLEARED = 'X'.
          <FS_OUT>-REMARK = '추가 지급 필요 (일부 송장 미반제)'.
        ELSEIF LV_HAS_OPEN = 'X'.
          <FS_OUT>-REMARK = '추가 지급 필요 (미지급)'.
        ELSE.
          <FS_OUT>-OFF_AMT = <FS_OUT>-VAL_AMT.
          CLEAR <FS_OUT>-VAL_AMT.
          <FS_OUT>-REMARK = '정상 처리 완료 (상계완료)'.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDLOOP.

  SORT LT_OUTPUT BY REMARK LIFNR EBELN EBELP.

  PERFORM BUILD_FIELDCAT.
  PERFORM DISPLAY_ALV.

  "----------------------------------------------------------------------
FORM BUILD_FIELDCAT.
  DATA: LS_FCAT TYPE SLIS_FIELDCAT_ALV.
  DEFINE ADD_COL.
    CLEAR LS_FCAT. LS_FCAT-FIELDNAME = &1. LS_FCAT-SELTEXT_L = &2.
    IF &1 CP '*AMT*'. LS_FCAT-DO_SUM = 'X'. LS_FCAT-CFIELDNAME = 'WAERS'. ENDIF.
    APPEND LS_FCAT TO LT_FCAT.
  END-OF-DEFINITION.
  ADD_COL 'LIFNR' '구매처'.
  ADD_COL 'NAME1' '구매처명'.
  ADD_COL 'EBELN' 'PO번호'.
  ADD_COL 'EBELP' '항목'.
  ADD_COL 'REQ_BELNR' '선급요청전표'.
  ADD_COL 'REQ_AMT' '선급요청액'.
  ADD_COL 'PRE_BELNR' '선급지급전표'.
  ADD_COL 'PRE_AMT' '선급지급액(A)'.
  ADD_COL 'CLR_PRE_BEL' '선금반제전표'.
  ADD_COL 'CLR_PRE_AMT' '선금반제합계(Z)'.
  ADD_COL 'BAL_PRE_AMT' '선급잔액(A-Z)'.
  ADD_COL 'AP_FI_BELNR' '송장회계전표'.
  ADD_COL 'AP_AMT' '물품송장합계(B)'.
  ADD_COL 'BANK_BELNR' '은행지급전표'.
  ADD_COL 'BANK_AMT' '은행지급액(C)'.
  ADD_COL 'OFF_AMT' '상계금액(D)'.
  ADD_COL 'VAL_AMT' '검증잔액(B-A-C-D)'.
  ADD_COL 'REMARK' '비고'.
ENDFORM.

FORM DISPLAY_ALV.
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      IS_LAYOUT   = VALUE SLIS_LAYOUT_ALV( ZEBRA = 'X' COLWIDTH_OPTIMIZE = 'X' INFO_FIELDNAME = 'LINE_COLOR' )
      IT_FIELDCAT = LT_FCAT
    TABLES
      T_OUTTAB    = LT_OUTPUT.
ENDFORM.
반응형