수취인 성명조회 금액 포함 펑션 개발시 참고 방향

안녕하세요 아는형입니다.

펌뱅킹(Firm Banking) 개발하다 보면 어느 순간 “어? 이건 예전엔 안 그랬는데” 싶은 스펙을 만날 때가 있습니다. 저한테는 이번 건이 그랬습니다. 수취인성명조회(계좌실명조회) 기능 자체는 이미 예전부터 쓰고 있던 펑션이었는데, 이번에 가상계좌 건을 붙이면서 문제가 터졌습니다.

기존 수취인성명조회 펑션은 계좌번호랑 은행코드만 넘기면 예금주 성명을 돌려주는 구조였습니다. 금액은 아예 체크 대상이 아니었죠. 그런데 가상계좌는 다릅니다. 가상계좌는 수취인 성명조회 시 금액이 반드시 일치해야만 응답을 주는 경우가 있다는 걸 이번에 알게 됐습니다. 실제 이체할 금액과 조회 시 넘기는 금액이 맞아야 은행 쪽에서 “이 사람 맞다”고 응답을 준다는 건데, 처음엔 이게 왜 필요한지도 모른 채로 에러부터 받았습니다.

그래서 이 부분에 금액 체크 로직을 추가하는 펑션 개발을 진행했는데, 막상 붙여보니 진짜 문제는 따로 있었습니다.

은행은 20자리, VAN사는 14자리 — 이 차이가 전문을 통째로 흔들어놨다

전문(電文) 작업 하시는 분들은 아시겠지만, 필드 자리수 하나 틀리면 그 뒤에 오는 필드가 전부 밀립니다. 이번 건이 딱 그 케이스였습니다.

은행 쪽 스펙 문서에는 예금주성명 필드가 20자리로 정의돼 있었습니다. 근데 실제로 전문을 태워서 보내는 VAN사(예: LG CNS) 쪽 스펙은 14자리였습니다. 은행이 공식적으로 준 문서와, 실제 전문을 중계하는 VAN사의 자리수가 서로 다르게 잡혀 있었던 겁니다.

이게 왜 문제가 되냐면, 은행 스펙(20자리)대로 필드를 채워서 보내면 VAN사 입장에서는 자기네가 알고 있는 14자리 이후 시점부터 다음 필드를 읽기 시작합니다. 그러니 예금주성명 뒤에 와야 할 출금계좌번호, 금액 같은 값들이 전부 엉뚱한 위치로 밀려 들어가는 거죠. 겉으로 보면 “성명조회가 왜 안 되지?” 싶지만, 실제로는 자리수 불일치 때문에 애초에 은행이 필드 자체를 잘못 읽고 있었던 겁니다.

혹시 이런 경우 겪어보신 분 계신가요? 스펙 문서 믿고 그대로 개발했는데 실제 중계사 쪽 자리수는 다른 경우요. 이럴 땐 답이 하나입니다 — VAN사에 먼저 확인부터 받는 것. 문서보다 실제로 전문이 어떻게 흘러가는지가 우선입니다.

VAN사 답변: 예비 필드에 금액을 넣어서 테스트해보라

실제로 VAN사 쪽에 문의를 넣었고, 아래와 같은 답변을 받았습니다.

출금계좌번호 이후 예비부필드 13byte에 금액을 넣어서 보내보시기 바랍니다.
아래 형식대로 테스트에 전송해 보시고 결과 회신 주시기 바랍니다.
수취인성명조회(0400/440, 0410/440)

이 답변대로 필드를 다시 짜서 보냈더니 은행 쪽에 정상적으로 값이 들어갔습니다. 즉, 자리수 불일치로 밀려 있던 필드 위치를 VAN사가 실제로 쓰는 레이아웃 기준으로 다시 맞춘 거였습니다.

전문 필드 레이아웃 정리 (수취인성명조회 0400/440, 0410/440)

필드명 길이(byte) 시작 위치
은행코드 3 100
계좌번호 15 103
주민번호 14 118
예금주성명 14 132
출금계좌번호 16 146
금액 13 162
예비 125 175

보시다시피 예금주성명은 14자리(132번 위치부터)로 잡혀 있고, 그 뒤 출금계좌번호와 금액이 이어집니다. 우리은행 문서 기준 20자리로 필드를 채웠다면 이 뒷 필드들이 전부 어긋났을 겁니다.

 

참고 – Strucutre 정보

참고 소스: ZF_GET_ACCOUNT_NAME

아래는 이번에 금액 체크 로직을 추가해서 개발한 ZF_GET_ACCOUNT_NAME 펑션입니다. 흐름만 먼저 짚고 가면, 업체코드(ZTRFB2005) 조회 → 전문번호 생성 → 전문 구조체(ZFBS2006)에 값 세팅 → 계좌번호 복호화 → 펌뱅킹 전송(ZF_FILE_SEND) 순서입니다.

여기서 눈여겨봐야 할 부분이 두 군데입니다.

첫 번째는 금액 처리입니다. 처음엔 CURRENCY_AMOUNT_SAP_TO_IDOC 펑션으로 IDOC 포맷 변환을 시도했는데, 결국 변환된 원금액을 그대로 받아서 WRITE ... RIGHT-JUSTIFIED로 우측 정렬하고, ABS()로 절댓값 처리하는 방식으로 정리했습니다. 코드에 그 시행착오 흔적이 주석으로 남아 있는데, 일부러 지우지 않고 그대로 뒀습니다 — 이게 왜 이렇게 갔는지 나중에 다시 볼 때 도움이 되거든요.

