11package com .loopers .infrastructure .payment .pg ;
22
3+ import com .loopers .domain .payment .CardType ;
4+ import com .loopers .domain .payment .gateway .PgGateway ;
35import io .github .resilience4j .circuitbreaker .annotation .CircuitBreaker ;
46import io .github .resilience4j .retry .annotation .Retry ;
57import io .github .resilience4j .timelimiter .annotation .TimeLimiter ;
1719
1820@ Slf4j
1921@ Component
20- public class PgPaymentClient {
22+ public class PgPaymentClient implements PgGateway {
2123
2224 private final RestTemplate pgRestTemplate ;
2325
@@ -30,23 +32,26 @@ public PgPaymentClient(RestTemplate pgRestTemplate) {
3032 this .pgRestTemplate = pgRestTemplate ;
3133 }
3234
33- /**
34- * 결제 요청 API
35- * - CircuitBreaker: PG 장애 시 빠른 실패
36- * - Retry: 일시적 오류 시 재시도
37- * - TimeLimiter: 2초 타임아웃
38- */
35+ @ Override
3936 @ CircuitBreaker (name = PG_INSTANCE , fallbackMethod = "requestPaymentFallback" )
4037 @ Retry (name = PG_INSTANCE )
4138 @ TimeLimiter (name = PG_INSTANCE )
42- public CompletableFuture <PgPaymentResponse > requestPayment (String userId , PgPaymentRequest request ) {
39+ public CompletableFuture <PgPaymentResult > requestPayment (String userId , PgPaymentCommand command ) {
4340 return CompletableFuture .supplyAsync (() -> {
44- log .info ("[PG] 결제 요청 시작 - orderId: {}, amount: {}" , request .orderId (), request .amount ());
41+ log .info ("[PG] 결제 요청 시작 - orderId: {}, amount: {}" , command .orderId (), command .amount ());
4542
4643 HttpHeaders headers = new HttpHeaders ();
4744 headers .set ("X-USER-ID" , userId );
4845 headers .set ("Content-Type" , "application/json" );
4946
47+ PgPaymentRequest request = new PgPaymentRequest (
48+ command .orderId (),
49+ toPgCardType (command .cardType ()),
50+ command .cardNo (),
51+ command .amount (),
52+ command .callbackUrl ()
53+ );
54+
5055 HttpEntity <PgPaymentRequest > entity = new HttpEntity <>(request , headers );
5156
5257 try {
@@ -62,25 +67,25 @@ public CompletableFuture<PgPaymentResponse> requestPayment(String userId, PgPaym
6267 PgPaymentResponse paymentResponse = response .getBody ().data ();
6368 log .info ("[PG] 결제 요청 성공 - transactionKey: {}, status: {}" ,
6469 paymentResponse .transactionKey (), paymentResponse .status ());
65- return paymentResponse ;
70+ return new PgPaymentResult (
71+ paymentResponse .transactionKey (),
72+ toPgTransactionStatus (paymentResponse .status ()),
73+ paymentResponse .reason ()
74+ );
6675 } else {
6776 throw new PgCommunicationException ("PG 응답이 비어있습니다." );
6877 }
6978 } catch (RestClientException e ) {
70- log .error ("[PG] 결제 요청 실패 - orderId: {}" , request .orderId (), e );
79+ log .error ("[PG] 결제 요청 실패 - orderId: {}" , command .orderId (), e );
7180 throw new PgCommunicationException ("PG 통신 실패" , e );
7281 }
7382 });
7483 }
7584
76- /**
77- * 결제 상태 조회 API
78- * - CircuitBreaker 적용
79- * - Retry 적용
80- */
85+ @ Override
8186 @ CircuitBreaker (name = PG_INSTANCE , fallbackMethod = "getPaymentStatusFallback" )
8287 @ Retry (name = PG_INSTANCE )
83- public PgPaymentDetailResponse getPaymentStatus (String userId , String transactionKey ) {
88+ public PgPaymentDetail getPaymentStatus (String userId , String transactionKey ) {
8489 log .info ("[PG] 결제 상태 조회 - transactionKey: {}" , transactionKey );
8590
8691 HttpHeaders headers = new HttpHeaders ();
@@ -101,7 +106,15 @@ public PgPaymentDetailResponse getPaymentStatus(String userId, String transactio
101106 PgPaymentDetailResponse detailResponse = response .getBody ().data ();
102107 log .info ("[PG] 결제 상태 조회 성공 - transactionKey: {}, status: {}" ,
103108 transactionKey , detailResponse .status ());
104- return detailResponse ;
109+ return new PgPaymentDetail (
110+ detailResponse .transactionKey (),
111+ detailResponse .orderId (),
112+ toCardType (detailResponse .cardType ()),
113+ detailResponse .cardNo (),
114+ detailResponse .amount (),
115+ toPgTransactionStatus (detailResponse .status ()),
116+ detailResponse .reason ()
117+ );
105118 } else {
106119 throw new PgCommunicationException ("PG 응답이 비어있습니다." );
107120 }
@@ -111,69 +124,60 @@ public PgPaymentDetailResponse getPaymentStatus(String userId, String transactio
111124 }
112125 }
113126
114- // ========== Fallback Methods ==========
115-
116- /**
117- * 결제 요청 Fallback
118- * - Circuit Open 또는 재시도 실패 시 호출
119- * - transactionKey를 null로 반환하여 재시도 필요함을 표시
120- */
121- private CompletableFuture <PgPaymentResponse > requestPaymentFallback (
127+ private CompletableFuture <PgPaymentResult > requestPaymentFallback (
122128 String userId ,
123- PgPaymentRequest request ,
129+ PgPaymentCommand command ,
124130 Exception ex
125131 ) {
126132 log .error ("[PG Fallback] 결제 요청 실패 - orderId: {}, error: {}" ,
127- request .orderId (), ex .getMessage ());
133+ command .orderId (), ex .getMessage ());
128134
129- // transactionKey를 null로 반환하여 PG 장애를 명확히 표시
130- // Service 레이어에서 이를 감지하고 requiresRetry 플래그 설정
131- PgPaymentResponse fallbackResponse = new PgPaymentResponse (
132- null , // transactionKey가 없음 = PG 호출 실패
133- PgPaymentResponse .PgTransactionStatus .PENDING ,
135+ PgPaymentResult fallbackResponse = new PgPaymentResult (
136+ null ,
137+ PgTransactionStatus .PENDING ,
134138 "PG 시스템 일시 장애 - 나중에 재시도가 필요합니다."
135139 );
136140
137141 return CompletableFuture .completedFuture (fallbackResponse );
138142 }
139143
140- /**
141- * 결제 상태 조회 Fallback
142- * - 조회 실패 시 PENDING 상태로 반환
143- */
144- private PgPaymentDetailResponse getPaymentStatusFallback (
144+ private PgPaymentDetail getPaymentStatusFallback (
145145 String userId ,
146146 String transactionKey ,
147147 Exception ex
148148 ) {
149149 log .warn ("[PG Fallback] 결제 상태 조회 실패, PENDING 상태로 반환 - transactionKey: {}, error: {}" ,
150150 transactionKey , ex .getMessage ());
151151
152- return new PgPaymentDetailResponse (
152+ return new PgPaymentDetail (
153153 transactionKey ,
154154 "UNKNOWN" ,
155155 null ,
156156 "****-****-****-****" ,
157157 0L ,
158- PgPaymentResponse . PgTransactionStatus .PENDING ,
158+ PgTransactionStatus .PENDING ,
159159 "PG 시스템 일시 장애 - 결제 상태를 확인할 수 없습니다."
160160 );
161161 }
162162
163- // ========== Helper Classes ==========
163+ private PgPaymentRequest .PgCardType toPgCardType (CardType cardType ) {
164+ return PgPaymentRequest .PgCardType .valueOf (cardType .name ());
165+ }
166+
167+ private CardType toCardType (PgPaymentRequest .PgCardType cardType ) {
168+ return CardType .valueOf (cardType .name ());
169+ }
170+
171+ private PgTransactionStatus toPgTransactionStatus (PgPaymentResponse .PgTransactionStatus status ) {
172+ return PgTransactionStatus .valueOf (status .name ());
173+ }
164174
165- /**
166- * PG API 응답 래퍼
167- */
168175 public record PgApiResponse <T >(
169176 String result ,
170177 String message ,
171178 T data
172179 ) {}
173180
174- /**
175- * PG 통신 예외
176- */
177181 public static class PgCommunicationException extends RuntimeException {
178182 public PgCommunicationException (String message ) {
179183 super (message );
0 commit comments