Skip to content

Commit 9c83f56

Browse files
authored
Merge pull request #47 from sumte-app/feat/#46-kakaopay-integration-api
[FEAT] 카카오페이 연동 구현
2 parents 9d63232 + e88b74d commit 9c83f56

17 files changed

+299
-117
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dependencies {
2727
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2828
implementation 'org.springframework.boot:spring-boot-starter-security'
2929
implementation 'org.springframework.boot:spring-boot-starter-web'
30+
implementation 'org.springframework.boot:spring-boot-starter-webflux'
3031
implementation 'org.springframework.boot:spring-boot-starter-validation' // 에러 핸들러 만들 때 씀
3132

3233
testImplementation 'org.springframework.boot:spring-boot-starter-test'

src/main/java/com/sumte/payment/controller/PaymentController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.sumte.payment.controller;
22

33
import com.sumte.apiPayload.ApiResponse;
4+
import com.sumte.payment.dto.KakaoPayApproveResponseDTO;
45
import com.sumte.payment.dto.PaymentRequestDTO;
56
import com.sumte.payment.dto.PaymentResponseDTO;
67
import com.sumte.payment.service.PaymentService;
@@ -33,11 +34,11 @@ public ResponseEntity<ApiResponse<PaymentResponseDTO.CreatePaymentDTO>> requestP
3334
summary = "결제 승인 처리 API",
3435
description = "PG사(예: 카카오페이) 결제 완료 후, 해당 결제 ID의 상태를 PAID로 변경합니다."
3536
)
36-
public ResponseEntity<ApiResponse<Void>> approvePayment(
37+
public ResponseEntity<ApiResponse<KakaoPayApproveResponseDTO>> approvePayment(
3738
@PathVariable("id") Long id,
3839
@RequestParam("pg_token") String pgToken) {
3940

40-
paymentService.approvePayment(id, pgToken);
41-
return ResponseEntity.ok(ApiResponse.success(null));
41+
KakaoPayApproveResponseDTO response = paymentService.approvePayment(id, pgToken);
42+
return ResponseEntity.ok(ApiResponse.success(response));
4243
}
4344
}

src/main/java/com/sumte/payment/converter/PaymentConverter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
public class PaymentConverter {
1111

1212
public static Payment toEntity(PaymentRequestDTO.CreatePaymentDTO dto, Reservation reservation) {
13+
PaymentMethod method = dto.getPaymentMethod() != null
14+
? dto.getPaymentMethod()
15+
: PaymentMethod.KAKAOPAY;
16+
1317
return Payment.builder()
1418
.reservation(reservation)
1519
.paidPrice(dto.getAmount())
16-
.paymentMethod(PaymentMethod.valueOf(dto.getPaymentMethod()))
20+
.paymentMethod(method)
1721
.paymentStatus(PaymentStatus.PENDING)
1822
.build();
1923
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.sumte.payment.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@Builder
8+
public class KakaoPayApproveRequestDTO {
9+
private String cid;
10+
private String tid;
11+
private String partner_order_id;
12+
private String partner_user_id;
13+
private String pg_token;
14+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.sumte.payment.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@Builder
8+
public class KakaoPayApproveResponseDTO {
9+
private String aid;
10+
private String tid;
11+
private String cid;
12+
private String partner_order_id;
13+
private String partner_user_id;
14+
private String payment_method_type;
15+
private Amount amount;
16+
17+
@Getter
18+
public static class Amount {
19+
private int total;
20+
private int tax_free;
21+
private int vat;
22+
}
23+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.sumte.payment.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
import org.springframework.util.LinkedMultiValueMap;
6+
import org.springframework.util.MultiValueMap;
7+
8+
@Getter
9+
@Builder
10+
public class KakaoPayReadyRequestDTO {
11+
private String cid;
12+
private String partner_order_id;
13+
private String partner_user_id;
14+
private String item_name;
15+
private String quantity;
16+
private String total_amount;
17+
private String tax_free_amount;
18+
private String approval_url;
19+
private String cancel_url;
20+
private String fail_url;
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.sumte.payment.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@Builder
8+
public class KakaoPayReadyResponseDTO {
9+
private String tid;
10+
private String next_redirect_app_url;
11+
private String next_redirect_pc_url;
12+
private String created_at;
13+
}

src/main/java/com/sumte/payment/dto/PaymentRequestDTO.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.sumte.payment.dto;
22

3+
import com.sumte.payment.entity.PaymentMethod;
34
import lombok.AllArgsConstructor;
45
import lombok.Builder;
56
import lombok.Getter;
@@ -14,6 +15,6 @@ public class PaymentRequestDTO {
1415
public static class CreatePaymentDTO {
1516
private Long reservationId;
1617
private Long amount;
17-
private String paymentMethod;
18+
private PaymentMethod paymentMethod;
1819
}
1920
}

src/main/java/com/sumte/payment/entity/Payment.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,8 @@ public void markAsFailed() {
5252
public void markAsRefunded() {
5353
this.paymentStatus = PaymentStatus.REFUNDED;
5454
}
55+
56+
public void setTid(String tid) {
57+
this.tid = tid;
58+
}
5559
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.sumte.payment.kakaopay;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.sumte.payment.dto.KakaoPayApproveRequestDTO;
5+
import com.sumte.payment.dto.KakaoPayApproveResponseDTO;
6+
import com.sumte.payment.dto.KakaoPayReadyRequestDTO;
7+
import com.sumte.payment.dto.KakaoPayReadyResponseDTO;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.stereotype.Component;
11+
import org.springframework.web.reactive.function.client.WebClient;
12+
13+
@Component
14+
@RequiredArgsConstructor
15+
public class KakaoPayClient {
16+
17+
private final WebClient webClient;
18+
private final ObjectMapper objectMapper;
19+
20+
@Value("${kakao.pay.secret-key}")
21+
private String adminKey;
22+
23+
public KakaoPayReadyResponseDTO requestPayment(KakaoPayReadyRequestDTO request) {
24+
return webClient.post()
25+
.uri("https://open-api.kakaopay.com/online/v1/payment/ready")
26+
.header("Authorization", "SECRET_KEY " + adminKey)
27+
.header("Content-Type", "application/json")
28+
.bodyValue(request)
29+
.retrieve()
30+
.bodyToMono(KakaoPayReadyResponseDTO.class)
31+
.block();
32+
}
33+
34+
public KakaoPayApproveResponseDTO approvePayment(KakaoPayApproveRequestDTO request) {
35+
return webClient.post()
36+
.uri("https://open-api.kakaopay.com/online/v1/payment/approve")
37+
.header("Authorization", "SECRET_KEY " + adminKey)
38+
.header("Content-Type", "application/json")
39+
.bodyValue(request)
40+
.retrieve()
41+
.bodyToMono(KakaoPayApproveResponseDTO.class)
42+
.block();
43+
}
44+
}

0 commit comments

Comments
 (0)