두 번째는 계좌번호 복호화입니다. CONVERSION_EXIT_ZBANK_OUTPUT을 계좌번호(accno)와 출금계좌번호(oaccno) 양쪽에 다 태우고 있습니다. 이 부분 빠뜨리면 암호화된 계좌번호가 그대로 전문에 실려 나가니 주의하셔야 합니다.

FUNCTION ZF_GET_ACCOUNT_NAME.
*"----------------------------------------------------------------------
*"*"로컬 인터페이스:
*"  IMPORTING
*"     REFERENCE(I_BUKRS) LIKE BKPF-BUKRS
*"     REFERENCE(I_BNKCD) LIKE ZTRFB2035-BANKL
*"     REFERENCE(I_BANKN) LIKE T012K-BANKN
*"     REFERENCE(I_OUTAMT) LIKE ZTRFB2035-OUTAMT
*"  EXPORTING
*"     REFERENCE(E_REALN) TYPE ZTRFB2035-REALN
*"     REFERENCE(E_RETCD) TYPE ZTRFB2035-RETCD
*"     REFERENCE(E_TEXT) TYPE ZTRFB2006-RETCDT
*"----------------------------------------------------------------------
  DATA: l_docuno LIKE ztrfb2008-docuno,   "전문번호
        l_time   TYPE i.                  "응답시간

  DATA: l_subrc(1),
        lv_subrc LIKE sy-subrc,
        l_errmsg LIKE zfbs2001-err_msg.

  DATA: gs_data LIKE zfbs2004-data.

  CLEAR: e_retcd, e_realn, e_text.   "EXPORTING 이전값 제거
  CLEAR: l_time.                    "타임아웃 카운터 리셋


* 전문번호생성
  PERFORM create_docuno_rtn USING I_BUKRS sy-datum
                                   '020' '0400' '440'.   " gt_main-bankl

  CLEAR: zfbs2006.   "20260706 AI 전문구조 잔류값 제거

* 다음 구조의 값을 활용하자.
  zfbs2006-entcd   = ''.
  zfbs2006-trxcd   = ztrfb2005-trxcd.
  zfbs2006-bnkcd   = '20'.          "우리은행 ls_005-bnkcd. "은행코드(2자리)
  zfbs2006-docucd  = '0400'.        "전문코드
  zfbs2006-upmucd  = '440'.         "업무코드
  zfbs2006-sendno  = '1'.           "전송횟수
  zfbs2006-docuno  = gv_docuno .    "전문번호
  zfbs2006-sdate   = sy-datum.      "전송일자
  zfbs2006-stime   = sy-uzeit.      "전송시간
  zfbs2006-retcd   = ' '.           "응답코드
  zfbs2006-bigo    = ' '.           "예비

  zfbs2006-bankcd  = i_bnkcd.       "은행코드(3자리)
  zfbs2006-accno   = i_bankn.       "계좌번호
  zfbs2006-jumin   = ' '.
  zfbs2006-bname   = ' '.           "예금주명
  zfbs2006-oaccno  = ' '.
* zfbs2006-outamt = i_outamt*100.   "금액 필드 추가
* zfbs2006-outamt = i_outamt.       "금액 필드 추가

  DATA : LV_AMT(13) TYPE N.
  clear : lv_amt.

  IF i_outamt is not initial.

*   변환된 원금액을 그대로 받는다.
    WRITE i_outamt TO zfbs2006-outamt RIGHT-JUSTIFIED.   "금액추가
    lv_amt = abs( zfbs2006-outamt ).
    zfbs2006-outamt = lv_amt.

  endif.

* 수취인 조회 테이블 데이터 생성
 
*--> start : 계좌번호 복호화

  CALL FUNCTION 'CONVERSION_EXIT_ZBANK_OUTPUT'
    EXPORTING
      input  = zfbs2006-accno
    IMPORTING
      output = zfbs2006-accno.

  CALL FUNCTION 'CONVERSION_EXIT_ZBANK_OUTPUT'
    EXPORTING
      input  = zfbs2006-oaccno
    IMPORTING
      output = zfbs2006-oaccno.

*--> END : 계좌번호 복호화
  gs_data = zfbs2006.

* 펌뱅킹 데이터 전송
  "공통사용 대응
  CALL FUNCTION 'ZF_FILE_SEND'
    EXPORTING
      i_bukrs   = I_BUKRS
      i_data    = gs_data
    IMPORTING
      o_subrc   = l_subrc
      o_err_msg = l_errmsg.

ENDFUNCTION.

정리하며

이번 건 정리하면서 새삼 느낀 건, 펌뱅킹 개발에서 진짜 골치 아픈 건 로직 자체보다 기관마다 다른 전문 스펙이라는 겁니다. 은행이 준 문서, VAN사가 실제로 쓰는 레이아웃, 그리고 개발자가 짜는 코드 — 이 셋이 항상 일치한다는 보장이 없습니다.

가상계좌 금액 체크 이슈로 시작했다가 결국 자리수 불일치라는 전혀 다른 문제로 흘러간 케이스였는데, 이런 경험이 쌓이다 보면 다음 프로젝트에선 처음부터 VAN사 자리수부터 확인하고 들어가게 되더라고요. 펌뱅킹 실시간 인터페이스 설계 다룰 때도 이 자리수 이슈는 꼭 한 번 짚고 넘어가겠습니다.

 

댓글 남기기