0. 서론
가상계좌를 새로 개발해야하는 요구사항이 들어와서 개발하게 되었습니다.
- 기존 모듈에서는 고객이 가상계좌를 취소할 수 없었습니다
- 기존 모듈은 특정 기기에서 결제를 하지 못하는 이슈가 있었습니다. 구 모듈에서는 모바일, PC창을 구분해서 결제창을 랜더링 해줘야하는데 특정 기기에서 결제창을 오픈하지 못했습니다. 그 이유는 User-Agent 로 모바일 또는 PC을 구분했었는데 글로벌 커머스를 운영하다보니 커스텀하게 관리해보려 했으나 관리가 쉽지 않았습니다.
1. 가상계좌 이해하기
가상계좌 결제 입금
카드 결제는 결제를 요청하면 인증 → 승인 → 매입 절차로 즉각 이뤄져 동기로 이뤄지는 반면 가상계좌는 결제를 요청하면 가상계좌만 발급된 상태입니다. 발급 받은 상황에서는 X일 이내 입급 완료할 수 있게 세팅이 되어있고 고객이 가상계좌에 입금을 해야 결제가 완료됩니다.
가상계좌 결제 취소
고객이 가상계좌에 입금을 아직 안 했다면, 결제를 취소해도 환불해야 되는 금액이 없는 상태입니다. 해당 상태는 가상 계좌 발급 취소에 해당하는 상태입니다.
고객이 가상계좌에 입금한 이후에 결제를 취소하면 금액을 환불해야 됩니다. 근데 가상계좌에 입금한 고객의 계좌 정보를 자동으로 알 수 없어요. 가상계좌 결제가 취소되면 고객으로부터 직접 환불계좌 정보를 입력 받아야 합니다. 환불계좌의 은행명, 계좌번호, 예금주 정보가 필요합니다.
2. 가상계좌 플로우 이해하기
가상계좌를 연동할 때 반드시 필요한 부분이 가상 계좌 웹훅이 필수적입니다. 가상 계좌 웹훅 연동이 반드시 필요한 이유는 신용카드와 다르게 동기로 이뤄지는 반면 가상계좌는 결제를 요청하면 가상계좌만 발급된 상태입니다. 이후, 고객이 입급을 하게되면 이때 결제 완료 처리를 하기 때문에 구매자가 결제를 완료하는 시점을 직접 결정하는 결제수단입니다.
가상계좌 플로우를 이해하기 위해 다음과 같이 가정합니다.
- 결제를 처리하는 결제 서비스, 주문을 처리하는 주문 서비스, 재고를 처리하는 재고 서비스가 있다고 가정합니다
- 재고 서비스는 계좌 발급 완료 시점에 재고를 차감한다고 가정합니다.
- 결제, 주문(재고) 서비스 MSA 구조로 분리되어있다고 가정합니다.
결제 플로우를 알아보기전에 중요하게 고려해야할 점입니다.
- 토스의 가상계좌 웹훅은 발급된 이후 일정 시간이 지나면 입금 자체는 PG사에서 Block을 해주지만 만료처리를 해줘야 했습니다. 만료 처리가 필요한 이유는 계좌 발급시점이 주문 완료 시점이었기 때문에 주문한 재고를 잡아야하기 때문입니다. 이를 위해 잡은 재고를 다시 취소해야 해서 관련 처리가 필요합니다.
- 결제 상태 변경 웹훅과는 다른 입금 오류 상황이 있습니다. 해당 상황은 은행에서 입금처리중 오류 발생으로 정상적으로 입금이 되지 않는 경우 발생합니다. 그리고 해당 케이스는 최소는 1초 ~ 최대는 99.5% 는 2분안에 발생한다고 합니다.
- 토스에서 제공하는 웹훅이 PAYMENT_STATUS_CHANGED , DEPOSIT_CALLBACK 이 있습니다. 2개의 웹훅은 서로 완전히 목적이 다른 웹훅입니다. 좀 더 부연 설명하자면, 2개의 웹훅이 연동된 상태라면 가상계좌로 결제 이벤트가 변경될 시 PAYMENT_STATUS_CHANGED 에도 이벤트 수신이 가능하고, DEPOSIT_CALLBACK 둘 다 수신이 된다는 점입니다.
3. 가상계좌 결제 플로우 설계
위의 요구사항을 위해서는 웹훅 연동, 만료 배치 처리, 롤백 처리 3가지가 필요했습니다. 차례대로 플로우를 알아보겠습니다.
가상계좌 웹훅(결제 완료)
가상 계좌 웹훅을 연동하며 결제 완료 처리를 진행한 플로우 입니다. 가상계좌는 발급 ~ 입금 완료 까지 동시에 처리되지 않기 때문에 입금 대기(계좌 발급)와 입금 완료로 나눠보겠습니다.
입금 대기
- 고객이 주문을 시도하며 PG사와 통신을 한다
- 인증이 완료되었다면 인증 결과를 결제 서비스로 통보해준다
- 인증 결과를 받고 결제 서비스는 결제 발급 요청을 한다
- PG사에서는 발급 처리가 된다면 입금 대기 웹훅을 전송해준다. 가상계좌 발급을 호출하면 WAITING_FOR_DEPOSIT 이벤트를 수신받는다.
- 수신 받은 웹훅을 입금 대기 이벤트에 등록한다
- 가상 계좌 입금 대기를 수신받는다
- 입금 대기를 처리한다
- 고객에게 입금해야할 가상 계좌 발급 정보를 전달한다
- 재고 이벤트를 등록한다
- 재고 이벤트 Worker는 재고 차감 이벤트를 수신 받는다
- Redis로 부터 재고 락을 획득한다(동시성 문제를 해결하기 위해 분산락을 사용한다고 가정하겠습니다)
- 재고 차감 및 주문 완료 처리를 한다
- 락을 해제한다.
- 처리 완료
입금 완료
- 고객은 입금 정보를 보고 입금을 합니다
- 입금을 하게되면 DONE 을 수신받습니다. 이 때 롤백이 될 수 있기 때문에 특정 시점 이후에 결제를 할 수 있도록 지연 큐에 넣습니다
- 지연 큐에 넣고, 별다른 롤백 이벤트가 발생하지 않는다면 결제 서비스가 수신을 받습니다.
- 입금 오류가 발생한다면 아래에 입금 오류 이벤트를 참고해주세요
- 결제 서비스는 결제 처리 중 → 결제 완료를 처리합니다
- 결제 완료를 할 경우, 쇼핑 서비스에 주문 완료 처리를 처리하기 위해 주문 서비스로 이벤트를 던집니다.
- 주문 서비스는 선으로 잡았던 재고를 잡았기 때문에 재고 처리를 제외한 주문 완료 처리를 수행합니다.
가상계좌 웹훅(입금 오류)
입금 오류는 은행에서 입금처리중 오류 발생으로 정상적으로 입금이 되지 않는 경우 발생합니다. 그리고 해당 케이스는 최소는 1초 ~ 최대는 99.5% 는 2분안에 발생한다고 위해서 설명했습니다.
- 입금 오류가 발생했다면 가상계좌 발급은 다시 발급 상태로 돌아가게 되고 발급 상태 이벤트를 수신받습니다.
- 가상계좌 발급 상태로 돌아가게 되면 토스에서 안내해준대로 결제 고객에게 다시 입급하도록 안내해야합니다.
- 다시 입금을 처리할 수 있도록 결제 완료를 롤백하는 처리를 진행합니다.
- 결제 완료 → 결제 처리 중
- 주문 완료 → 주문 처리 중
- 롤백 처리가 완료되었다면 이를 위해 고객 SMS로 입금 재안내를 해주도록 이벤트를 전송했습니다
가상계좌 만료
가상계좌 만료는 PG사에서 입금시간이 지나면 입금이 되지 않지만 가상계좌 발급을 할 때 재고를 먼저 잡았기 때문에 만료 처리가 필요했습니다. 다만, 별도로 토스에서 웹훅을 지원하지 않았기에 직접 구현이 필요했습니다. 만료를 처리하기 위해 배치 서비스를 이용했습니다.
- 배치 서비스에서 특정 시간 간격으로 결제 만료 이벤트를 큐에 등록 및 체크
- 만료 이벤트 등록
- 결제 서비스는 이벤트를 수신받고 만료할 주문을 체크합니다
- 만료시킬 주문 대상이 있다면 결제 처리 중 → 결제 만료로 상태를 변경합니다
- 결제 만료 처리가 완료된다면 선으로 잡았던 재고를 다시 복구 해줘야 하기에 주문 서비스에 재고 복구 이벤트 큐에 등록합니다
- 주문 서비스는 재고 복구 이벤트를 수신받습니다
- 재고 복구 및 주문 완료 처리를 진행합니다.
4. 정리
토스 가상계좌 웹훅을 이용하여 가상계좌 처리를 플로우를 알아봤습니다.
다음에 기회가 된다면 코드로 작성해보겠습니다.
댓글