수수료 계층별 정산 배치와 미입금 알림 화면 추가
목차
수수료 계층 정산은 건드릴 때마다 긴장이 된다. 금전 관련 로직이라 버그 하나가 신뢰 문제로 직결되고, 계층이 늘어날수록 검증 포인트도 따라서 늘어나기 때문이다. 이번에 정산 배치 로직과 미입금 알림 화면을 함께 추가하면서 몇 가지 정리할 게 생겼다.
계층별 차등 요율 구조가 왜 까다로운가
이 시스템의 수수료 모델은 유통 계층마다 요율이 다르게 붙는 차등 구조다. 하위 계층이 상위 계층보다 높은 요율을 부담하고, 그 차액이 상위 계층의 수익이 되는 방식이다. 직관적으로 보면 단순한데, 실제 계산 코드를 짜다 보면 경우의 수가 생각보다 많다.
| 계층 | 요율 | 마진(상위 대비) |
|---|---|---|
| 최하위 | 1.0% | - |
| 중간 | 0.8% | 0.2% |
| 최상위 | 0.6% | 0.2% |
여기에 비율 수수료만 있으면 그나마 단순한데, 건당 고정 수수료가 함께 붙는다. 결국 계산식은 이렇다.
// 비율 수수료 + 건당 고정 수수료 합산
long feeAmount = (long)(txAmount * feeRate) + perTxFee;
이 한 줄짜리처럼 보이는 코드에서 올림/버림 처리가 결과를 바꾼다. (long) 캐스팅은 소수점을 버리는 floor 처리다. 수수료를 납부하는 쪽에 유리한 방향이라 의도적인 선택이긴 한데, 이걸 명시적으로 주석에 남겨두지 않으면 나중에 누군가 Math.round()로 바꿔서 올림이 들어가는 사고가 생길 수 있다. 이번에 이 부분을 명시적으로 남겨뒀다.
올림/버림 정책은 분쟁을 줄이는 방향으로 잡는 게 일반적이다. 수수료를 내는 쪽은 floor, 수수료를 받는 쪽은 ceil 없이 그대로 - 둘 다 수수료 납부자에게 유리한 방향이다. 어느 쪽이든 1원 단위 차이지만, 대량 거래에서 누적되면 수십만 원이 되고 그게 곧 분쟁 소지가 된다.
계층별 요율 순서가 역전되면 마진이 음수가 되는 버그가 생긴다. 중간 계층이 최하위보다 낮은 요율을 받으면 차액이 마이너스가 되고, 이걸 계산하면 상위 계층이 오히려 수수료를 지불하는 형태가 된다. 실제로 요율 설정 화면에서 입력 순서를 잘못 넣으면 발생할 수 있는 케이스라 validation을 별도로 추가했다. 로직 자체보다 설정값 검증이 더 중요한 케이스다.
// 계층 요율 순서 검증 - 하위 계층 요율이 상위보다 낮으면 마진 음수
for (int i = 0; i < tiers.size() - 1; i++) {
if (tiers.get(i).getRate() <= tiers.get(i + 1).getRate()) {
throw new InvalidFeeConfigException(
"계층 " + i + " 요율이 상위 계층보다 낮거나 같습니다.");
}
}
정산 배치 멱등성과 미입금 알림
정산 배치에서 가장 중요한 특성은 멱등성이다. 같은 기간을 두 번 실행해도 결과가 동일해야 한다. 서버 이슈로 배치가 중간에 끊겼다가 재실행될 때, 이미 처리된 거래를 다시 집계하면 수수료가 두 배로 잡힌다.
구현 패턴은 크게 두 가지다.
- 정산 레코드에
settlement_id와period_key를 unique key로 걸고, 중복 insert 시 upsert나 skip 처리 - 배치 시작 전 해당 기간의 정산 상태를 먼저 조회해서 이미 완료된 경우 early return
두 방법 모두 쓰고 있는데, DB unique constraint를 최후 방어선으로 두는 게 더 안전하다. 애플리케이션 레벨 체크만 믿다가 race condition으로 중복 삽입이 발생하면 rollback 처리가 복잡해진다.
미입금 알림 화면은 별도 배치로 돌린다. 정산 기준일 이후에도 입금이 확인되지 않은 주문을 집계해서 알림 대상으로 올리는 구조다. 화면에서는 미입금 기간, 금액, 주문 건수를 우선순위 기준으로 정렬해서 보여준다. 금액 큰 건을 먼저 처리하는 게 운영 효율 면에서 낫고, 이걸 화면 단에서 정렬 기준으로 노출하면 담당자가 직접 판단할 수 있다.
정산 UI에서 숫자를 읽히게 만드는 것
정산 화면에서 사용자가 가장 오래 보는 건 결국 숫자다. 총 거래액, 수수료, 실수령액 세 가지가 명확하게 보여야 한다. 여기서 자주 놓치는 게 표기 일관성이다.
- 천 단위 구분자 일관 적용 (1,234,567원)
- 마이너스 금액은 색으로 구분 - 빨간색 텍스트 또는 괄호 표기
- 계층별 수수료 내역은 접을 수 있게 - 기본은 요약, 상세는 펼침
특히 정산 내역 화면에서 수수료 계산 근거를 보여주는 건 운영 측면에서 중요하다. "왜 이 금액이 나왔는가"를 화면에서 바로 확인할 수 있어야 CS 문의가 줄어든다. 계층별 요율, 적용 건수, 건당 고정 수수료 합계를 별도 테이블로 보여주는 정도면 충분하다.
이번 작업 규모 자체는 크지 않았다. 하지만 정산 배치나 수수료 로직은 한 번 잘못 나가면 복구가 복잡하다. 특히 이미 지급이 완료된 정산을 소급 수정해야 하는 상황은 그냥 골치 아픈 수준이 아니다. 이런 류의 작업은 변경 범위보다 검증 커버리지를 더 신경 쓰게 된다. validation 추가, 멱등성 보장, 올림/버림 정책 주석 - 전부 "나중에 누가 이 코드를 건드릴 때를 위한" 방어막이다.
댓글 0
첫 댓글 달아줘.