결제 수수료 정산을 지연 차감 방식으로 전환해 환불 흐름 단순화
목차
배경
결제 플랫폼에서 파트너에게 부과되는 수수료를 결제 즉시 차감하는 기존 로직이 있었음. 문제는 이커머스 특성상 결제 후에도 환불/취소가 빈번하게 일어난다는 점. 즉시 차감해버리면 환불이 들어왔을 때 수수료를 다시 환원해야 하는데, 이 역방향 흐름이 곳곳에서 깨지고 있었음.
흐름 재설계
결제대행사에서 정산 데이터가 넘어오는 시점을 기준으로 상태를 다시 잡았음.
| 단계 | 상태 | 시점 |
|---|---|---|
| 결제 발생 | PENDING | 즉시 3건 생성 |
| 가상계좌 확정 | COMPLETED | 결제 +2시간 |
| 카드 확정 | COMPLETED | 결제 +3일 |
| 홀딩 중 환불 | CANCELLED | 잔액 변동 0 |
핵심은 PENDING 단계에서 잔액에 손대지 않는다는 것. COMPLETED로 넘어가는 순간에만 파트너 잔액이 움직임. 환불이 홀딩 중 들어오면 그냥 CANCELLED로 마킹하고 끝.
구현하면서 막힌 지점
- 3건 동시 생성: 충전수수료, 결제수수료, 판매대금이 한 트랜잭션에서 같이 PENDING으로 박혀야 했음. 하나라도 빠지면 정산 검수 때 차이남.
- 상태 전환 단일 진입점: 곳곳에서 상태를 바꾸지 못하게 단일 메서드로 막아두고, 잔액 차감/지급도 그 안에서만 호출되도록 묶었음.
- 마진 계산: 가맹점이 1.0% 부담, 총판이 0.8%면 차액 0.2%가 총판 수익. 위로 갈수록 요율이 낮아지고 차액이 각 상위 계층의 수익으로 떨어지는 구조라, COMPLETED 시점에 계층별로 분배 레코드를 같이 박았음.
핵심 쿼리 한 토막
UPDATE charge_history
SET status = 'COMPLETED',
confirmed_at = NOW()
WHERE order_id = #{orderId}
AND status = 'PENDING'
AND status = 'PENDING' 이 진짜 핵심. 이미 CANCELLED로 넘어간 건은 절대 COMPLETED로 못 가게 막았음. 동시성 들어와도 한 번만 차감되도록.
회고
- 즉시 차감 → 지연 차감으로 바꿨더니 환불 흐름이 단순해짐. 역방향 보정 코드를 통째로 들어냈음.
- PENDING/COMPLETED/CANCELLED 3상태로 줄이니 정산 보고서가 깔끔해짐. 검수 담당자가 한 번에 이해함.
- 가장 위험했던 건 기존 데이터 마이그레이션. 운영 중인 미정산 건들이 PENDING으로 잡혀야 했는데, 일부가 이미 차감된 상태라 백필 스크립트를 별도로 짰음.
- 즉시 차감의 유혹은 코드량이 적어서 생기는 듯함. 시간축이 들어가는 도메인은 결국 상태머신으로 가는 게 답.
- 홀딩 기간을 결제 수단별로 동적 설정하는 화면 붙이는 건 다음 작업으로 미뤄둠.
다음
댓글 0
첫 댓글 달아줘.