안녕하세요. 아는형입니다.
파생상품 세팅을 할 때마다 느끼는 건데, 이론적으로 IMG 다 맞춰놨다고 안심하면 꼭 한 번씩 뒤통수를 맞습니다. 이번엔 CRS(Cross Currency Interest Rate Swap, 통화이자율스왑)였습니다.
TPM18에서 조회가 안 된다? IMG는 분명 멀쩡한데
프로젝트 수행 중인 회사에서 파생상품 중 하나로 CRS를 쓰겠다고 하셔서, 금융상품 Setting부터 차근차근 진행했습니다. 상품 생성까지는 순조로웠어요. 그런데 문제는 그다음, 환차전기를 위해 TPM18을 실행하는 순간 터졌습니다.
조회가 안 됩니다. 아예.
이럴 때 제일 먼저 하는 게 IMG 재확인이죠. 포지션 관리 절차, Update Type 지정, 다 다시 훑어봤습니다. 그런데 이상하게 문제가 없어요. 설정은 표준대로 다 되어 있는데 TPM18에서는 요지부동입니다. 이쯤 되면 슬슬 당황스러워지기 시작하는데요, 혹시 이런 경험 있으신 분 계신가요? 분명 설정은 맞는데 트랜잭션이 반응을 안 하는 그 답답함.
결국 IMG를 아무리 뒤져도 안 나오는 문제였다는 게 이 케이스의 핵심입니다. 설정의 문제가 아니라 로직의 문제였거든요.

SAP Note를 뒤지다 만난 921346 — CCIRS는 원래 이렇다
당황한 채로 SAP Note를 뒤지기 시작했고, 한참을 파다가 SAP Note 921346 – Sample implementation for BAdI TPM_TRL_MANIPULATE을 찾았습니다.
내용을 뜯어보니 이게 딱 제 상황이었어요. 요약하면 이렇습니다. CCIRS(통화이자율스왑)는 외화 명목금액을 갖고 있는데, 이 외화 명목금액이 환율 변동에 따라 평가통화로 환산했을 때 손익이 생깁니다. 그런데 표준 TRL(Transaction Result Ledger) 로직이 생성하는 파생 흐름(Derived Flow)만으로는 이 통화별 환차손익이 자동으로 분리 계산되지 않아요. 그래서 SAP이 이 부분을 처리하라고 별도로 던져준 게 TPM_TRL_MANIPULATE라는 BAdI였던 겁니다.
정리하면 이렇습니다.
- 대상: Interest Currency Swap / CCIRS
- 계산 기준: 외화 명목금액을 평가통화로 환산한 금액의 변화
- 결과: 외화별로 별도의 Price Gain/Loss Flow 생성
- 사용 BAdI:
TPM_TRL_MANIPULATE - 구현 메서드:
MANIPULATE_DERIVED_FLOWS - 필수 전제조건: 관련 Nominal Flow의 Position Change Category가
1006 – Indirect Position Change - 손익 Update Type: 파생 비즈니스 트랜잭션 설정의 필드 13, 14에 지정된 Update Type
즉 이 Note가 주는 건 “누르면 되는 자동 기능”이 아니라, 샘플 ABAP 로직입니다. SAP 표준에서는 파생 비즈니스 트랜잭션을 포지션관리절차별로 설정하고, 여기서 생성된 파생 흐름이 TPM10, TPM18, TPM27 같은 프로세스와 연결되는 구조인데, CCIRS의 경우 이 표준 흐름 생성 로직에 이 BAdI로 손봐야 할 여지가 남아있는 셈이죠.
Note 원문 Symptom 항목도 그대로 옮겨보면 이렇습니다.
This note delivers a sample implementation for the Business Add-in (BAdI) TPM_TRL_MANIPULATE. The sample implementation calculates the price gains in valuation currency for interest currency swaps by calculating the difference between the nominal changes in valuation currency. A separate price gain flow is created for every foreign currency.
그리고 Solution 항목에는 이렇게 나와 있었어요.
To use the sample implementation, use Transaction SE19 to create a new implementation of the BAdI TPM_TRL_MANIPULATE. Copy the source code of the sample implementation (use Transaction SE18 to do this) to the method MANIPULATE_DERIVED_FLOWS and activate the new implementation.
자, 여기까지가 배경이고, 이제 진짜 작업이 시작되는 지점입니다.
SE19에서 BAdI 구현체 만들기
먼저 SE19로 들어갑니다. Classic BAdI를 선택하고, BAdI Name에 TPM_TRL_MANIPULATE를 입력한 뒤 Create를 누릅니다.

Create Implementation 팝업이 뜨면 Definition Name은 TPM_TRL_MANIPULATE로 고정되어 있고, Implementation Name에 저는 ZTPM_TRL_MANIPULATE로 명명했습니다. 사내 네이밍 규칙에 맞춰 접두어만 Z로 바꾼 정도입니다.

생성 직후에는 Implementation Short Text에 ZTPM_TRL_MANIPULATE를 적어주고, Runtime Behavior는 아직 Implementation will not be called 상태입니다. 당연한 거예요, 아직 활성화 전이니까요. Properties 탭에서 개발클래스(Package)는 ZTEST001로 지정했고, Person Responsible과 오리지널 시스템 정보를 채웠습니다.

