Skip to content

Commit

Permalink
#7 결제 요청 API 개발
Browse files Browse the repository at this point in the history
  • Loading branch information
gugbab2 committed Jan 9, 2025
1 parent 76ab7cf commit 95d4390
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.gugbab2.productdraw.controller;

import com.gugbab2.productdraw.domain.entity.Payment;
import com.gugbab2.productdraw.domain.service.PaymentService;
import com.gugbab2.productdraw.dto.PaymentDto;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/payments")
@RequiredArgsConstructor
public class PaymentController {

private final PaymentService paymentService;

// 결제 요청
@PostMapping("/request")
public ResponseEntity<?> requestPayment(@RequestBody PaymentDto.RequestPaymentDto requestPaymentDto) {
try{
Payment payment = paymentService.requestPayment(requestPaymentDto.getDrawId(), requestPaymentDto.getPaymentMethod(), requestPaymentDto.getAmount());
return new ResponseEntity<>(payment, HttpStatus.CREATED);
} catch (RuntimeException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
}

// 결제 환불 요청
// @PostMapping("/refund")
// public ResponseEntity<?> refundPayment(@RequestBody PaymentDto.RefundPaymentDto refundPaymentDto) {
// try{
// Payment payment = paymentService.requestPayment(requestPaymentDto.getDrawId(), requestPaymentDto.getPaymentMethod(), requestPaymentDto.getAmount());
// return new ResponseEntity<>(payment, HttpStatus.CREATED);
// } catch (RuntimeException e) {
// return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
// }
// }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.gugbab2.productdraw.domain.entity;

import com.gugbab2.productdraw.domain.vo.PaymentMethod;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
@Setter
public class Payment {
private String id;
private String drawId;
private PaymentMethod paymentMethod;
private long amount;
private boolean isPaid;
private LocalDateTime createdAt;

public Payment(String drawId, PaymentMethod paymentMethod, long amount) {
this.id = UUID.randomUUID().toString();
this.drawId = drawId;
this.paymentMethod = paymentMethod;
this.amount = amount;
this.isPaid = false;
this.createdAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.gugbab2.productdraw.domain.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
@AllArgsConstructor
public class Product {
private String id;
private String name;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.gugbab2.productdraw.domain.repository;

import com.gugbab2.productdraw.domain.entity.Payment;

import java.util.List;

public interface PaymentRepository {
Payment save(Payment payment);
Payment findAllByDrawId(String DrawId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.gugbab2.productdraw.domain.repository.inmemory;

import com.gugbab2.productdraw.domain.entity.Payment;
import com.gugbab2.productdraw.domain.repository.PaymentRepository;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.Map;

@Repository
public class PaymentRepositoryImpl implements PaymentRepository {
private final Map<String, Payment> paymentsDatabase = new HashMap<>();

@Override
public Payment save(Payment payment) {
paymentsDatabase.put(payment.getId(), payment);
return payment;
}

@Override
public Payment findAllByDrawId(String DrawId) {
for(Payment payment : paymentsDatabase.values()) {
if(payment.getDrawId().equals(DrawId)) {
return payment;
}
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.gugbab2.productdraw.domain.service;

import com.gugbab2.productdraw.domain.entity.Draw;
import com.gugbab2.productdraw.domain.entity.Payment;
import com.gugbab2.productdraw.domain.entity.Product;
import com.gugbab2.productdraw.domain.repository.inmemory.DrawRepositoryImpl;
import com.gugbab2.productdraw.domain.repository.inmemory.PaymentRepositoryImpl;
import com.gugbab2.productdraw.domain.repository.inmemory.ProductRepositoryImpl;
import com.gugbab2.productdraw.domain.vo.PaymentMethod;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class PaymentService {

private final DrawRepositoryImpl drawRepository;
private final ProductRepositoryImpl productRepository;
private final PaymentRepositoryImpl paymentRepository;

public Payment requestPayment(String drawId, PaymentMethod paymentMethod, long amount) {

// 사용자 인증 상태 확인(사용자 인증 개념 추가 후 적용 가능)

// 응모 당첨 여부 확인
Draw draw = drawRepository.findById(drawId);
if (!draw.isWinner()) {
throw new RuntimeException("entrant is not winner");
}

// 결제 정보 검증(제품 가격 체크)
Product product = productRepository.findById(draw.getProductId());
if(product.getPrice() != amount) {
throw new RuntimeException("product price is not equal to amount");
}

// 중복 결제 여부 검증
Payment findPayment = paymentRepository.findAllByDrawId(drawId);
if (findPayment != null) {
throw new RuntimeException("payment already exists");
}

// 결제 처리(카드사 API 호출)

// 결제 완료 시 비동기로 결제 알림

// 결제 완료 후 결제 정보 DB 저장
Payment payment = new Payment(drawId, paymentMethod, amount);
return paymentRepository.save(payment);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.gugbab2.productdraw.domain.vo;

public enum PaymentMethod {
CARD;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.gugbab2.productdraw.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

public class DrawDto {

@Getter
@Setter
@AllArgsConstructor
public static class CreateDrawDto{
private String entrantId;
private String productId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.gugbab2.productdraw.dto;

import com.gugbab2.productdraw.domain.vo.PaymentMethod;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

public class PaymentDto {

@Getter
@Setter
@AllArgsConstructor
public static class RequestPaymentDto{
private String drawId;
private PaymentMethod paymentMethod;
private long amount;
}

@Getter
@Setter
@AllArgsConstructor
public static class RefundPaymentDto{
private String paymentId;
private long amount;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.gugbab2.productdraw.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gugbab2.productdraw.domain.entity.Draw;
import com.gugbab2.productdraw.domain.entity.Product;
import com.gugbab2.productdraw.domain.repository.inmemory.DrawRepositoryImpl;
import com.gugbab2.productdraw.domain.repository.inmemory.ProductRepositoryImpl;
import com.gugbab2.productdraw.dto.DrawDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.time.LocalDateTime;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
class DrawControllerIntegrationTest {

// @Autowired
// private WebApplicationContext context;
//
// @Autowired
// private DrawRepositoryImpl drawRepository;
//
// @Autowired
// private ProductRepositoryImpl productRepository;
//
// private MockMvc mockMvc;
//
// private ObjectMapper objectMapper;
//
// @BeforeEach
// void setUp() {
// mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
// objectMapper = new ObjectMapper();
//
// // 테스트용 상품 데이터 추가
// Product product = new Product("product123", "Test Product", "Test Product", 1000, 2, LocalDateTime.now().minusDays(1),
// LocalDateTime.now().plusDays(1));
// productRepository.save(product);
// }
//
// @Test
// void testFlowOfAPIRequests() throws Exception {
// // Step 1: 응모 제출 API 호출
// DrawDto.CreateDrawDto drawDto = new DrawDto.CreateDrawDto("entrant123", "product123");
// String drawRequestJson = objectMapper.writeValueAsString(drawDto);
//
// mockMvc.perform(post("/draws/submit")
// .contentType(MediaType.APPLICATION_JSON)
// .content(drawRequestJson))
// .andExpect(status().isCreated())
// .andExpect(jsonPath("$.entrantId").value("entrant123"))
// .andExpect(jsonPath("$.productId").value("product123"));
//
// // Step 2: 당첨자 발표 API 호출
// mockMvc.perform(post("/draws/product123/result"))
// .andExpect(status().isOk())
// .andExpect(jsonPath("$[0].entrantId").value("entrant123"))
// .andExpect(jsonPath("$[0].productId").value("product123"));
//
// // Step 3: 당첨 데이터 검증 (Repository 사용)
// Draw winner = drawRepository.findDrawsByProductId("product123").get(0);
// assertNotNull(winner);
// assertEquals("entrant123", winner.getEntrantId());
// assertEquals(true, winner.isWinner());
// }
}

0 comments on commit 95d4390

Please sign in to comment.