Skip to content

Commit

Permalink
feat: 결제승인 API 테스트 코드
Browse files Browse the repository at this point in the history
  • Loading branch information
binarywoo27 committed Nov 24, 2023
1 parent 52c4924 commit 7a1797a
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 18 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation group: 'io.github.lotteon-maven', name: 'blooming-blooms-utils', version: '0.1.0-alpha2'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.mock-server:mockserver-netty:5.11.2' // 사용 중인 MockServer 버전
}

dependencyManagement {
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/kr/bb/payment/config/RestTemplateConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kr.bb.payment.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
package kr.bb.payment.controller.clientcontroller;

import bloomingblooms.response.SuccessResponse;
import kr.bb.payment.dto.request.KakaopayApproveRequestDto;
import kr.bb.payment.dto.request.KakaopayReadyRequestDto;
import kr.bb.payment.dto.response.KakaopayReadyResponseDto;
import kr.bb.payment.service.KakaopayReadyService;
import kr.bb.payment.service.KakaopayService;
import kr.bb.payment.service.PaymentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequiredArgsConstructor
public class OrderClientController {

private final PaymentService paymentService;
private final KakaopayReadyService kakaopayReadyService;
private final KakaopayService kakaopayService;

@PostMapping("/ready")
public ResponseEntity<SuccessResponse<KakaopayReadyResponseDto>> payReady(
@RequestBody KakaopayReadyRequestDto readyRequestDto) {

KakaopayReadyResponseDto responseDto = kakaopayReadyService.kakaoPayReady(readyRequestDto);
KakaopayReadyResponseDto responseDto = kakaopayService.kakaoPayReady(readyRequestDto);

return ResponseEntity.ok()
.body(
Expand All @@ -33,4 +35,15 @@ public ResponseEntity<SuccessResponse<KakaopayReadyResponseDto>> payReady(
.data(responseDto)
.build());
}

@PostMapping("/approve")
public ResponseEntity<SuccessResponse<Void>> payApprove(@RequestBody KakaopayApproveRequestDto approveRequestDto){

kakaopayService.kakaoPayApprove(approveRequestDto);

return ResponseEntity.ok().body(SuccessResponse.<Void>builder()
.code(String.valueOf(HttpStatus.OK.value()))
.message(HttpStatus.OK.name())
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
public class KakaopayApproveRequestDto {
private Long orderId;
private Long userId;
private String orderType; // 배송/픽업 판별용
private String tid;
private String pgToken;
}
30 changes: 30 additions & 0 deletions src/main/java/kr/bb/payment/dto/response/Amount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package kr.bb.payment.dto.response;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@NoArgsConstructor
public class Amount {

private Integer total;
private Integer tax_free;
private Integer vat;
private Integer point;
private Integer discount;

public Amount(Integer total, Integer tax_free, Integer vat, Integer point, Integer discount) {
this.total = total;
this.tax_free = tax_free;
this.vat = vat;
this.point = point;
this.discount = discount;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package kr.bb.payment.dto.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class KakaoPayApproveResponseDto {
private String aid; // 요청 고유번호
private String tid; // 결제 고유번호
private String cid; // 가맹점 코드
private String sid; // 정기 결제용 id
@JsonProperty("partner_order_id")
private String partnerOrderId; // 가맹점 주문번호
@JsonProperty("partner_user_id")
private String partnerUserId; // 가맹점 회원
@JsonProperty("payment_method_type")
private String paymentMethodType; // 결제수단
@JsonProperty("item_name")
private String itemName;
private Integer quantity;
@JsonProperty("created_at")
private String createdAt;
@JsonProperty("approved_at")
private String approvedAt;
private Amount amount;
}
4 changes: 4 additions & 0 deletions src/main/java/kr/bb/payment/entity/Payment.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name = "payment")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
import kr.bb.payment.entity.Payment;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PaymentRepository extends JpaRepository<Payment, Long> {}
public interface PaymentRepository extends JpaRepository<Payment, Long> {
Payment findByOrderId(Long orderId);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package kr.bb.payment.service;

import kr.bb.payment.dto.request.KakaopayApproveRequestDto;
import kr.bb.payment.dto.request.KakaopayReadyRequestDto;
import kr.bb.payment.dto.response.KakaoPayApproveResponseDto;
import kr.bb.payment.dto.response.KakaopayReadyResponseDto;
import kr.bb.payment.entity.Payment;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -14,8 +17,9 @@

@RequiredArgsConstructor
@Component
public class KakaopayReadyService {
public class KakaopayService {
private final PaymentService paymentService;
private final RestTemplate restTemplate;

@Value("${kakao.admin}")
private String ADMIN_KEY;
Expand Down Expand Up @@ -45,16 +49,37 @@ public KakaopayReadyResponseDto kakaoPayReady(KakaopayReadyRequestDto requestDto
HttpEntity<MultiValueMap<String, String>> requestEntity =
new HttpEntity<>(parameters, this.getHeaders());

RestTemplate template = new RestTemplate();
String url = "https://kapi.kakao.com/v1/payment/ready";
KakaopayReadyResponseDto responseDto =
template.postForObject(url, requestEntity, KakaopayReadyResponseDto.class);
restTemplate.postForObject(url, requestEntity, KakaopayReadyResponseDto.class);

paymentService.savePayReadyInfo(requestDto, responseDto, cid);

return responseDto;
}

public void kakaoPayApprove(KakaopayApproveRequestDto requestDto) {
Payment paymentEntity = paymentService.getPaymentEntity(requestDto.getOrderId());

MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();

parameters.add("cid", paymentEntity.getPaymentCid());
parameters.add("tid", requestDto.getTid());
parameters.add("partner_order_id", String.valueOf(requestDto.getOrderId()));
parameters.add("partner_user_id", String.valueOf(requestDto.getUserId()));
parameters.add("pg_token", requestDto.getPgToken());

HttpEntity<MultiValueMap<String, String>> requestEntity =
new HttpEntity<>(parameters, this.getHeaders());

String url = "https://kapi.kakao.com/v1/payment/approve";

KakaoPayApproveResponseDto approveResponse =
restTemplate.postForObject(url, requestEntity, KakaoPayApproveResponseDto.class);

paymentService.updatePayInfo(paymentEntity, approveResponse);
}

@NotNull
private HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/kr/bb/payment/service/PaymentService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.bb.payment.service;

import kr.bb.payment.dto.request.KakaopayReadyRequestDto;
import kr.bb.payment.dto.response.KakaoPayApproveResponseDto;
import kr.bb.payment.dto.response.KakaopayReadyResponseDto;
import kr.bb.payment.entity.OrderType;
import kr.bb.payment.entity.Payment;
Expand Down Expand Up @@ -47,4 +48,29 @@ public KakaopayReadyResponseDto savePayReadyInfo(

return responseDto;
}

/**
* orderId로 Payment Entity 찾기
*
* @param orderId
* @return
*/
@Transactional
public Payment getPaymentEntity(Long orderId) {
return paymentRepository.findByOrderId(orderId);
}

/**
* 결제수단, 결제상태 업데이트(PENDING -> COMPLETED)
*
* @param paymentEntity
* @param approveResponse
*/
@Transactional
public void updatePayInfo(Payment paymentEntity, KakaoPayApproveResponseDto approveResponse) {
paymentEntity.setPaymentType(approveResponse.getPaymentMethodType());
paymentEntity.setPaymentStatus(PaymentStatus.COMPLETED);

paymentRepository.save(paymentEntity);
}
}
100 changes: 100 additions & 0 deletions src/test/java/kr/bb/payment/service/KakaopayApproveTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package kr.bb.payment.service;


import com.fasterxml.jackson.databind.ObjectMapper;
import kr.bb.payment.dto.request.KakaopayApproveRequestDto;
import kr.bb.payment.dto.response.Amount;
import kr.bb.payment.dto.response.KakaoPayApproveResponseDto;
import kr.bb.payment.entity.OrderType;
import kr.bb.payment.entity.Payment;
import kr.bb.payment.entity.PaymentStatus;
import kr.bb.payment.repository.PaymentRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.client.match.MockRestRequestMatchers;
import org.springframework.test.web.client.response.MockRestResponseCreators;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

@SpringBootTest
@Transactional
public class KakaopayApproveTest {
@Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
@Autowired
private KakaopayService kakaopayService;
@Autowired
private PaymentRepository paymentRepository;

@BeforeEach
void setUp() throws Exception{
mockServer = MockRestServiceServer.createServer(restTemplate);

// Payment Entity 저장
Payment payment =
Payment.builder()
.userId(1L)
.orderId(1L)
.orderType(OrderType.ORDER_DELIVERY)
.paymentCid("TC0ONETIME")
.paymentTid("FAKE_TID_FOR_TEST")
.paymentActualAmount(52900L)
.paymentStatus(PaymentStatus.PENDING)
.build();
paymentRepository.save(payment);

KakaoPayApproveResponseDto responseDto =
KakaoPayApproveResponseDto.builder()
.aid("A5678901234567890123")
.tid("T1234567890123456789")
.cid("TC0ONETIME")
.partnerOrderId("partner_order_id")
.partnerUserId("partner_user_id")
.paymentMethodType("MONEY")
.itemName("초코파이")
.quantity(1)
.amount(new Amount(2200, 0, 200, 0, 0))
.createdAt("2016-11-15T21:18:22")
.approvedAt("2016-11-15T21:20:47")
.build();

ObjectMapper objectMapper = new ObjectMapper();
String responseJson = objectMapper.writeValueAsString(responseDto);

mockServer
.expect(MockRestRequestMatchers.requestTo("https://kapi.kakao.com/v1/payment/approve"))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(MockRestResponseCreators.withSuccess(responseJson, MediaType.APPLICATION_JSON));
}

@AfterEach
void shutDown() {
mockServer.reset();
}

@DisplayName("결제 승인 테스트")
@DirtiesContext
@Test
void kakaoPayApproveTest() {
KakaopayApproveRequestDto requestDto =
KakaopayApproveRequestDto.builder()
.userId(1L)
.orderId(1L)
.tid("T1234567890123456789")
.pgToken("pg_token=xxxxxxxxxxxxxxxxxxxx")
.build();

kakaopayService.kakaoPayApprove(requestDto);

mockServer.verify();
}
}
Loading

0 comments on commit 7a1797a

Please sign in to comment.