이 단계에서 오브젝트 디렉토리 지정 팝업이 뜨고, Workbench Request를 새로 생성하게 됩니다. 저는 Short Description에 [TR] ZTPM_TRL_MANIPULATE badi 적용_2024.07.25 이런 식으로 적어서 나중에 이관할 때 헷갈리지 않게 해뒀습니다.
여기서 재밌는 게, Implementation을 생성하면 자동으로 Implementing Class가 하나 붙습니다. 저는 ZCL_IM_TPM_TRL_MANIPULATE가 자동 생성됐고, Interface 탭을 보면 이 클래스가 구현해야 할 메서드 목록이 쭉 나옵니다.
| Method | 설명 |
|---|---|
CHANGE_TITLE_VALUATION |
For Changes to Security Valuation Amounts |
MANIPULATE_DERIVED_FLOWS |
For Manipulating Flows from Derived Business Transactions (이번에 쓸 메서드) |
MANIPULATE_VALUATION_FLOWS |
For Manipulating Flows from Valuations |
MANIPULATE_CALC_BASIS |
For Manipulating Calculation Basis of a Valuation Step |
EXCL_OTC_FROM_VALUATION |
Exclude OTC Transaction from Valuation |
Note에서 지목한 대로 MANIPULATE_DERIVED_FLOWS를 더블클릭해서 코드 편집 화면으로 들어갔습니다. 여기에 SE18에서 확인한 샘플 로직을 옮겨 담는 겁니다.

코드 상단에는 CCIRS 케이스에서 외화의 유출입 흐름을 상계해서 평가통화 기준 손익을 계산한다는 주석과, Note 921346을 참조했다는 표시를 남겨뒀습니다. 저희 팀 Rule에 따라 변경 이력에는 날짜와 작성자 이니셜을 남기는 방식을 그대로 따랐고요.
구조상으로는 외화별 평가금액을 담을 내부 테이블(t_tab_profit_fx)을 선언하고, 포지션 식별자(lp_identifier)를 통해 차이값(l_diff_values)을 가져오는 흐름입니다. 그리고 이 로직이 아무 때나 도는 게 아니라, 거래 종료나 실행 시점에만 동작하도록 CHECK 문으로 비즈니스 트랜잭션 카테고리를 걸러주고 있었습니다.
여기서 삽질 좀 했는데요, CHECK 문 조건에 어떤 비즈니스 트랜잭션 카테고리 상수들을 넣을지가 은근 헷갈렸습니다. Deal Close, Cash Settlement 같은 종료/정산 케이스만 태우도록 잡아야 다른 프로세스에서 엉뚱하게 흐름이 추가되는 걸 막을 수 있습니다.
코드를 다 옮기고 저장한 뒤, Implementation을 Activate 하면 하단에 “BAdI implementation ZTPM_TRL_MANIPULATE has been activated” 메시지가 뜹니다. 이 메시지 뜨는 순간이 은근 짜릿합니다.

IMG에서 화룡점정 — Update Type과 포지션 변경범주 지정
BAdI만 만들어놓는다고 끝이 아닙니다. Note 921346에 명시된 전제조건, 그러니까 관련 Nominal Flow가 Position Change Category 1006(간접 포지션 변경)로 지정되어야 한다는 부분을 IMG에서 채워줘야 합니다.
경로는 포지션 관리 설정 > 주요 일자 평가 > 포지션 구성요소의 업데이트 유형 영향 설정입니다. 여기서 신규 엔트리로 아래처럼 지정했습니다.
| U유형 | 경신 유형 텍스트 | VA | PCC | 포지션 변경 범주 |
|---|---|---|---|---|
DE1120+ |
계약 (전기관련) | 2500 | 1006 | 간접 포지션 변경 |
DE1120- |
계약 (전기관련) | 2500 | 1006 | 간접 포지션 변경 |

그다음이 Note에서 말한 필드 13, 14 부분입니다. 경로는 파생 비즈니스 트랜잭션 > 업데이트 유형 > 파생 비즈니스 트랜잭션의 업데이트 유형 지정이고, 여기서 포지션 관리 절차 7300 – OTC 파생 상품: 평가하지 않음의 실현 이익/손실 화면으로 들어가면 됩니다.
이 화면에서 외환 거래 섹션을 보면 필드 13, 14가 있습니다.
| 필드 번호 | 항목 | Update Type |
|---|---|---|
| 13 | 환차익(표준) | DBT_B013 |
| 14 | 환차손(표준) | DBT_B014 |
바로 이 DBT_B013, DBT_B014가 Note 921346에서 말한 “필드 13과 14에 지정된 Update Type”의 실체였던 겁니다. 이 두 개가 잡혀있어야 BAdI가 계산한 통화별 환차손익 흐름이 실제 Update Type을 달고 전표에 반영될 수 있어요.


참고로 이 포지션 관리 절차 7300은 이름 그대로 “평가하지 않음”이라 단계 1~4가 비어있는 게 정상입니다. 별도의 평가 스텝 없이 동일 구성요소로 전송(전송 범주: 동일한 구성요소에 전기)만 처리하는 절차거든요. 그리고 이 절차가 실제로 어느 거래에 적용되는지는 포지션 관리절차 지정 화면에서 회사코드/평가그룹/상품유형/Portfolio/증권 계정 그룹 조합별로 매핑되어 있는 걸 확인할 수 있습니다. 이번 건은 1000 / 001 / 0 / 620 조합이 7300 절차로 연결되어 있었습니다.

마무리하며
결국 이 문제는 IMG 설정이 틀려서가 아니라, CCIRS 특유의 외화별 환산 손익 계산을 표준 로직이 알아서 해주지 않는다는 걸 몰라서 생긴 문제였습니다. Note 하나 찾아내는 데 시간이 좀 걸렸지만, 찾고 나니 오히려 명쾌했어요. BAdI 하나, IMG 두 군데. 딱 그 정도 손을 대면 되는 거였습니다.
다음에는 이 포지션 관리 절차들이 실제로 배치/실시간 인터페이스 설계와 어떻게 맞물리는지, 펌뱅킹 실시간 인터페이스 설계 이야기할 때 한 번 더 짚어보겠습니다.