From 9f707326b3f55c44602251876c9b96922ac93dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:35:30 +0900 Subject: [PATCH 01/29] =?UTF-8?q?refactor:=20order=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20pk=20=EB=B3=80=EA=B2=BD=20(#80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Order PK 변경 - 기존 PK는 pgOrderId으로 변경 - 새로운 PK 추가 * refactor: Order PK 변경으로 인한 테스트 및 구현 코드 변경 * refactor: 토스 페이먼츠 주문 번호 생성 클래스 리네이밍 --- .../koin/domain/order/model/Order.java | 21 +++++++++++---- .../domain/order/model/OrderDelivery.java | 2 +- .../koin/domain/order/model/OrderTakeout.java | 2 +- .../order/repository/OrderMenuRepository.java | 2 +- .../payment/model/redis/TemporaryPayment.java | 26 +++++++++---------- .../TemporaryPaymentRedisRepository.java | 10 +++---- .../service/TossPaymentRollBackService.java | 4 +-- .../payment/service/TossService.java | 16 ++++++------ .../payment/util/OrderIdGenerator.java | 5 ---- .../payment/util/PgOrderIdGenerator.java | 5 ++++ .../util/TossPaymentOrderIdGenerator.java | 4 +-- .../acceptance/domain/PaymentApiTest.java | 24 +++++++++-------- .../acceptance/support/DBInitializer.java | 2 +- 13 files changed, 68 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/util/OrderIdGenerator.java create mode 100644 src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java diff --git a/src/main/java/in/koreatech/koin/domain/order/model/Order.java b/src/main/java/in/koreatech/koin/domain/order/model/Order.java index 9d6511e..b101e95 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/Order.java +++ b/src/main/java/in/koreatech/koin/domain/order/model/Order.java @@ -3,6 +3,7 @@ import static jakarta.persistence.CascadeType.ALL; import static jakarta.persistence.EnumType.STRING; import static jakarta.persistence.FetchType.LAZY; +import static jakarta.persistence.GenerationType.IDENTITY; import static java.lang.Boolean.FALSE; import static lombok.AccessLevel.PROTECTED; @@ -14,6 +15,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; @@ -34,10 +36,13 @@ public class Order extends BaseEntity { @Id + @GeneratedValue(strategy = IDENTITY) + private Integer id; + @NotBlank @Size(min = 6, max = 64) - @Column(name = "id", length = 64, nullable = false, updatable = false) - private String id; + @Column(name = "pg_order_id", length = 64, nullable = false, updatable = false) + private String pgOrderId; @NotNull @Enumerated(STRING) @@ -76,17 +81,21 @@ public class Order extends BaseEntity { private OrderTakeout orderTakeout; @Builder - public Order( - String id, + private Order( + Integer id, + String pgOrderId, OrderType orderType, String phoneNumber, Integer totalProductPrice, Integer totalPrice, Boolean isDeleted, OrderableShop orderableShop, - User user + User user, + OrderDelivery orderDelivery, + OrderTakeout orderTakeout ) { this.id = id; + this.pgOrderId = pgOrderId; this.orderType = orderType; this.phoneNumber = phoneNumber; this.totalProductPrice = totalProductPrice; @@ -94,6 +103,8 @@ public Order( this.isDeleted = isDeleted; this.orderableShop = orderableShop; this.user = user; + this.orderDelivery = orderDelivery; + this.orderTakeout = orderTakeout; } public void setOrderDelivery(OrderDelivery orderDelivery) { diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java b/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java index 27bcd78..2bbd29b 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java +++ b/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java @@ -24,7 +24,7 @@ public class OrderDelivery { @Id @Column(name = "order_id", nullable = false, updatable = false) - private String id; + private Integer id; @MapsId @OneToOne diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java b/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java index ed5cc7c..1f50b51 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java +++ b/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java @@ -23,7 +23,7 @@ public class OrderTakeout { @Id @Column(name = "order_id", nullable = false, updatable = false) - private String id; + private Integer id; @MapsId @OneToOne diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java b/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java index 5020d5c..bfb99df 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java +++ b/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java @@ -10,5 +10,5 @@ public interface OrderMenuRepository extends Repository { void saveAll(Iterable orderMenus); - List findAllByOrderId(String orderId); + List findAllByOrderId(Integer orderId); } diff --git a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java index 8ad2750..465db13 100644 --- a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java +++ b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java @@ -27,7 +27,7 @@ public class TemporaryPayment { private static final Long CACHE_EXPIRE_SECOND = 60 * 10L; @Id - private String orderId; + private String pgOrderId; private Integer userId; @@ -59,7 +59,7 @@ public class TemporaryPayment { private LocalDateTime createdAt; private TemporaryPayment( - String orderId, + String pgOrderId, Integer userId, Integer orderableShopId, String phoneNumber, @@ -73,7 +73,7 @@ private TemporaryPayment( Integer totalPrice, List temporaryMenuItems ) { - this.orderId = orderId; + this.pgOrderId = pgOrderId; this.userId = userId; this.orderableShopId = orderableShopId; this.phoneNumber = phoneNumber; @@ -91,7 +91,7 @@ private TemporaryPayment( } public static TemporaryPayment toDeliveryEntity( - String orderId, + String pgOrderId, Integer userId, Integer orderableShopId, String phoneNumber, @@ -105,7 +105,7 @@ public static TemporaryPayment toDeliveryEntity( List temporaryMenuItems ) { return new TemporaryPayment( - orderId, + pgOrderId, userId, orderableShopId, phoneNumber, @@ -122,7 +122,7 @@ public static TemporaryPayment toDeliveryEntity( } public static TemporaryPayment toTakeOutEntity( - String orderId, + String pgOrderId, Integer userId, Integer orderableShopId, String phoneNumber, @@ -133,7 +133,7 @@ public static TemporaryPayment toTakeOutEntity( List temporaryMenuItems ) { return new TemporaryPayment( - orderId, + pgOrderId, userId, orderableShopId, phoneNumber, @@ -151,7 +151,7 @@ public static TemporaryPayment toTakeOutEntity( public Order toOrder(User user, OrderableShop orderableShop) { Order order = Order.builder() - .id(orderId) + .pgOrderId(pgOrderId) .orderType(orderType) .phoneNumber(phoneNumber) .totalProductPrice(totalProductPrice) @@ -181,15 +181,15 @@ public Order toOrder(User user, OrderableShop orderableShop) { return order; } - public void validateMatches(String orderId, Integer userId, Integer amount) { - validateOrderIdMatches(orderId); + public void validateMatches(String pgOrderId, Integer userId, Integer amount) { + validatePgOrderIdMatches(pgOrderId); validateUserIdMatches(userId); validateAmountMatches(amount); } - private void validateOrderIdMatches(String orderId) { - if (!orderId.equals(this.orderId)) { - throw InvalidTemporaryPaymentException.withDetail("orderId : " + orderId); + private void validatePgOrderIdMatches(String pgOrderId) { + if (!pgOrderId.equals(this.pgOrderId)) { + throw InvalidTemporaryPaymentException.withDetail("orderId : " + pgOrderId); } } diff --git a/src/main/java/in/koreatech/payment/repository/redis/TemporaryPaymentRedisRepository.java b/src/main/java/in/koreatech/payment/repository/redis/TemporaryPaymentRedisRepository.java index 4ad89cd..7dc07fe 100644 --- a/src/main/java/in/koreatech/payment/repository/redis/TemporaryPaymentRedisRepository.java +++ b/src/main/java/in/koreatech/payment/repository/redis/TemporaryPaymentRedisRepository.java @@ -11,12 +11,12 @@ public interface TemporaryPaymentRedisRepository extends Repository findById(String orderId); + Optional findById(String pgOrderId); - default TemporaryPayment getById(String orderId) { - return findById(orderId) - .orElseThrow(() -> TemporaryPaymentNotFoundException.withDetail("orderId : " + orderId)); + default TemporaryPayment getById(String pgOrderId) { + return findById(pgOrderId) + .orElseThrow(() -> TemporaryPaymentNotFoundException.withDetail("pgOrderId : " + pgOrderId)); } - void deleteById(String orderId); + void deleteById(String pgOrderId); } diff --git a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java b/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java index b2d33a9..a9261e4 100644 --- a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java +++ b/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java @@ -83,11 +83,11 @@ public void paymentRollback(TossPaymentRollBackEvent event) { List paymentCancels = response.getPaymentCancels(payment); paymentCancelRepository.saveAll(paymentCancels); - temporaryPaymentRedisRepository.deleteById(order.getId()); + temporaryPaymentRedisRepository.deleteById(order.getPgOrderId()); cartRepository.deleteByUserId(user.getId()); } catch (Exception e) { log.error("결제 취소 과정에서 오류 발생 - paymentId: {}, userId: {}, orderId: {}", event.paymentKey(), - temporaryPayment.getUserId(), temporaryPayment.getOrderId()); + temporaryPayment.getUserId(), temporaryPayment.getPgOrderId()); } } } diff --git a/src/main/java/in/koreatech/payment/service/TossService.java b/src/main/java/in/koreatech/payment/service/TossService.java index 2cec10d..17ba8b4 100644 --- a/src/main/java/in/koreatech/payment/service/TossService.java +++ b/src/main/java/in/koreatech/payment/service/TossService.java @@ -40,7 +40,7 @@ import in.koreatech.payment.model.domain.TemporaryMenuItems; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import in.koreatech.payment.util.OrderIdGenerator; +import in.koreatech.payment.util.PgOrderIdGenerator; import in.koreatech.payment.util.TemporaryMenuItemConverter; import lombok.RequiredArgsConstructor; @@ -49,7 +49,7 @@ @Transactional(readOnly = true) public class TossService implements PaymentService { - private final OrderIdGenerator orderIdGenerator; + private final PgOrderIdGenerator pgOrderIdGenerator; private final JwtProvider jwtProvider; private final UserRepository userRepository; private final TossPaymentClient tossPaymentClient; @@ -85,10 +85,10 @@ public String createTemporaryDeliveryPayment(String accessToken, TemporaryDelive + totalProductPrice + "finalAmount : " + finalAmount); } - String orderId = orderIdGenerator.generateOrderId(); + String pgOrderId = pgOrderIdGenerator.generatePgOrderId(); TemporaryPayment deliveryEntity = TemporaryPayment.toDeliveryEntity( - orderId, + pgOrderId, user.getId(), orderableShop.getId(), request.phoneNumber(), @@ -103,7 +103,7 @@ public String createTemporaryDeliveryPayment(String accessToken, TemporaryDelive ); temporaryPaymentRedisRepository.save(deliveryEntity); - return orderId; + return pgOrderId; } @Transactional @@ -125,10 +125,10 @@ public String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeout "totalProductPrice : " + totalProductPrice + "finalAmount : " + finalAmount); } - String orderId = orderIdGenerator.generateOrderId(); + String pgOrderId = pgOrderIdGenerator.generatePgOrderId(); TemporaryPayment deliveryEntity = TemporaryPayment.toTakeOutEntity( - orderId, + pgOrderId, user.getId(), orderableShop.getId(), request.phoneNumber(), @@ -140,7 +140,7 @@ public String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeout ); temporaryPaymentRedisRepository.save(deliveryEntity); - return orderId; + return pgOrderId; } @Transactional diff --git a/src/main/java/in/koreatech/payment/util/OrderIdGenerator.java b/src/main/java/in/koreatech/payment/util/OrderIdGenerator.java deleted file mode 100644 index b733dc9..0000000 --- a/src/main/java/in/koreatech/payment/util/OrderIdGenerator.java +++ /dev/null @@ -1,5 +0,0 @@ -package in.koreatech.payment.util; - -public interface OrderIdGenerator { - String generateOrderId(); -} diff --git a/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java b/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java new file mode 100644 index 0000000..9b02c7b --- /dev/null +++ b/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java @@ -0,0 +1,5 @@ +package in.koreatech.payment.util; + +public interface PgOrderIdGenerator { + String generatePgOrderId(); +} diff --git a/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java b/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java index 3c1e324..39fc2c2 100644 --- a/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java +++ b/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java @@ -5,14 +5,14 @@ import org.springframework.stereotype.Component; @Component -public class TossPaymentOrderIdGenerator implements OrderIdGenerator { +public class TossPaymentOrderIdGenerator implements PgOrderIdGenerator { private static final String ORDER_ID_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; private static final int ORDER_ID_MIN_LENGTH = 6; private static final int ORDER_ID_MAX_LENGTH = 64; private final SecureRandom random = new SecureRandom(); - public String generateOrderId() { + public String generatePgOrderId() { int length = ORDER_ID_MIN_LENGTH + random.nextInt(ORDER_ID_MAX_LENGTH - ORDER_ID_MIN_LENGTH + 1); StringBuilder sb = new StringBuilder(length); for (int index = 0; index < length; index++) { diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index 43a5542..8541457 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -54,7 +54,7 @@ import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import in.koreatech.payment.service.PaymentRollBackService; -import in.koreatech.payment.util.OrderIdGenerator; +import in.koreatech.payment.util.PgOrderIdGenerator; public class PaymentApiTest extends AcceptanceTest { @@ -101,7 +101,7 @@ public class PaymentApiTest extends AcceptanceTest { private PaymentRollBackService paymentRollBackService; @MockBean - private OrderIdGenerator orderIdGenerator; + private PgOrderIdGenerator pgOrderIdGenerator; private User user; private String token; @@ -132,7 +132,7 @@ class TemporaryPaymentSuccess { @Test void 임시_배달_결제_정보_저장에_성공한다() throws Exception { - given(orderIdGenerator.generateOrderId()).willReturn("FAKE_ORDER_123"); + given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); mockMvc.perform( post("/payments/delivery/temporary") @@ -162,7 +162,7 @@ class TemporaryPaymentSuccess { TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById("FAKE_ORDER_123"); assertSoftly( softly -> { - softly.assertThat(temporaryPayment.getOrderId()).isEqualTo("FAKE_ORDER_123"); + softly.assertThat(temporaryPayment.getPgOrderId()).isEqualTo("FAKE_ORDER_123"); softly.assertThat(temporaryPayment.getUserId()).isEqualTo(user.getId()); softly.assertThat(temporaryPayment.getOrderableShopId()).isEqualTo(orderableShop.getId()); softly.assertThat(temporaryPayment.getPhoneNumber()).isEqualTo("01012345678"); @@ -183,7 +183,7 @@ class TemporaryPaymentSuccess { @Test void 임시_포장_결제_정보_저장에_성공한다() throws Exception { - given(orderIdGenerator.generateOrderId()).willReturn("FAKE_ORDER_123"); + given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); mockMvc.perform( post("/payments/takeout/temporary") @@ -209,7 +209,7 @@ class TemporaryPaymentSuccess { TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById("FAKE_ORDER_123"); assertSoftly( softly -> { - softly.assertThat(temporaryPayment.getOrderId()).isEqualTo("FAKE_ORDER_123"); + softly.assertThat(temporaryPayment.getPgOrderId()).isEqualTo("FAKE_ORDER_123"); softly.assertThat(temporaryPayment.getUserId()).isEqualTo(user.getId()); softly.assertThat(temporaryPayment.getOrderableShopId()).isEqualTo(orderableShop.getId()); softly.assertThat(temporaryPayment.getPhoneNumber()).isEqualTo("01012345678"); @@ -245,7 +245,7 @@ class PaymentSuccess { ); when(tossPaymentClient.requestConfirm(eq("pay_123"), eq("FAKE_ORDER_123"), eq(24000))) .thenReturn(confirmDto); - given(orderIdGenerator.generateOrderId()).willReturn("FAKE_ORDER_123"); + given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); mockMvc.perform( post("/payments/delivery/temporary") @@ -324,11 +324,12 @@ class PaymentSuccess { softly.assertThat(payment.getPaymentStatus()).isEqualTo(PaymentStatus.DONE); softly.assertThat(payment.getPaymentMethod()).isEqualTo(PaymentMethod.CARD); - softly.assertThat(order.getId()).isEqualTo("FAKE_ORDER_123"); + softly.assertThat(order.getId()).isEqualTo(1); softly.assertThat(order.getOrderType()).isEqualTo(OrderType.DELIVERY); softly.assertThat(order.getPhoneNumber()).isEqualTo("01012345678"); softly.assertThat(order.getTotalProductPrice()).isEqualTo(24000); softly.assertThat(order.getTotalPrice()).isEqualTo(24000); + softly.assertThat(order.getPgOrderId()).isEqualTo("FAKE_ORDER_123"); softly.assertThat(orderTakeout).isNull(); @@ -360,7 +361,7 @@ class PaymentSuccess { ); when(tossPaymentClient.requestConfirm(eq("pay_123"), eq("FAKE_ORDER_123"), eq(24000))) .thenReturn(confirmDto); - given(orderIdGenerator.generateOrderId()).willReturn("FAKE_ORDER_123"); + given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); mockMvc.perform( post("/payments/takeout/temporary") @@ -434,11 +435,12 @@ class PaymentSuccess { softly.assertThat(payment.getPaymentStatus()).isEqualTo(PaymentStatus.DONE); softly.assertThat(payment.getPaymentMethod()).isEqualTo(PaymentMethod.CARD); - softly.assertThat(order.getId()).isEqualTo("FAKE_ORDER_123"); + softly.assertThat(order.getId()).isEqualTo(1); softly.assertThat(order.getOrderType()).isEqualTo(OrderType.TAKE_OUT); softly.assertThat(order.getPhoneNumber()).isEqualTo("01012345678"); softly.assertThat(order.getTotalProductPrice()).isEqualTo(24000); softly.assertThat(order.getTotalPrice()).isEqualTo(24000); + softly.assertThat(order.getPgOrderId()).isEqualTo("FAKE_ORDER_123"); softly.assertThat(orderTakeout.getToOwner()).isEqualTo("리뷰 이벤트 감사합니다."); softly.assertThat(orderTakeout.getProvideCutlery()).isEqualTo(true); @@ -468,7 +470,7 @@ class PaymentSuccess { ); when(tossPaymentClient.requestConfirm(eq("pay_123"), eq("FAKE_ORDER_123"), eq(24000))) .thenReturn(confirmDto); - given(orderIdGenerator.generateOrderId()).willReturn("FAKE_ORDER_123"); + given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); PaymentCancelResponse cancelDto = new PaymentCancelResponse( "pay_123", diff --git a/src/test/java/in/koreatech/payment/acceptance/support/DBInitializer.java b/src/test/java/in/koreatech/payment/acceptance/support/DBInitializer.java index b826c1c..5ac311f 100644 --- a/src/test/java/in/koreatech/payment/acceptance/support/DBInitializer.java +++ b/src/test/java/in/koreatech/payment/acceptance/support/DBInitializer.java @@ -46,7 +46,7 @@ public void initIncrement() { String sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND AUTO_INCREMENT >= 1"; List dirtyTables = entityManager.createNativeQuery(sql).getResultList(); for (String dirtyTable: dirtyTables) { - entityManager.createNativeQuery(String.format("ALTER TABLE %s AUTO_INCREMENT = 1", dirtyTable)).executeUpdate(); + entityManager.createNativeQuery(String.format("ALTER TABLE `%s` AUTO_INCREMENT = 1", dirtyTable)).executeUpdate(); } } From 8cd7ff4572b96bfcb2cf7c2b4f6b50df24021635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:42:28 +0900 Subject: [PATCH 02/29] =?UTF-8?q?refactor:=20=EC=99=B8=EB=B6=80=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EA=B3=84=EC=B8=B5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Order PK 변경 - 기존 PK는 pgOrderId으로 변경 - 새로운 PK 추가 * refactor: Order PK 변경으로 인한 테스트 및 구현 코드 변경 * refactor: 토스 페이먼츠 주문 번호 생성 클래스 리네이밍 * feat: PG GateWay 인터페이스 추가 * chore: PgOrderIdGenerator 패키지 이동 * chore: TossOrderIdGenerator 패키지 이동 * chore: TossPaymentClient 패키지 이동 * chore: TossPayment Dto 패키지 이동 * feat: 결제 승인 구현 * feat: 결제 승인 구현 * chore: 롤백 로직 주석 처리 * feat: 결제 멱등키 서비스 추가 * refactor: 결제 취소 로직 리펙토링 * fix: 페이먼츠 인터페이스 참조로 변경 * test: 응답 dto 변경에 의한 테스트 수정 * chore: 클래스 및 변수 리네이밍 * chore: 토스 클라이언트 예외 클래스 패키지 변경 * fix: 결제 승인 및 취소 예외 처리 서비스로 이동 --- .../dto/request/PaymentCancelRequest.java | 7 -- .../dto/request/PaymentConfirmRequest.java | 9 -- .../dto/response/PaymentCancelResponse.java | 44 --------- .../exception/GlobalExceptionHandler.java | 2 +- .../event/TossPaymentRollBackEvent.java | 2 +- .../gateway/pg/PaymentGatewayService.java | 9 ++ .../gateway/pg/PgOrderIdGenerator.java | 5 ++ .../pg/dto/PgPaymentCancelResponse.java | 19 ++++ .../pg/dto/PgPaymentConfirmResponse.java | 13 +++ .../toss/TossOrderIdGenerator.java} | 6 +- .../toss}/TossPaymentClient.java | 25 +++--- .../toss/TossPaymentGatewayService.java | 52 +++++++++++ .../dto/request/TossPaymentCancelRequest.java | 7 ++ .../request/TossPaymentConfirmRequest.java | 9 ++ .../response/TossPaymentCancelResponse.java | 20 +++++ .../response/TossPaymentConfirmResponse.java | 13 +++ .../toss}/exception/TossPaymentErrorCode.java | 2 +- .../exception/TossPaymentErrorResponse.java | 2 +- .../toss}/exception/TossPaymentException.java | 2 +- .../payment/mapper/PaymentCancelMapper.java | 36 ++++++++ .../PaymentMapper.java} | 30 +++---- .../service/PaymentIdempotencyKeyService.java | 33 +++++++ .../service/TossPaymentRollBackService.java | 89 ++++++++----------- .../payment/service/TossService.java | 64 ++++++------- .../acceptance/domain/PaymentApiTest.java | 15 ++-- .../unit/client/TossPaymentClientTest.java | 15 ++-- 26 files changed, 332 insertions(+), 198 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/client/dto/request/PaymentCancelRequest.java delete mode 100644 src/main/java/in/koreatech/payment/client/dto/request/PaymentConfirmRequest.java delete mode 100644 src/main/java/in/koreatech/payment/client/dto/response/PaymentCancelResponse.java create mode 100644 src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java create mode 100644 src/main/java/in/koreatech/payment/gateway/pg/PgOrderIdGenerator.java create mode 100644 src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java create mode 100644 src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java rename src/main/java/in/koreatech/payment/{util/TossPaymentOrderIdGenerator.java => gateway/toss/TossOrderIdGenerator.java} (82%) rename src/main/java/in/koreatech/payment/{client => gateway/toss}/TossPaymentClient.java (78%) create mode 100644 src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java create mode 100644 src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentCancelRequest.java create mode 100644 src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentConfirmRequest.java create mode 100644 src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentCancelResponse.java create mode 100644 src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentConfirmResponse.java rename src/main/java/in/koreatech/payment/{client => gateway/toss}/exception/TossPaymentErrorCode.java (99%) rename src/main/java/in/koreatech/payment/{client => gateway/toss}/exception/TossPaymentErrorResponse.java (62%) rename src/main/java/in/koreatech/payment/{client => gateway/toss}/exception/TossPaymentException.java (92%) create mode 100644 src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java rename src/main/java/in/koreatech/payment/{client/dto/response/TossPaymentConfirmResponse.java => mapper/PaymentMapper.java} (56%) create mode 100644 src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java diff --git a/src/main/java/in/koreatech/payment/client/dto/request/PaymentCancelRequest.java b/src/main/java/in/koreatech/payment/client/dto/request/PaymentCancelRequest.java deleted file mode 100644 index 8e5c9e2..0000000 --- a/src/main/java/in/koreatech/payment/client/dto/request/PaymentCancelRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package in.koreatech.payment.client.dto.request; - -public record PaymentCancelRequest( - String cancelReason -) { - -} diff --git a/src/main/java/in/koreatech/payment/client/dto/request/PaymentConfirmRequest.java b/src/main/java/in/koreatech/payment/client/dto/request/PaymentConfirmRequest.java deleted file mode 100644 index 1002216..0000000 --- a/src/main/java/in/koreatech/payment/client/dto/request/PaymentConfirmRequest.java +++ /dev/null @@ -1,9 +0,0 @@ -package in.koreatech.payment.client.dto.request; - -public record PaymentConfirmRequest( - String paymentKey, - String orderId, - Integer amount -) { - -} diff --git a/src/main/java/in/koreatech/payment/client/dto/response/PaymentCancelResponse.java b/src/main/java/in/koreatech/payment/client/dto/response/PaymentCancelResponse.java deleted file mode 100644 index d12a93a..0000000 --- a/src/main/java/in/koreatech/payment/client/dto/response/PaymentCancelResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -package in.koreatech.payment.client.dto.response; - -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; - -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; - -public record PaymentCancelResponse( - String paymentKey, - String orderId, - String status, - List cancels -) { - public record CancelInfo( - Integer cancelAmount, - String cancelReason, - String canceledAt, - String transactionKey - ) { - - } - - public List getPaymentCancels(Payment payment) { - List paymentCancels = new ArrayList<>(); - - for (CancelInfo cancelInfo : cancels) { - OffsetDateTime cancelOffsetDateTime = OffsetDateTime.parse(cancelInfo.canceledAt); - LocalDateTime canceled = cancelOffsetDateTime.toLocalDateTime(); - - paymentCancels.add(PaymentCancel.builder() - .transactionKey(cancelInfo.transactionKey) - .cancelReason(cancelInfo.cancelReason) - .cancelAmount(cancelInfo.cancelAmount) - .canceledAt(canceled) - .payment(payment) - .build()); - } - - return paymentCancels; - } -} diff --git a/src/main/java/in/koreatech/payment/common/exception/GlobalExceptionHandler.java b/src/main/java/in/koreatech/payment/common/exception/GlobalExceptionHandler.java index 952833c..2e9edf0 100644 --- a/src/main/java/in/koreatech/payment/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/in/koreatech/payment/common/exception/GlobalExceptionHandler.java @@ -25,7 +25,7 @@ import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.WebUtils; -import in.koreatech.payment.client.exception.TossPaymentException; +import in.koreatech.payment.gateway.toss.exception.TossPaymentException; import in.koreatech.payment.common.exception.custom.AuthenticationException; import in.koreatech.payment.common.exception.custom.AuthorizationException; import in.koreatech.payment.common.exception.custom.DataNotFoundException; diff --git a/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java b/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java index 835c0ca..822d648 100644 --- a/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java +++ b/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java @@ -1,6 +1,6 @@ package in.koreatech.payment.event; -import in.koreatech.payment.client.dto.response.TossPaymentConfirmResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; import in.koreatech.payment.model.redis.TemporaryPayment; public record TossPaymentRollBackEvent( diff --git a/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java new file mode 100644 index 0000000..f4ddccd --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java @@ -0,0 +1,9 @@ +package in.koreatech.payment.gateway.pg; + +import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; + +public interface PaymentGatewayService { + PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount); + PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey); +} diff --git a/src/main/java/in/koreatech/payment/gateway/pg/PgOrderIdGenerator.java b/src/main/java/in/koreatech/payment/gateway/pg/PgOrderIdGenerator.java new file mode 100644 index 0000000..020c5df --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/pg/PgOrderIdGenerator.java @@ -0,0 +1,5 @@ +package in.koreatech.payment.gateway.pg; + +public interface PgOrderIdGenerator { + String generatePgOrderId(); +} diff --git a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java b/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java new file mode 100644 index 0000000..b7c1b56 --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java @@ -0,0 +1,19 @@ +package in.koreatech.payment.gateway.pg.dto; + +import java.util.List; + +public record PgPaymentCancelResponse( + String paymentKey, + String orderId, + String status, + List cancels +) { + public record CancelInfo( + Integer cancelAmount, + String cancelReason, + String canceledAt, + String transactionKey + ) { + + } +} diff --git a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java new file mode 100644 index 0000000..23f5b6f --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java @@ -0,0 +1,13 @@ +package in.koreatech.payment.gateway.pg.dto; + +public record PgPaymentConfirmResponse( + String paymentKey, + Integer totalAmount, + String orderId, + String status, + String method, + String requestedAt, + String approvedAt +) { + +} diff --git a/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java b/src/main/java/in/koreatech/payment/gateway/toss/TossOrderIdGenerator.java similarity index 82% rename from src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java rename to src/main/java/in/koreatech/payment/gateway/toss/TossOrderIdGenerator.java index 39fc2c2..0f6237f 100644 --- a/src/main/java/in/koreatech/payment/util/TossPaymentOrderIdGenerator.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/TossOrderIdGenerator.java @@ -1,11 +1,13 @@ -package in.koreatech.payment.util; +package in.koreatech.payment.gateway.toss; import java.security.SecureRandom; import org.springframework.stereotype.Component; +import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; + @Component -public class TossPaymentOrderIdGenerator implements PgOrderIdGenerator { +public class TossOrderIdGenerator implements PgOrderIdGenerator { private static final String ORDER_ID_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; private static final int ORDER_ID_MIN_LENGTH = 6; diff --git a/src/main/java/in/koreatech/payment/client/TossPaymentClient.java b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentClient.java similarity index 78% rename from src/main/java/in/koreatech/payment/client/TossPaymentClient.java rename to src/main/java/in/koreatech/payment/gateway/toss/TossPaymentClient.java index 17268f3..fcd7e58 100644 --- a/src/main/java/in/koreatech/payment/client/TossPaymentClient.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentClient.java @@ -1,4 +1,4 @@ -package in.koreatech.payment.client; +package in.koreatech.payment.gateway.toss; import static java.nio.charset.StandardCharsets.UTF_8; import static org.springframework.http.HttpHeaders.AUTHORIZATION; @@ -14,14 +14,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import in.koreatech.payment.client.dto.request.PaymentCancelRequest; -import in.koreatech.payment.client.dto.request.PaymentConfirmRequest; -import in.koreatech.payment.client.dto.response.PaymentCancelResponse; -import in.koreatech.payment.client.dto.response.TossPaymentConfirmResponse; -import in.koreatech.payment.client.exception.TossPaymentErrorCode; -import in.koreatech.payment.client.exception.TossPaymentErrorResponse; -import in.koreatech.payment.client.exception.TossPaymentException; +import in.koreatech.payment.gateway.toss.exception.TossPaymentErrorCode; +import in.koreatech.payment.gateway.toss.exception.TossPaymentErrorResponse; +import in.koreatech.payment.gateway.toss.exception.TossPaymentException; import in.koreatech.payment.common.exception.custom.KoinIllegalStateException; +import in.koreatech.payment.gateway.toss.dto.request.TossPaymentCancelRequest; +import in.koreatech.payment.gateway.toss.dto.request.TossPaymentConfirmRequest; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; @Component public class TossPaymentClient { @@ -48,7 +48,7 @@ public TossPaymentClient( } public TossPaymentConfirmResponse requestConfirm(String paymentKey, String orderId, Integer amount) { - PaymentConfirmRequest request = new PaymentConfirmRequest(paymentKey, orderId, amount); + TossPaymentConfirmRequest request = new TossPaymentConfirmRequest(paymentKey, orderId, amount); try { return webClient.post() @@ -57,7 +57,6 @@ public TossPaymentConfirmResponse requestConfirm(String paymentKey, String order .retrieve() .bodyToMono(TossPaymentConfirmResponse.class) .block(); - } catch (WebClientResponseException e) { throw handleErrorResponse(e); } catch (Exception e) { @@ -65,8 +64,8 @@ public TossPaymentConfirmResponse requestConfirm(String paymentKey, String order } } - public PaymentCancelResponse requestCancel(String paymentKey, String cancelReason, String IdempotencyKey) { - PaymentCancelRequest request = new PaymentCancelRequest(cancelReason); + public TossPaymentCancelResponse requestCancel(String paymentKey, String cancelReason, String IdempotencyKey) { + TossPaymentCancelRequest request = new TossPaymentCancelRequest(cancelReason); try { return webClient.post() @@ -74,7 +73,7 @@ public PaymentCancelResponse requestCancel(String paymentKey, String cancelReaso .header(IDEMPOTENT_KEY, IdempotencyKey) .bodyValue(request) .retrieve() - .bodyToMono(PaymentCancelResponse.class) + .bodyToMono(TossPaymentCancelResponse.class) .block(); } catch (WebClientResponseException e) { throw handleErrorResponse(e); diff --git a/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java new file mode 100644 index 0000000..f057d54 --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java @@ -0,0 +1,52 @@ +package in.koreatech.payment.gateway.toss; + +import static in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse.CancelInfo; + +import org.springframework.stereotype.Service; + +import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class TossPaymentGatewayService implements PaymentGatewayService { + + private final TossPaymentClient tossPaymentClient; + + public PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount) { + TossPaymentConfirmResponse tossPaymentConfirmResponse = tossPaymentClient.requestConfirm(paymentKey, pgOrderId, + amount); + + return new PgPaymentConfirmResponse( + tossPaymentConfirmResponse.paymentKey(), + tossPaymentConfirmResponse.totalAmount(), + tossPaymentConfirmResponse.orderId(), + tossPaymentConfirmResponse.status(), + tossPaymentConfirmResponse.method(), + tossPaymentConfirmResponse.requestedAt(), + tossPaymentConfirmResponse.approvedAt() + ); + } + + public PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey) { + TossPaymentCancelResponse tossPaymentCancelResponse = tossPaymentClient.requestCancel(paymentKey, cancelReason, idempotencyKey); + + return new PgPaymentCancelResponse( + tossPaymentCancelResponse.paymentKey(), + tossPaymentCancelResponse.orderId(), + tossPaymentCancelResponse.status(), + tossPaymentCancelResponse.cancels().stream() + .map(cancelInfo -> new CancelInfo( + cancelInfo.cancelAmount(), + cancelInfo.cancelReason(), + cancelInfo.canceledAt(), + cancelInfo.transactionKey() + )) + .toList() + ); + } +} diff --git a/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentCancelRequest.java b/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentCancelRequest.java new file mode 100644 index 0000000..50956a0 --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentCancelRequest.java @@ -0,0 +1,7 @@ +package in.koreatech.payment.gateway.toss.dto.request; + +public record TossPaymentCancelRequest( + String cancelReason +) { + +} diff --git a/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentConfirmRequest.java b/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentConfirmRequest.java new file mode 100644 index 0000000..3a2a2bd --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/toss/dto/request/TossPaymentConfirmRequest.java @@ -0,0 +1,9 @@ +package in.koreatech.payment.gateway.toss.dto.request; + +public record TossPaymentConfirmRequest( + String paymentKey, + String orderId, + Integer amount +) { + +} diff --git a/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentCancelResponse.java b/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentCancelResponse.java new file mode 100644 index 0000000..3a2d4ed --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentCancelResponse.java @@ -0,0 +1,20 @@ +package in.koreatech.payment.gateway.toss.dto.response; + +import java.util.List; + +public record TossPaymentCancelResponse( + String paymentKey, + String orderId, + String status, + List cancels +) { + public record CancelInfo( + Integer cancelAmount, + String cancelReason, + String canceledAt, + String transactionKey + ) { + + } + +} diff --git a/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentConfirmResponse.java new file mode 100644 index 0000000..6585b80 --- /dev/null +++ b/src/main/java/in/koreatech/payment/gateway/toss/dto/response/TossPaymentConfirmResponse.java @@ -0,0 +1,13 @@ +package in.koreatech.payment.gateway.toss.dto.response; + +public record TossPaymentConfirmResponse( + String paymentKey, + Integer totalAmount, + String orderId, + String status, + String method, + String requestedAt, + String approvedAt +) { + +} diff --git a/src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorCode.java b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorCode.java similarity index 99% rename from src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorCode.java rename to src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorCode.java index 21503f8..74170e5 100644 --- a/src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorCode.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorCode.java @@ -1,4 +1,4 @@ -package in.koreatech.payment.client.exception; +package in.koreatech.payment.gateway.toss.exception; import java.util.Map; import java.util.stream.Collectors; diff --git a/src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorResponse.java b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorResponse.java similarity index 62% rename from src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorResponse.java rename to src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorResponse.java index 5be3924..edea146 100644 --- a/src/main/java/in/koreatech/payment/client/exception/TossPaymentErrorResponse.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentErrorResponse.java @@ -1,4 +1,4 @@ -package in.koreatech.payment.client.exception; +package in.koreatech.payment.gateway.toss.exception; public record TossPaymentErrorResponse( String code, diff --git a/src/main/java/in/koreatech/payment/client/exception/TossPaymentException.java b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentException.java similarity index 92% rename from src/main/java/in/koreatech/payment/client/exception/TossPaymentException.java rename to src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentException.java index 3b47452..336f5c2 100644 --- a/src/main/java/in/koreatech/payment/client/exception/TossPaymentException.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/exception/TossPaymentException.java @@ -1,4 +1,4 @@ -package in.koreatech.payment.client.exception; +package in.koreatech.payment.gateway.toss.exception; public class TossPaymentException extends RuntimeException { diff --git a/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java new file mode 100644 index 0000000..327ba6c --- /dev/null +++ b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java @@ -0,0 +1,36 @@ +package in.koreatech.payment.mapper; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.koin.domain.order.model.PaymentCancel; +import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; + +@Component +public class PaymentCancelMapper { + + public List toEntity(Payment payment, PgPaymentCancelResponse pgPaymentCancelResponse) { + List paymentCancels = new ArrayList<>(); + List cancels = pgPaymentCancelResponse.cancels(); + + for (PgPaymentCancelResponse.CancelInfo cancelInfo : cancels) { + OffsetDateTime cancelOffsetDateTime = OffsetDateTime.parse(cancelInfo.canceledAt()); + LocalDateTime canceled = cancelOffsetDateTime.toLocalDateTime(); + + paymentCancels.add(PaymentCancel.builder() + .transactionKey(cancelInfo.transactionKey()) + .cancelReason(cancelInfo.cancelReason()) + .cancelAmount(cancelInfo.cancelAmount()) + .canceledAt(canceled) + .payment(payment) + .build()); + } + + return paymentCancels; + } +} diff --git a/src/main/java/in/koreatech/payment/client/dto/response/TossPaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java similarity index 56% rename from src/main/java/in/koreatech/payment/client/dto/response/TossPaymentConfirmResponse.java rename to src/main/java/in/koreatech/payment/mapper/PaymentMapper.java index cbcab26..7d231d0 100644 --- a/src/main/java/in/koreatech/payment/client/dto/response/TossPaymentConfirmResponse.java +++ b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java @@ -1,33 +1,31 @@ -package in.koreatech.payment.client.dto.response; +package in.koreatech.payment.mapper; import java.time.LocalDateTime; import java.time.OffsetDateTime; +import org.springframework.stereotype.Component; + import in.koreatech.koin.domain.order.model.Order; import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentMethod; import in.koreatech.koin.domain.order.model.PaymentStatus; +import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; + +@Component +public class PaymentMapper { -public record TossPaymentConfirmResponse( - String paymentKey, - Integer totalAmount, - String status, - String method, - String requestedAt, - String approvedAt -) { - public Payment toEntity(Order order) { - OffsetDateTime requestedOffsetDateTime = OffsetDateTime.parse(requestedAt); - OffsetDateTime approvedOffsetDateTime = OffsetDateTime.parse(approvedAt); + public Payment toEntity(Order order, PgPaymentConfirmResponse response) { + OffsetDateTime requestedOffsetDateTime = OffsetDateTime.parse(response.requestedAt()); + OffsetDateTime approvedOffsetDateTime = OffsetDateTime.parse(response.approvedAt()); LocalDateTime requested = requestedOffsetDateTime.toLocalDateTime(); LocalDateTime approved = approvedOffsetDateTime.toLocalDateTime(); return Payment.builder() - .paymentKey(paymentKey) - .amount(totalAmount) - .paymentStatus(PaymentStatus.valueOf(status)) - .paymentMethod(PaymentMethod.from(method)) + .paymentKey(response.paymentKey()) + .amount(response.totalAmount()) + .paymentStatus(PaymentStatus.valueOf(response.status())) + .paymentMethod(PaymentMethod.from(response.method())) .requestedAt(requested) .approvedAt(approved) .order(order) diff --git a/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java new file mode 100644 index 0000000..ccb9f06 --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java @@ -0,0 +1,33 @@ +package in.koreatech.payment.service; + +import java.util.UUID; + +import org.springframework.stereotype.Service; + +import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; +import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class PaymentIdempotencyKeyService { + + private final PaymentIdempotencyKeyRepository paymentIdempotencyKeyRepository; + + public String getOrCreate(Integer userId) { + return paymentIdempotencyKeyRepository + .findByUserId(userId) + .map(idempotencyKey -> { + if (idempotencyKey.isOlderThanExpireDays()) { + idempotencyKey.updateIdempotencyKey(UUID.randomUUID().toString()); + } + return idempotencyKey; + }) + .orElseGet(() -> paymentIdempotencyKeyRepository.save( + PaymentIdempotencyKey.builder() + .userId(userId) + .idempotencyKey(UUID.randomUUID().toString()) + .build() + )).getIdempotencyKey(); + } +} diff --git a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java b/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java index a9261e4..4ced520 100644 --- a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java +++ b/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java @@ -3,30 +3,19 @@ import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; import static org.springframework.transaction.event.TransactionPhase.AFTER_ROLLBACK; -import java.util.List; -import java.util.UUID; - import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; import in.koreatech.koin.domain.order.cart.repository.CartRepository; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; import in.koreatech.koin.domain.order.repository.OrderRepository; import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; import in.koreatech.koin.domain.order.repository.PaymentRepository; -import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; -import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.payment.client.TossPaymentClient; -import in.koreatech.payment.client.dto.response.PaymentCancelResponse; +import in.koreatech.payment.gateway.toss.TossPaymentClient; import in.koreatech.payment.event.TossPaymentRollBackEvent; -import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -51,43 +40,43 @@ public class TossPaymentRollBackService implements PaymentRollBackService { @TransactionalEventListener(phase = AFTER_ROLLBACK) @Transactional(propagation = REQUIRES_NEW) public void paymentRollback(TossPaymentRollBackEvent event) { - TemporaryPayment temporaryPayment = event.temporaryPayment(); - User user = userRepository.getById(temporaryPayment.getUserId()); - PaymentIdempotencyKey paymentIdempotencyKey = paymentIdempotencyKeyRepository - .findByUserId(user.getId()) - .map(idempotencyKey -> { - if (idempotencyKey.isOlderThanExpireDays()) { - idempotencyKey.updateIdempotencyKey(UUID.randomUUID().toString()); - } - return idempotencyKey; - }) - .orElseGet(() -> paymentIdempotencyKeyRepository.save( - PaymentIdempotencyKey.builder() - .userId(user.getId()) - .idempotencyKey(UUID.randomUUID().toString()) - .build() - )); - - PaymentCancelResponse response = tossPaymentClient.requestCancel(event.paymentKey(), - PAYMENT_CANCEL_REASON, paymentIdempotencyKey.getIdempotencyKey()); - - try { - OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); - Order order = temporaryPayment.toOrder(user, orderableShop); - orderRepository.save(order); - - Payment payment = event.tossPaymentConfirmResponse().toEntity(order); - payment.cancel(); - paymentRepository.save(payment); - - List paymentCancels = response.getPaymentCancels(payment); - paymentCancelRepository.saveAll(paymentCancels); - - temporaryPaymentRedisRepository.deleteById(order.getPgOrderId()); - cartRepository.deleteByUserId(user.getId()); - } catch (Exception e) { - log.error("결제 취소 과정에서 오류 발생 - paymentId: {}, userId: {}, orderId: {}", event.paymentKey(), - temporaryPayment.getUserId(), temporaryPayment.getPgOrderId()); - } + // TemporaryPayment temporaryPayment = event.temporaryPayment(); + // User user = userRepository.getById(temporaryPayment.getUserId()); + // PaymentIdempotencyKey paymentIdempotencyKey = paymentIdempotencyKeyRepository + // .findByUserId(user.getId()) + // .map(idempotencyKey -> { + // if (idempotencyKey.isOlderThanExpireDays()) { + // idempotencyKey.updateIdempotencyKey(UUID.randomUUID().toString()); + // } + // return idempotencyKey; + // }) + // .orElseGet(() -> paymentIdempotencyKeyRepository.save( + // PaymentIdempotencyKey.builder() + // .userId(user.getId()) + // .idempotencyKey(UUID.randomUUID().toString()) + // .build() + // )); + // + // PaymentCancelResponse response = tossPaymentClient.requestCancel(event.paymentKey(), + // PAYMENT_CANCEL_REASON, paymentIdempotencyKey.getIdempotencyKey()); + // + // try { + // OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); + // Order order = temporaryPayment.toOrder(user, orderableShop); + // orderRepository.save(order); + // + // Payment payment = event.tossPaymentConfirmResponse().toEntity(order); + // payment.cancel(); + // paymentRepository.save(payment); + // + // List paymentCancels = response.getPaymentCancels(payment); + // paymentCancelRepository.saveAll(paymentCancels); + // + // temporaryPaymentRedisRepository.deleteById(order.getPgOrderId()); + // cartRepository.deleteByUserId(user.getId()); + // } catch (Exception e) { + // log.error("결제 취소 과정에서 오류 발생 - paymentId: {}, userId: {}, orderId: {}", event.paymentKey(), + // temporaryPayment.getUserId(), temporaryPayment.getPgOrderId()); + // } } } diff --git a/src/main/java/in/koreatech/payment/service/TossService.java b/src/main/java/in/koreatech/payment/service/TossService.java index 17ba8b4..d35c615 100644 --- a/src/main/java/in/koreatech/payment/service/TossService.java +++ b/src/main/java/in/koreatech/payment/service/TossService.java @@ -1,7 +1,6 @@ package in.koreatech.payment.service; import java.util.List; -import java.util.UUID; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -13,34 +12,33 @@ import in.koreatech.koin.domain.order.model.OrderMenu; import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; import in.koreatech.koin.domain.order.model.PaymentStatus; import in.koreatech.koin.domain.order.repository.OrderMenuRepository; import in.koreatech.koin.domain.order.repository.OrderRepository; import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; -import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; import in.koreatech.koin.domain.order.repository.PaymentRepository; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.payment.client.TossPaymentClient; -import in.koreatech.payment.client.dto.response.PaymentCancelResponse; -import in.koreatech.payment.client.dto.response.TossPaymentConfirmResponse; import in.koreatech.payment.common.auth.JwtProvider; import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; -import in.koreatech.payment.event.TossPaymentRollBackEvent; import in.koreatech.payment.exception.OrderPriceMismatchException; import in.koreatech.payment.exception.PaymentAlreadyCanceledException; import in.koreatech.payment.exception.PaymentCancelException; import in.koreatech.payment.exception.PaymentConfirmException; +import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; +import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.mapper.PaymentCancelMapper; +import in.koreatech.payment.mapper.PaymentMapper; import in.koreatech.payment.model.domain.TemporaryMenuItems; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import in.koreatech.payment.util.PgOrderIdGenerator; import in.koreatech.payment.util.TemporaryMenuItemConverter; import lombok.RequiredArgsConstructor; @@ -52,9 +50,8 @@ public class TossService implements PaymentService { private final PgOrderIdGenerator pgOrderIdGenerator; private final JwtProvider jwtProvider; private final UserRepository userRepository; - private final TossPaymentClient tossPaymentClient; private final PaymentRepository paymentRepository; - private final PaymentIdempotencyKeyRepository paymentIdempotencyKeyRepository; + private final PaymentIdempotencyKeyService paymentIdempotencyKeyService; private final PaymentCancelRepository paymentCancelRepository; private final CartRepository cartRepository; private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; @@ -62,6 +59,9 @@ public class TossService implements PaymentService { private final OrderRepository orderRepository; private final OrderMenuRepository orderMenuRepository; private final ApplicationEventPublisher applicationEventPublisher; + private final PaymentGatewayService paymentGatewayService; + private final PaymentMapper paymentMapper; + private final PaymentCancelMapper paymentCancelMappers; @Transactional public String createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { @@ -144,21 +144,21 @@ public String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeout } @Transactional - public PaymentConfirmResponse confirmPayment(String accessToken, String paymentKey, String orderId, - Integer amount) { + public PaymentConfirmResponse confirmPayment(String accessToken, String paymentKey, String orderId, Integer amount) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(orderId); temporaryPayment.validateMatches(orderId, user.getId(), amount); - TossPaymentConfirmResponse tossPaymentResponse = tossPaymentClient.requestConfirm(paymentKey, orderId, amount); - PaymentStatus paymentStatus = PaymentStatus.valueOf(tossPaymentResponse.status()); + PgPaymentConfirmResponse pgPaymentConfirmResponse = paymentGatewayService.confirmPayment(paymentKey, orderId, amount); + PaymentStatus paymentStatus = PaymentStatus.valueOf(pgPaymentConfirmResponse.status()); if (!paymentStatus.isDone()) { - throw PaymentConfirmException.withDetail("paymentStatus : " + tossPaymentResponse.status()); + throw PaymentConfirmException.withDetail("paymentStatus : " + pgPaymentConfirmResponse.status()); } - applicationEventPublisher.publishEvent( - TossPaymentRollBackEvent.from(paymentKey, temporaryPayment, tossPaymentResponse)); + // TODO. 롤백 로직 수정 + // applicationEventPublisher.publishEvent( + // TossPaymentRollBackEvent.from(paymentKey, temporaryPayment, paymentConfirmResponse)); OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); Order order = temporaryPayment.toOrder(user, orderableShop); @@ -169,7 +169,7 @@ public PaymentConfirmResponse confirmPayment(String accessToken, String paymentK .toList(); orderMenuRepository.saveAll(orderMenus); - Payment payment = tossPaymentResponse.toEntity(order); + Payment payment = paymentMapper.toEntity(order, pgPaymentConfirmResponse); paymentRepository.save(payment); temporaryPaymentRedisRepository.deleteById(orderId); cartRepository.deleteByUserId(user.getId()); @@ -186,29 +186,15 @@ public List cancelPayment(String accessToken, Integer paymentId, } payment.validateUserIdMatches(user.getId()); - PaymentIdempotencyKey paymentIdempotencyKey = paymentIdempotencyKeyRepository - .findByUserId(user.getId()) - .map(idempotencyKey -> { - if (idempotencyKey.isOlderThanExpireDays()) { - idempotencyKey.updateIdempotencyKey(UUID.randomUUID().toString()); - } - return idempotencyKey; - }) - .orElseGet(() -> paymentIdempotencyKeyRepository.save( - PaymentIdempotencyKey.builder() - .userId(user.getId()) - .idempotencyKey(UUID.randomUUID().toString()) - .build() - )); - - PaymentCancelResponse response = tossPaymentClient.requestCancel(payment.getPaymentKey(), cancelReason, - paymentIdempotencyKey.getIdempotencyKey()); - if (!PaymentStatus.valueOf(response.status()).isCanceled()) { - throw PaymentCancelException.withDetail("paymentStatus : " + response.status()); + String paymentIdempotencyKey = paymentIdempotencyKeyService.getOrCreate(user.getId()); + PgPaymentCancelResponse pgPaymentCancelResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), cancelReason, paymentIdempotencyKey); + if (!PaymentStatus.valueOf(pgPaymentCancelResponse.status()).isCanceled()) { + throw PaymentCancelException.withDetail("paymentStatus : " + pgPaymentCancelResponse.status()); } - + payment.cancel(); - List paymentCancels = response.getPaymentCancels(payment); + + List paymentCancels = paymentCancelMappers.toEntity(payment, pgPaymentCancelResponse); paymentCancelRepository.saveAll(paymentCancels); return paymentCancels; } diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index 8541457..2f88dbb 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -1,6 +1,6 @@ package in.koreatech.payment.acceptance.domain; -import static in.koreatech.payment.client.dto.response.PaymentCancelResponse.CancelInfo; +import static in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse.CancelInfo; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.eq; @@ -47,14 +47,14 @@ import in.koreatech.payment.acceptance.fixture.PaymentIdempotencyKeyFixture; import in.koreatech.payment.acceptance.fixture.ShopFixture; import in.koreatech.payment.acceptance.fixture.UserFixture; -import in.koreatech.payment.client.TossPaymentClient; -import in.koreatech.payment.client.dto.response.PaymentCancelResponse; -import in.koreatech.payment.client.dto.response.TossPaymentConfirmResponse; +import in.koreatech.payment.gateway.toss.TossPaymentClient; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; import in.koreatech.payment.common.auth.JwtProvider; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import in.koreatech.payment.service.PaymentRollBackService; -import in.koreatech.payment.util.PgOrderIdGenerator; +import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; public class PaymentApiTest extends AcceptanceTest { @@ -238,6 +238,7 @@ class PaymentSuccess { TossPaymentConfirmResponse confirmDto = new TossPaymentConfirmResponse( "pay_123", 24000, + "FAKE_ORDER_123", "DONE", "카드", "2024-01-01T10:00:00+09:00", @@ -354,6 +355,7 @@ class PaymentSuccess { TossPaymentConfirmResponse confirmDto = new TossPaymentConfirmResponse( "pay_123", 24000, + "FAKE_ORDER_123", "DONE", "카드", "2024-01-01T10:00:00+09:00", @@ -463,6 +465,7 @@ class PaymentSuccess { TossPaymentConfirmResponse confirmDto = new TossPaymentConfirmResponse( "pay_123", 24000, + "FAKE_ORDER_123", "DONE", "카드", "2024-01-01T10:00:00+09:00", @@ -472,7 +475,7 @@ class PaymentSuccess { .thenReturn(confirmDto); given(pgOrderIdGenerator.generatePgOrderId()).willReturn("FAKE_ORDER_123"); - PaymentCancelResponse cancelDto = new PaymentCancelResponse( + TossPaymentCancelResponse cancelDto = new TossPaymentCancelResponse( "pay_123", "FAKE_ORDER_123", "CANCELED", diff --git a/src/test/java/in/koreatech/payment/unit/client/TossPaymentClientTest.java b/src/test/java/in/koreatech/payment/unit/client/TossPaymentClientTest.java index de11edb..bc47800 100644 --- a/src/test/java/in/koreatech/payment/unit/client/TossPaymentClientTest.java +++ b/src/test/java/in/koreatech/payment/unit/client/TossPaymentClientTest.java @@ -1,6 +1,6 @@ package in.koreatech.payment.unit.client; -import static in.koreatech.payment.client.dto.response.PaymentCancelResponse.CancelInfo; +import static in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse.CancelInfo; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; @@ -20,10 +20,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import in.koreatech.payment.client.TossPaymentClient; -import in.koreatech.payment.client.dto.response.PaymentCancelResponse; -import in.koreatech.payment.client.dto.response.TossPaymentConfirmResponse; -import in.koreatech.payment.client.exception.TossPaymentException; +import in.koreatech.payment.gateway.toss.TossPaymentClient; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; +import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; +import in.koreatech.payment.gateway.toss.exception.TossPaymentException; import in.koreatech.payment.unit.support.MockHttpServer; import okhttp3.mockwebserver.RecordedRequest; @@ -57,6 +57,7 @@ class PaymentConfirmSuccess { TossPaymentConfirmResponse dto = new TossPaymentConfirmResponse( "pay_123", 15000, + "FAKE_ORDER_123", "DONE", "CARD", "2024-01-01T10:00:00+09:00", @@ -143,7 +144,7 @@ class PaymentCancelSuccess { @Test void 결제_취소_요청을_성공한다() throws Exception { // given - PaymentCancelResponse dto = new PaymentCancelResponse( + TossPaymentCancelResponse dto = new TossPaymentCancelResponse( "pay_123", "a4CWyWY5m89PNh7xJwhk1", "CANCELED", @@ -157,7 +158,7 @@ class PaymentCancelSuccess { mockHttpServer.enqueueJson(objectMapper.writeValueAsString(dto), 200); // when - PaymentCancelResponse response = tossPaymentClient.requestCancel( + TossPaymentCancelResponse response = tossPaymentClient.requestCancel( "pay_123", "단순 변심이에요", "91b0343a-423d-431d-832c-031d9391afae" From 2bec7d9cd936d7e1b8057a2df75bab958d33fd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:48:31 +0900 Subject: [PATCH 03/29] =?UTF-8?q?fix:=20PaymentService=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/controller/PaymentsController.java | 1 - .../payment/service/PaymentService.java | 17 ----------------- .../koreatech/payment/service/TossService.java | 2 +- 3 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/service/PaymentService.java diff --git a/src/main/java/in/koreatech/payment/controller/PaymentsController.java b/src/main/java/in/koreatech/payment/controller/PaymentsController.java index 2fa2eff..bc2b9a3 100644 --- a/src/main/java/in/koreatech/payment/controller/PaymentsController.java +++ b/src/main/java/in/koreatech/payment/controller/PaymentsController.java @@ -20,7 +20,6 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; -import in.koreatech.payment.service.PaymentService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java deleted file mode 100644 index 9c99a42..0000000 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ /dev/null @@ -1,17 +0,0 @@ -package in.koreatech.payment.service; - -import java.util.List; - -import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; -import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; -import in.koreatech.payment.dto.response.PaymentConfirmResponse; -import in.koreatech.payment.dto.response.PaymentResponse; - -public interface PaymentService { - String createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request); - String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeoutPaymentSaveRequest request); - PaymentConfirmResponse confirmPayment(String accessToken, String paymentKey, String orderId, Integer amount); - List cancelPayment(String accessToken, Integer paymentId, String cancelReason); - PaymentResponse getPayment(String accessToken, Integer paymentId); -} diff --git a/src/main/java/in/koreatech/payment/service/TossService.java b/src/main/java/in/koreatech/payment/service/TossService.java index d35c615..21126d9 100644 --- a/src/main/java/in/koreatech/payment/service/TossService.java +++ b/src/main/java/in/koreatech/payment/service/TossService.java @@ -45,7 +45,7 @@ @Service @RequiredArgsConstructor @Transactional(readOnly = true) -public class TossService implements PaymentService { +public class TossService { private final PgOrderIdGenerator pgOrderIdGenerator; private final JwtProvider jwtProvider; From 5aa8e4a5e03487c6a36e857aa3964d478d0b540d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:52:07 +0900 Subject: [PATCH 04/29] =?UTF-8?q?fix:=20DTO=20=EB=B3=80=ED=99=98=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/controller/PaymentsController.java | 18 ++++++------------ .../{TossService.java => PaymentService.java} | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 20 deletions(-) rename src/main/java/in/koreatech/payment/service/{TossService.java => PaymentService.java} (93%) diff --git a/src/main/java/in/koreatech/payment/controller/PaymentsController.java b/src/main/java/in/koreatech/payment/controller/PaymentsController.java index bc2b9a3..c3ff5b8 100644 --- a/src/main/java/in/koreatech/payment/controller/PaymentsController.java +++ b/src/main/java/in/koreatech/payment/controller/PaymentsController.java @@ -1,7 +1,5 @@ package in.koreatech.payment.controller; -import java.util.List; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -10,7 +8,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import in.koreatech.koin.domain.order.model.PaymentCancel; import in.koreatech.payment.common.auth.AccessToken; import in.koreatech.payment.dto.request.PaymentCancelRequest; import in.koreatech.payment.dto.request.PaymentConfirmRequest; @@ -20,6 +17,7 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; +import in.koreatech.payment.service.PaymentService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -35,8 +33,7 @@ public ResponseEntity createTemporaryDeliveryPayment( @RequestBody @Valid final TemporaryDeliveryPaymentSaveRequest request, @AccessToken final String accessToken ) { - String orderId = paymentService.createTemporaryDeliveryPayment(accessToken, request); - TemporaryPaymentResponse response = TemporaryPaymentResponse.of(orderId); + TemporaryPaymentResponse response = paymentService.createTemporaryDeliveryPayment(accessToken, request); return ResponseEntity.ok(response); } @@ -45,8 +42,7 @@ public ResponseEntity createTemporaryTakeoutPayment( @RequestBody @Valid final TemporaryTakeoutPaymentSaveRequest request, @AccessToken final String accessToken ) { - String orderId = paymentService.createTemporaryTakeoutPayment(accessToken, request); - TemporaryPaymentResponse response = TemporaryPaymentResponse.of(orderId); + TemporaryPaymentResponse response = paymentService.createTemporaryTakeoutPayment(accessToken, request); return ResponseEntity.ok(response); } @@ -55,8 +51,8 @@ public ResponseEntity confirmPayment( @RequestBody @Valid final PaymentConfirmRequest request, @AccessToken final String accessToken ) { - PaymentConfirmResponse response = paymentService.confirmPayment(accessToken, request.paymentKey(), request.orderId(), - request.amount()); + PaymentConfirmResponse response = paymentService.confirmPayment(accessToken, request.paymentKey(), + request.orderId(), request.amount()); return ResponseEntity.ok(response); } @@ -66,9 +62,7 @@ public ResponseEntity cancelPayment( @RequestBody @Valid final PaymentCancelRequest request, @AccessToken final String accessToken ) { - List paymentCancels = paymentService.cancelPayment(accessToken, paymentId, - request.cancelReason()); - PaymentCancelResponse response = PaymentCancelResponse.from(paymentCancels); + PaymentCancelResponse response = paymentService.cancelPayment(accessToken, paymentId, request.cancelReason()); return ResponseEntity.ok(response); } diff --git a/src/main/java/in/koreatech/payment/service/TossService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java similarity index 93% rename from src/main/java/in/koreatech/payment/service/TossService.java rename to src/main/java/in/koreatech/payment/service/PaymentService.java index 21126d9..4ed9f4b 100644 --- a/src/main/java/in/koreatech/payment/service/TossService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -24,8 +24,10 @@ import in.koreatech.payment.common.auth.JwtProvider; import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; +import in.koreatech.payment.dto.response.PaymentCancelResponse; import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; +import in.koreatech.payment.dto.response.TemporaryPaymentResponse; import in.koreatech.payment.exception.OrderPriceMismatchException; import in.koreatech.payment.exception.PaymentAlreadyCanceledException; import in.koreatech.payment.exception.PaymentCancelException; @@ -45,7 +47,7 @@ @Service @RequiredArgsConstructor @Transactional(readOnly = true) -public class TossService { +public class PaymentService { private final PgOrderIdGenerator pgOrderIdGenerator; private final JwtProvider jwtProvider; @@ -64,7 +66,7 @@ public class TossService { private final PaymentCancelMapper paymentCancelMappers; @Transactional - public String createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { + public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); @@ -103,11 +105,11 @@ public String createTemporaryDeliveryPayment(String accessToken, TemporaryDelive ); temporaryPaymentRedisRepository.save(deliveryEntity); - return pgOrderId; + return TemporaryPaymentResponse.of(pgOrderId); } @Transactional - public String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeoutPaymentSaveRequest request) { + public TemporaryPaymentResponse createTemporaryTakeoutPayment(String accessToken, TemporaryTakeoutPaymentSaveRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); @@ -140,7 +142,7 @@ public String createTemporaryTakeoutPayment(String accessToken, TemporaryTakeout ); temporaryPaymentRedisRepository.save(deliveryEntity); - return pgOrderId; + return TemporaryPaymentResponse.of(pgOrderId); } @Transactional @@ -177,7 +179,7 @@ public PaymentConfirmResponse confirmPayment(String accessToken, String paymentK } @Transactional - public List cancelPayment(String accessToken, Integer paymentId, String cancelReason) { + public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, String cancelReason) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); Payment payment = paymentRepository.getById(paymentId); @@ -191,12 +193,12 @@ public List cancelPayment(String accessToken, Integer paymentId, if (!PaymentStatus.valueOf(pgPaymentCancelResponse.status()).isCanceled()) { throw PaymentCancelException.withDetail("paymentStatus : " + pgPaymentCancelResponse.status()); } - + payment.cancel(); List paymentCancels = paymentCancelMappers.toEntity(payment, pgPaymentCancelResponse); paymentCancelRepository.saveAll(paymentCancels); - return paymentCancels; + return PaymentCancelResponse.from(paymentCancels); } public PaymentResponse getPayment(String accessToken, Integer paymentId) { From 9f01554d4a5a636b876a8a5c7450ba0e163c40e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:53:18 +0900 Subject: [PATCH 05/29] =?UTF-8?q?fix:=20PaymentRollBackService=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/payment/service/PaymentRollBackService.java | 7 ------- .../payment/acceptance/domain/PaymentApiTest.java | 1 - 2 files changed, 8 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/service/PaymentRollBackService.java diff --git a/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java b/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java deleted file mode 100644 index 0b42951..0000000 --- a/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java +++ /dev/null @@ -1,7 +0,0 @@ -package in.koreatech.payment.service; - -import in.koreatech.payment.event.TossPaymentRollBackEvent; - -public interface PaymentRollBackService { - void paymentRollback(TossPaymentRollBackEvent event); -} diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index 2f88dbb..0903ff6 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -53,7 +53,6 @@ import in.koreatech.payment.common.auth.JwtProvider; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import in.koreatech.payment.service.PaymentRollBackService; import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; public class PaymentApiTest extends AcceptanceTest { From 0b58bd96c42583211329fc54e2e4283a41d220fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Wed, 27 Aug 2025 21:54:29 +0900 Subject: [PATCH 06/29] =?UTF-8?q?chore:=20TossPaymentRollBackService=20->?= =?UTF-8?q?=20PaymentRollBackService=20=EC=9C=BC=EB=A1=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sPaymentRollBackService.java => PaymentRollBackService.java} | 2 +- .../in/koreatech/payment/acceptance/domain/PaymentApiTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename src/main/java/in/koreatech/payment/service/{TossPaymentRollBackService.java => PaymentRollBackService.java} (98%) diff --git a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java b/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java similarity index 98% rename from src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java rename to src/main/java/in/koreatech/payment/service/PaymentRollBackService.java index 4ced520..18090ae 100644 --- a/src/main/java/in/koreatech/payment/service/TossPaymentRollBackService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java @@ -23,7 +23,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class TossPaymentRollBackService implements PaymentRollBackService { +public class PaymentRollBackService { private final TossPaymentClient tossPaymentClient; private final PaymentIdempotencyKeyRepository paymentIdempotencyKeyRepository; diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index 0903ff6..a01cf5e 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -54,6 +54,7 @@ import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; +import in.koreatech.payment.service.PaymentRollBackService; public class PaymentApiTest extends AcceptanceTest { From feff5709fd3d8ff15ea6d67b1978bf5cf9dae7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:19:35 +0900 Subject: [PATCH 07/29] =?UTF-8?q?feat:=20TemporaryPaymentService=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TemporaryPaymentService.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java new file mode 100644 index 0000000..2ee09d0 --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -0,0 +1,111 @@ +package in.koreatech.payment.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import in.koreatech.koin.domain.order.cart.model.Cart; +import in.koreatech.koin.domain.order.cart.repository.CartRepository; +import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; +import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; +import in.koreatech.payment.dto.response.TemporaryPaymentResponse; +import in.koreatech.payment.exception.OrderPriceMismatchException; +import in.koreatech.payment.model.domain.TemporaryMenuItems; +import in.koreatech.payment.model.redis.TemporaryPayment; +import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; +import in.koreatech.payment.util.TemporaryMenuItemConverter; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class TemporaryPaymentService { + + private final CartRepository cartRepository; + private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; + + @Transactional + public TemporaryPaymentResponse createDeliveryPayment(User user, String pgOrderId, TemporaryDeliveryPaymentSaveRequest request) { + Cart cart = cartRepository.getCartByUserId(user.getId()); + OrderableShop orderableShop = cart.getOrderableShop(); + + List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); + int totalProductPrice = cart.calculateItemsAmount(); + int deliveryFee = orderableShop.calculateDeliveryFee(totalProductPrice); + int finalAmount = totalProductPrice + deliveryFee; + + validateDeliveryPrice(request, totalProductPrice, deliveryFee, finalAmount); + + TemporaryPayment deliveryEntity = TemporaryPayment.toDeliveryEntity( + pgOrderId, + user.getId(), + orderableShop.getId(), + request.phoneNumber(), + request.address(), + request.toOwner(), + request.toRider(), + request.provideCutlery(), + totalProductPrice, + deliveryFee, + finalAmount, + temporaryMenuItems + ); + + temporaryPaymentRedisRepository.save(deliveryEntity); + return TemporaryPaymentResponse.of(pgOrderId); + } + + @Transactional + public TemporaryPaymentResponse createTakeoutPayment(User user, String pgOrderId, TemporaryTakeoutPaymentSaveRequest request) { + Cart cart = cartRepository.getCartByUserId(user.getId()); + OrderableShop orderableShop = cart.getOrderableShop(); + + List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); + int totalProductPrice = cart.calculateItemsAmount(); + int finalAmount = totalProductPrice; + + validateTakeoutPrice(request, totalProductPrice, finalAmount); + + TemporaryPayment takeoutEntity = TemporaryPayment.toTakeOutEntity( + pgOrderId, + user.getId(), + orderableShop.getId(), + request.phoneNumber(), + request.toOwner(), + request.provideCutlery(), + totalProductPrice, + finalAmount, + temporaryMenuItems + ); + + temporaryPaymentRedisRepository.save(takeoutEntity); + return TemporaryPaymentResponse.of(pgOrderId); + } + + private void validateDeliveryPrice( + TemporaryDeliveryPaymentSaveRequest request, int totalProductPrice, int deliveryFee, int finalAmount + ) { + if (!request.totalMenuPrice().equals(totalProductPrice) + || !request.deliveryTip().equals(deliveryFee) + || !request.totalAmount().equals(finalAmount) + ) { + throw OrderPriceMismatchException.withDetail( + "totalProductPrice : " + totalProductPrice + "deliveryFee : " + deliveryFee + "totalAmount : " + + totalProductPrice + "finalAmount : " + finalAmount); + } + } + + private void validateTakeoutPrice( + TemporaryTakeoutPaymentSaveRequest request, int totalProductPrice, int finalAmount + ) { + if (!request.totalMenuPrice().equals(totalProductPrice) + || !request.totalAmount().equals(finalAmount) + ) { + throw OrderPriceMismatchException.withDetail( + "totalProductPrice : " + totalProductPrice + "finalAmount : " + finalAmount); + } + } +} From 7ea0b5601c41befc40a202926c8b7ab7b86f4984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:28:38 +0900 Subject: [PATCH 08/29] =?UTF-8?q?fix:=20pgOrderId=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=20PaymentGatewayService=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/gateway/pg/PaymentGatewayService.java | 1 + .../payment/gateway/toss/TossPaymentGatewayService.java | 6 ++++++ .../payment/service/TemporaryPaymentService.java | 8 ++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java index f4ddccd..e1f50d2 100644 --- a/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java +++ b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java @@ -6,4 +6,5 @@ public interface PaymentGatewayService { PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount); PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey); + String generatePgOrderId(); } diff --git a/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java index f057d54..ebb284f 100644 --- a/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service; import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; @@ -16,6 +17,7 @@ public class TossPaymentGatewayService implements PaymentGatewayService { private final TossPaymentClient tossPaymentClient; + private final PgOrderIdGenerator pgOrderIdGenerator; public PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount) { TossPaymentConfirmResponse tossPaymentConfirmResponse = tossPaymentClient.requestConfirm(paymentKey, pgOrderId, @@ -49,4 +51,8 @@ public PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelRea .toList() ); } + + public String generatePgOrderId() { + return pgOrderIdGenerator.generatePgOrderId(); + } } diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index 2ee09d0..5f25a80 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -13,6 +13,7 @@ import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; import in.koreatech.payment.exception.OrderPriceMismatchException; +import in.koreatech.payment.gateway.pg.PaymentGatewayService; import in.koreatech.payment.model.domain.TemporaryMenuItems; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; @@ -25,10 +26,11 @@ public class TemporaryPaymentService { private final CartRepository cartRepository; + private final PaymentGatewayService paymentGatewayService; private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; @Transactional - public TemporaryPaymentResponse createDeliveryPayment(User user, String pgOrderId, TemporaryDeliveryPaymentSaveRequest request) { + public TemporaryPaymentResponse createDeliveryPayment(User user, TemporaryDeliveryPaymentSaveRequest request) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); @@ -39,6 +41,7 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, String pgOrderI validateDeliveryPrice(request, totalProductPrice, deliveryFee, finalAmount); + String pgOrderId = paymentGatewayService.generatePgOrderId(); TemporaryPayment deliveryEntity = TemporaryPayment.toDeliveryEntity( pgOrderId, user.getId(), @@ -59,7 +62,7 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, String pgOrderI } @Transactional - public TemporaryPaymentResponse createTakeoutPayment(User user, String pgOrderId, TemporaryTakeoutPaymentSaveRequest request) { + public TemporaryPaymentResponse createTakeoutPayment(User user, TemporaryTakeoutPaymentSaveRequest request) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); @@ -69,6 +72,7 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, String pgOrderId validateTakeoutPrice(request, totalProductPrice, finalAmount); + String pgOrderId = paymentGatewayService.generatePgOrderId(); TemporaryPayment takeoutEntity = TemporaryPayment.toTakeOutEntity( pgOrderId, user.getId(), From 022c4d9b09443c376bd1e21bffe983485afeb775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:30:32 +0900 Subject: [PATCH 09/29] =?UTF-8?q?refactor:=20PaymentService=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EA=B2=B0=EC=A0=9C=20=EC=83=9D=EC=84=B1=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentService.java | 72 +------------------ 1 file changed, 3 insertions(+), 69 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index 4ed9f4b..6c553e7 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -49,7 +49,6 @@ @Transactional(readOnly = true) public class PaymentService { - private final PgOrderIdGenerator pgOrderIdGenerator; private final JwtProvider jwtProvider; private final UserRepository userRepository; private final PaymentRepository paymentRepository; @@ -64,85 +63,20 @@ public class PaymentService { private final PaymentGatewayService paymentGatewayService; private final PaymentMapper paymentMapper; private final PaymentCancelMapper paymentCancelMappers; + private final TemporaryPaymentService temporaryPaymentService; @Transactional public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - - Cart cart = cartRepository.getCartByUserId(user.getId()); - - OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); - int totalProductPrice = cart.calculateItemsAmount(); - int deliveryFee = orderableShop.calculateDeliveryFee(totalProductPrice); - int finalAmount = totalProductPrice + deliveryFee; - - if (!request.totalMenuPrice().equals(totalProductPrice) - || !request.deliveryTip().equals(deliveryFee) - || !request.totalAmount().equals(finalAmount) - ) { - throw OrderPriceMismatchException.withDetail( - "totalProductPrice : " + totalProductPrice + "deliveryFee : " + deliveryFee + "totalAmount : " - + totalProductPrice + "finalAmount : " + finalAmount); - } - - String pgOrderId = pgOrderIdGenerator.generatePgOrderId(); - - TemporaryPayment deliveryEntity = TemporaryPayment.toDeliveryEntity( - pgOrderId, - user.getId(), - orderableShop.getId(), - request.phoneNumber(), - request.address(), - request.toOwner(), - request.toRider(), - request.provideCutlery(), - totalProductPrice, - deliveryFee, - finalAmount, - temporaryMenuItems - ); - - temporaryPaymentRedisRepository.save(deliveryEntity); - return TemporaryPaymentResponse.of(pgOrderId); + return temporaryPaymentService.createDeliveryPayment(user, request); } @Transactional public TemporaryPaymentResponse createTemporaryTakeoutPayment(String accessToken, TemporaryTakeoutPaymentSaveRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - - Cart cart = cartRepository.getCartByUserId(user.getId()); - - OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); - int totalProductPrice = cart.calculateItemsAmount(); - int finalAmount = totalProductPrice; - - if (!request.totalMenuPrice().equals(totalProductPrice) - || !request.totalAmount().equals(finalAmount) - ) { - throw OrderPriceMismatchException.withDetail( - "totalProductPrice : " + totalProductPrice + "finalAmount : " + finalAmount); - } - - String pgOrderId = pgOrderIdGenerator.generatePgOrderId(); - - TemporaryPayment deliveryEntity = TemporaryPayment.toTakeOutEntity( - pgOrderId, - user.getId(), - orderableShop.getId(), - request.phoneNumber(), - request.toOwner(), - request.provideCutlery(), - totalProductPrice, - finalAmount, - temporaryMenuItems - ); - - temporaryPaymentRedisRepository.save(deliveryEntity); - return TemporaryPaymentResponse.of(pgOrderId); + return temporaryPaymentService.createTakeoutPayment(user, request); } @Transactional From f7581d1aa5157c1ef18beb71d4b17f9571888108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:34:01 +0900 Subject: [PATCH 10/29] =?UTF-8?q?feat:=20PaymentConfirmService=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/PaymentConfirmService.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/main/java/in/koreatech/payment/service/PaymentConfirmService.java diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java new file mode 100644 index 0000000..fb3b299 --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -0,0 +1,81 @@ +package in.koreatech.payment.service; + +import in.koreatech.koin.domain.order.cart.repository.CartRepository; +import in.koreatech.koin.domain.order.model.Order; +import in.koreatech.koin.domain.order.model.OrderMenu; +import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.koin.domain.order.model.PaymentStatus; +import in.koreatech.koin.domain.order.repository.OrderMenuRepository; +import in.koreatech.koin.domain.order.repository.OrderRepository; +import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; +import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.payment.dto.response.PaymentConfirmResponse; +import in.koreatech.payment.exception.PaymentConfirmException; +import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.mapper.PaymentMapper; +import in.koreatech.payment.model.redis.TemporaryPayment; +import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class PaymentConfirmService { + + private final PaymentGatewayService paymentGatewayService; + private final OrderableShopRepository orderableShopRepository; + private final OrderRepository orderRepository; + private final OrderMenuRepository orderMenuRepository; + private final PaymentRepository paymentRepository; + private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; + private final CartRepository cartRepository; + private final PaymentMapper paymentMapper; + + @Transactional + public PaymentConfirmResponse confirmPayment(User user, String paymentKey, String orderId, Integer amount) { + TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(orderId); + temporaryPayment.validateMatches(orderId, user.getId(), amount); + + PgPaymentConfirmResponse pgResponse = paymentGatewayService.confirmPayment(paymentKey, orderId, amount); + validatePaymentStatus(pgResponse.status()); + + OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); + Order order = temporaryPayment.toOrder(user, orderableShop); + orderRepository.save(order); + + List orderMenus = createOrderMenus(temporaryPayment, order); + orderMenuRepository.saveAll(orderMenus); + + Payment payment = paymentMapper.toEntity(order, pgResponse); + paymentRepository.save(payment); + + cleanupAfterPaymentConfirm(orderId, user.getId()); + + return PaymentConfirmResponse.of(payment, order, orderMenus); + } + + private void validatePaymentStatus(String status) { + PaymentStatus paymentStatus = PaymentStatus.valueOf(status); + if (!paymentStatus.isDone()) { + throw PaymentConfirmException.withDetail("paymentStatus : " + status); + } + } + + private List createOrderMenus(TemporaryPayment temporaryPayment, Order order) { + return temporaryPayment.getTemporaryMenuItems().stream() + .map(temporaryMenuItems -> temporaryMenuItems.toOrderMenu(order)) + .toList(); + } + + private void cleanupAfterPaymentConfirm(String orderId, Integer userId) { + temporaryPaymentRedisRepository.deleteById(orderId); + cartRepository.deleteByUserId(userId); + } +} From 2a21e946b32be11801fe22876dccdb854645157b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:35:21 +0900 Subject: [PATCH 11/29] =?UTF-8?q?refactor:=20PaymentService=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=8A=B9=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC?= =?UTF-8?q?=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentService.java | 50 +------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index 6c553e7..2aa845b 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -2,23 +2,17 @@ import java.util.List; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import in.koreatech.koin.domain.order.cart.model.Cart; -import in.koreatech.koin.domain.order.cart.repository.CartRepository; import in.koreatech.koin.domain.order.model.Order; import in.koreatech.koin.domain.order.model.OrderMenu; import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentCancel; import in.koreatech.koin.domain.order.model.PaymentStatus; import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.OrderRepository; import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; import in.koreatech.koin.domain.order.repository.PaymentRepository; -import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; -import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; import in.koreatech.payment.common.auth.JwtProvider; @@ -28,20 +22,11 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; -import in.koreatech.payment.exception.OrderPriceMismatchException; import in.koreatech.payment.exception.PaymentAlreadyCanceledException; import in.koreatech.payment.exception.PaymentCancelException; -import in.koreatech.payment.exception.PaymentConfirmException; import in.koreatech.payment.gateway.pg.PaymentGatewayService; -import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; -import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; import in.koreatech.payment.mapper.PaymentCancelMapper; -import in.koreatech.payment.mapper.PaymentMapper; -import in.koreatech.payment.model.domain.TemporaryMenuItems; -import in.koreatech.payment.model.redis.TemporaryPayment; -import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import in.koreatech.payment.util.TemporaryMenuItemConverter; import lombok.RequiredArgsConstructor; @Service @@ -54,16 +39,11 @@ public class PaymentService { private final PaymentRepository paymentRepository; private final PaymentIdempotencyKeyService paymentIdempotencyKeyService; private final PaymentCancelRepository paymentCancelRepository; - private final CartRepository cartRepository; - private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; - private final OrderableShopRepository orderableShopRepository; - private final OrderRepository orderRepository; private final OrderMenuRepository orderMenuRepository; - private final ApplicationEventPublisher applicationEventPublisher; private final PaymentGatewayService paymentGatewayService; - private final PaymentMapper paymentMapper; private final PaymentCancelMapper paymentCancelMappers; private final TemporaryPaymentService temporaryPaymentService; + private final PaymentConfirmService paymentConfirmService; @Transactional public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { @@ -83,33 +63,7 @@ public TemporaryPaymentResponse createTemporaryTakeoutPayment(String accessToken public PaymentConfirmResponse confirmPayment(String accessToken, String paymentKey, String orderId, Integer amount) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(orderId); - temporaryPayment.validateMatches(orderId, user.getId(), amount); - - PgPaymentConfirmResponse pgPaymentConfirmResponse = paymentGatewayService.confirmPayment(paymentKey, orderId, amount); - PaymentStatus paymentStatus = PaymentStatus.valueOf(pgPaymentConfirmResponse.status()); - if (!paymentStatus.isDone()) { - throw PaymentConfirmException.withDetail("paymentStatus : " + pgPaymentConfirmResponse.status()); - } - - // TODO. 롤백 로직 수정 - // applicationEventPublisher.publishEvent( - // TossPaymentRollBackEvent.from(paymentKey, temporaryPayment, paymentConfirmResponse)); - - OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); - Order order = temporaryPayment.toOrder(user, orderableShop); - orderRepository.save(order); - - List orderMenus = temporaryPayment.getTemporaryMenuItems().stream() - .map(temporaryMenuItems -> temporaryMenuItems.toOrderMenu(order)) - .toList(); - orderMenuRepository.saveAll(orderMenus); - - Payment payment = paymentMapper.toEntity(order, pgPaymentConfirmResponse); - paymentRepository.save(payment); - temporaryPaymentRedisRepository.deleteById(orderId); - cartRepository.deleteByUserId(user.getId()); - return PaymentConfirmResponse.of(payment, order, orderMenus); + return paymentConfirmService.confirmPayment(user, paymentKey, orderId, amount); } @Transactional From 321114ac35a5a797b66a63af7e4a0bc685053c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:40:56 +0900 Subject: [PATCH 12/29] =?UTF-8?q?feat:=20PaymentCancelService=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentCancelService.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/java/in/koreatech/payment/service/PaymentCancelService.java diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java new file mode 100644 index 0000000..7f2a398 --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -0,0 +1,60 @@ +package in.koreatech.payment.service; + +import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.koin.domain.order.model.PaymentCancel; +import in.koreatech.koin.domain.order.model.PaymentStatus; +import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; +import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.payment.dto.response.PaymentCancelResponse; +import in.koreatech.payment.exception.PaymentAlreadyCanceledException; +import in.koreatech.payment.exception.PaymentCancelException; +import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.mapper.PaymentCancelMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class PaymentCancelService { + + private final PaymentRepository paymentRepository; + private final PaymentCancelRepository paymentCancelRepository; + private final PaymentGatewayService paymentGatewayService; + private final PaymentIdempotencyKeyService paymentIdempotencyKeyService; + private final PaymentCancelMapper paymentCancelMapper; + + @Transactional + public PaymentCancelResponse cancelPayment(User user, Integer paymentId, String cancelReason) { + Payment payment = paymentRepository.getById(paymentId); + validatePaymentStatusIsNotCanceled(payment); + payment.validateUserIdMatches(user.getId()); + + String paymentIdempotencyKey = paymentIdempotencyKeyService.getOrCreate(user.getId()); + PgPaymentCancelResponse pgResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), cancelReason, paymentIdempotencyKey); + validatePaymentIsCanceled(pgResponse.status()); + + payment.cancel(); + List paymentCancels = paymentCancelMapper.toEntity(payment, pgResponse); + paymentCancelRepository.saveAll(paymentCancels); + + return PaymentCancelResponse.from(paymentCancels); + } + + private void validatePaymentStatusIsNotCanceled(Payment payment) { + if (payment.getPaymentStatus().isCanceled()) { + throw PaymentAlreadyCanceledException.withDetail("paymentId : " + payment.getId()); + } + } + + private void validatePaymentIsCanceled(String status) { + if (!PaymentStatus.valueOf(status).isCanceled()) { + throw PaymentCancelException.withDetail("paymentStatus : " + status); + } + } +} From 384c9c4f01f25329a179435941c4aabe376e81a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:41:54 +0900 Subject: [PATCH 13/29] =?UTF-8?q?refactor:=20PaymentService=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=B7=A8=EC=86=8C=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC?= =?UTF-8?q?=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentService.java | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index 2aa845b..a56a660 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -8,10 +8,7 @@ import in.koreatech.koin.domain.order.model.Order; import in.koreatech.koin.domain.order.model.OrderMenu; import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.koin.domain.order.model.PaymentStatus; import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; import in.koreatech.koin.domain.order.repository.PaymentRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; @@ -22,11 +19,6 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; -import in.koreatech.payment.exception.PaymentAlreadyCanceledException; -import in.koreatech.payment.exception.PaymentCancelException; -import in.koreatech.payment.gateway.pg.PaymentGatewayService; -import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; -import in.koreatech.payment.mapper.PaymentCancelMapper; import lombok.RequiredArgsConstructor; @Service @@ -37,13 +29,10 @@ public class PaymentService { private final JwtProvider jwtProvider; private final UserRepository userRepository; private final PaymentRepository paymentRepository; - private final PaymentIdempotencyKeyService paymentIdempotencyKeyService; - private final PaymentCancelRepository paymentCancelRepository; private final OrderMenuRepository orderMenuRepository; - private final PaymentGatewayService paymentGatewayService; - private final PaymentCancelMapper paymentCancelMappers; private final TemporaryPaymentService temporaryPaymentService; private final PaymentConfirmService paymentConfirmService; + private final PaymentCancelService paymentCancelService; @Transactional public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { @@ -70,23 +59,7 @@ public PaymentConfirmResponse confirmPayment(String accessToken, String paymentK public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, String cancelReason) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - Payment payment = paymentRepository.getById(paymentId); - if (payment.getPaymentStatus().isCanceled()) { - throw PaymentAlreadyCanceledException.withDetail("paymentId : " + payment.getId()); - } - payment.validateUserIdMatches(user.getId()); - - String paymentIdempotencyKey = paymentIdempotencyKeyService.getOrCreate(user.getId()); - PgPaymentCancelResponse pgPaymentCancelResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), cancelReason, paymentIdempotencyKey); - if (!PaymentStatus.valueOf(pgPaymentCancelResponse.status()).isCanceled()) { - throw PaymentCancelException.withDetail("paymentStatus : " + pgPaymentCancelResponse.status()); - } - - payment.cancel(); - - List paymentCancels = paymentCancelMappers.toEntity(payment, pgPaymentCancelResponse); - paymentCancelRepository.saveAll(paymentCancels); - return PaymentCancelResponse.from(paymentCancels); + return paymentCancelService.cancelPayment(user, paymentId, cancelReason); } public PaymentResponse getPayment(String accessToken, Integer paymentId) { From 3a6f092696c16fc7bad31e98be22987588a5cc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:42:44 +0900 Subject: [PATCH 14/29] =?UTF-8?q?feat:=20PaymentQueryService=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentQueryService.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/in/koreatech/payment/service/PaymentQueryService.java diff --git a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java new file mode 100644 index 0000000..b7786da --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java @@ -0,0 +1,33 @@ +package in.koreatech.payment.service; + +import in.koreatech.koin.domain.order.model.Order; +import in.koreatech.koin.domain.order.model.OrderMenu; +import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.koin.domain.order.repository.OrderMenuRepository; +import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.payment.dto.response.PaymentResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class PaymentQueryService { + + private final PaymentRepository paymentRepository; + private final OrderMenuRepository orderMenuRepository; + + public PaymentResponse getPayment(User user, Integer paymentId) { + Payment payment = paymentRepository.getById(paymentId); + payment.validateUserIdMatches(user.getId()); + + Order order = payment.getOrder(); + List orderMenus = orderMenuRepository.findAllByOrderId(order.getId()); + + return PaymentResponse.of(payment, order, orderMenus); + } +} From 75f94f95599c0c78e94a7b0eba64987e8b435988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:43:26 +0900 Subject: [PATCH 15/29] =?UTF-8?q?refactor:=20PaymentService=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=A1=B0=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC?= =?UTF-8?q?=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/service/PaymentService.java | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index a56a660..da07d90 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -1,15 +1,8 @@ package in.koreatech.payment.service; -import java.util.List; - import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; import in.koreatech.payment.common.auth.JwtProvider; @@ -28,11 +21,10 @@ public class PaymentService { private final JwtProvider jwtProvider; private final UserRepository userRepository; - private final PaymentRepository paymentRepository; - private final OrderMenuRepository orderMenuRepository; private final TemporaryPaymentService temporaryPaymentService; private final PaymentConfirmService paymentConfirmService; private final PaymentCancelService paymentCancelService; + private final PaymentQueryService paymentQueryService; @Transactional public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { @@ -65,12 +57,6 @@ public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId public PaymentResponse getPayment(String accessToken, Integer paymentId) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - Payment payment = paymentRepository.getById(paymentId); - payment.validateUserIdMatches(user.getId()); - - Order order = payment.getOrder(); - List orderMenus = orderMenuRepository.findAllByOrderId(order.getId()); - - return PaymentResponse.of(payment, order, orderMenus); + return paymentQueryService.getPayment(user, paymentId); } } From 903de9c63868e576ad1d4999d933ff28862027ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 20:56:45 +0900 Subject: [PATCH 16/29] =?UTF-8?q?fix:=20PaymentService=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=20=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/controller/PaymentsController.java | 5 ++--- .../payment/service/PaymentService.java | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/in/koreatech/payment/controller/PaymentsController.java b/src/main/java/in/koreatech/payment/controller/PaymentsController.java index c3ff5b8..499f6fe 100644 --- a/src/main/java/in/koreatech/payment/controller/PaymentsController.java +++ b/src/main/java/in/koreatech/payment/controller/PaymentsController.java @@ -51,8 +51,7 @@ public ResponseEntity confirmPayment( @RequestBody @Valid final PaymentConfirmRequest request, @AccessToken final String accessToken ) { - PaymentConfirmResponse response = paymentService.confirmPayment(accessToken, request.paymentKey(), - request.orderId(), request.amount()); + PaymentConfirmResponse response = paymentService.confirmPayment(accessToken, request); return ResponseEntity.ok(response); } @@ -62,7 +61,7 @@ public ResponseEntity cancelPayment( @RequestBody @Valid final PaymentCancelRequest request, @AccessToken final String accessToken ) { - PaymentCancelResponse response = paymentService.cancelPayment(accessToken, paymentId, request.cancelReason()); + PaymentCancelResponse response = paymentService.cancelPayment(accessToken, paymentId, request); return ResponseEntity.ok(response); } diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index da07d90..0138b7a 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -6,6 +6,8 @@ import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; import in.koreatech.payment.common.auth.JwtProvider; +import in.koreatech.payment.dto.request.PaymentCancelRequest; +import in.koreatech.payment.dto.request.PaymentConfirmRequest; import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; import in.koreatech.payment.dto.response.PaymentCancelResponse; @@ -27,31 +29,35 @@ public class PaymentService { private final PaymentQueryService paymentQueryService; @Transactional - public TemporaryPaymentResponse createTemporaryDeliveryPayment(String accessToken, TemporaryDeliveryPaymentSaveRequest request) { + public TemporaryPaymentResponse createTemporaryDeliveryPayment( + String accessToken, TemporaryDeliveryPaymentSaveRequest request + ) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); return temporaryPaymentService.createDeliveryPayment(user, request); } @Transactional - public TemporaryPaymentResponse createTemporaryTakeoutPayment(String accessToken, TemporaryTakeoutPaymentSaveRequest request) { + public TemporaryPaymentResponse createTemporaryTakeoutPayment( + String accessToken, TemporaryTakeoutPaymentSaveRequest request + ) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); return temporaryPaymentService.createTakeoutPayment(user, request); } @Transactional - public PaymentConfirmResponse confirmPayment(String accessToken, String paymentKey, String orderId, Integer amount) { + public PaymentConfirmResponse confirmPayment(String accessToken, PaymentConfirmRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - return paymentConfirmService.confirmPayment(user, paymentKey, orderId, amount); + return paymentConfirmService.confirmPayment(user, request.paymentKey(), request.orderId(), request.amount()); } @Transactional - public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, String cancelReason) { + public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, PaymentCancelRequest request) { Integer userId = jwtProvider.getUserId(accessToken); User user = userRepository.getById(userId); - return paymentCancelService.cancelPayment(user, paymentId, cancelReason); + return paymentCancelService.cancelPayment(user, paymentId, request.cancelReason()); } public PaymentResponse getPayment(String accessToken, Integer paymentId) { From e073c38a4e97700423785d27c325d642138c7a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Thu, 28 Aug 2025 21:13:42 +0900 Subject: [PATCH 17/29] =?UTF-8?q?feat:=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/domain/DeliveryPaymentInfo.java | 47 ++++++++++++++++ .../model/domain/PaymentCancelInfo.java | 9 +++ .../model/domain/PaymentConfirmInfo.java | 11 ++++ .../model/domain/TakeoutPaymentInfo.java | 27 +++++++++ .../payment/service/PaymentCancelService.java | 14 +++-- .../service/PaymentConfirmService.java | 21 ++++--- .../payment/service/PaymentService.java | 55 +++++++++++++------ .../service/TemporaryPaymentService.java | 53 +++++------------- .../service/UserAuthenticationService.java | 20 +++++++ 9 files changed, 185 insertions(+), 72 deletions(-) create mode 100644 src/main/java/in/koreatech/payment/model/domain/DeliveryPaymentInfo.java create mode 100644 src/main/java/in/koreatech/payment/model/domain/PaymentCancelInfo.java create mode 100644 src/main/java/in/koreatech/payment/model/domain/PaymentConfirmInfo.java create mode 100644 src/main/java/in/koreatech/payment/model/domain/TakeoutPaymentInfo.java create mode 100644 src/main/java/in/koreatech/payment/service/UserAuthenticationService.java diff --git a/src/main/java/in/koreatech/payment/model/domain/DeliveryPaymentInfo.java b/src/main/java/in/koreatech/payment/model/domain/DeliveryPaymentInfo.java new file mode 100644 index 0000000..c8ee1d7 --- /dev/null +++ b/src/main/java/in/koreatech/payment/model/domain/DeliveryPaymentInfo.java @@ -0,0 +1,47 @@ +package in.koreatech.payment.model.domain; + +import in.koreatech.payment.exception.OrderPriceMismatchException; + +public record DeliveryPaymentInfo( + String phoneNumber, + String address, + String toOwner, + String toRider, + Boolean provideCutlery, + Integer totalMenuPrice, + Integer deliveryTip, + Integer totalAmount +) { + public static DeliveryPaymentInfo of( + String phoneNumber, + String address, + String toOwner, + String toRider, + Boolean provideCutlery, + Integer totalMenuPrice, + Integer deliveryTip, + Integer totalAmount + ) { + return new DeliveryPaymentInfo( + phoneNumber, + address, + toOwner, + toRider, + provideCutlery, + totalMenuPrice, + deliveryTip, + totalAmount + ); + } + + public void validatePrice(Integer totalProductPrice, Integer deliveryFee, Integer finalAmount) { + if (!totalMenuPrice().equals(totalProductPrice) + || !deliveryTip().equals(deliveryFee) + || !totalAmount().equals(finalAmount) + ) { + throw OrderPriceMismatchException.withDetail( + "totalProductPrice : " + totalProductPrice + "deliveryFee : " + deliveryFee + "totalAmount : " + + totalProductPrice + "finalAmount : " + finalAmount); + } + } +} diff --git a/src/main/java/in/koreatech/payment/model/domain/PaymentCancelInfo.java b/src/main/java/in/koreatech/payment/model/domain/PaymentCancelInfo.java new file mode 100644 index 0000000..3dd59f8 --- /dev/null +++ b/src/main/java/in/koreatech/payment/model/domain/PaymentCancelInfo.java @@ -0,0 +1,9 @@ +package in.koreatech.payment.model.domain; + +public record PaymentCancelInfo( + String cancelReason +) { + public static PaymentCancelInfo of(String cancelReason) { + return new PaymentCancelInfo(cancelReason); + } +} diff --git a/src/main/java/in/koreatech/payment/model/domain/PaymentConfirmInfo.java b/src/main/java/in/koreatech/payment/model/domain/PaymentConfirmInfo.java new file mode 100644 index 0000000..c232a67 --- /dev/null +++ b/src/main/java/in/koreatech/payment/model/domain/PaymentConfirmInfo.java @@ -0,0 +1,11 @@ +package in.koreatech.payment.model.domain; + +public record PaymentConfirmInfo( + String paymentKey, + String orderId, + Integer amount +) { + public static PaymentConfirmInfo of(String paymentKey, String orderId, Integer amount) { + return new PaymentConfirmInfo(paymentKey, orderId, amount); + } +} diff --git a/src/main/java/in/koreatech/payment/model/domain/TakeoutPaymentInfo.java b/src/main/java/in/koreatech/payment/model/domain/TakeoutPaymentInfo.java new file mode 100644 index 0000000..587f788 --- /dev/null +++ b/src/main/java/in/koreatech/payment/model/domain/TakeoutPaymentInfo.java @@ -0,0 +1,27 @@ +package in.koreatech.payment.model.domain; + +import in.koreatech.payment.exception.OrderPriceMismatchException; + +public record TakeoutPaymentInfo( + String phoneNumber, + String toOwner, + Boolean provideCutlery, + Integer totalProductPrice, + Integer totalAmount +) { + public static TakeoutPaymentInfo of( + String phoneNumber, String toOwner, Boolean provideCutlery, + Integer totalMenuPrice, Integer totalAmount + ) { + return new TakeoutPaymentInfo(phoneNumber, toOwner, provideCutlery, totalMenuPrice, totalAmount); + } + + public void validatePrice(Integer totalProductPrice, Integer finalAmount) { + if (!totalProductPrice().equals(totalProductPrice) + || !totalAmount().equals(finalAmount) + ) { + throw OrderPriceMismatchException.withDetail( + "totalProductPrice : " + totalProductPrice + "finalAmount : " + finalAmount); + } + } +} diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java index 7f2a398..7ec70ad 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -1,5 +1,10 @@ package in.koreatech.payment.service; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentCancel; import in.koreatech.koin.domain.order.model.PaymentStatus; @@ -12,11 +17,8 @@ import in.koreatech.payment.gateway.pg.PaymentGatewayService; import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; import in.koreatech.payment.mapper.PaymentCancelMapper; +import in.koreatech.payment.model.domain.PaymentCancelInfo; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; @Service @RequiredArgsConstructor @@ -30,13 +32,13 @@ public class PaymentCancelService { private final PaymentCancelMapper paymentCancelMapper; @Transactional - public PaymentCancelResponse cancelPayment(User user, Integer paymentId, String cancelReason) { + public PaymentCancelResponse cancelPayment(User user, Integer paymentId, PaymentCancelInfo paymentCancelInfo) { Payment payment = paymentRepository.getById(paymentId); validatePaymentStatusIsNotCanceled(payment); payment.validateUserIdMatches(user.getId()); String paymentIdempotencyKey = paymentIdempotencyKeyService.getOrCreate(user.getId()); - PgPaymentCancelResponse pgResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), cancelReason, paymentIdempotencyKey); + PgPaymentCancelResponse pgResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), paymentCancelInfo.cancelReason(), paymentIdempotencyKey); validatePaymentIsCanceled(pgResponse.status()); payment.cancel(); diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index fb3b299..dd1a042 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -1,5 +1,10 @@ package in.koreatech.payment.service; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import in.koreatech.koin.domain.order.cart.repository.CartRepository; import in.koreatech.koin.domain.order.model.Order; import in.koreatech.koin.domain.order.model.OrderMenu; @@ -16,13 +21,10 @@ import in.koreatech.payment.gateway.pg.PaymentGatewayService; import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; import in.koreatech.payment.mapper.PaymentMapper; +import in.koreatech.payment.model.domain.PaymentConfirmInfo; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; @Service @RequiredArgsConstructor @@ -39,11 +41,12 @@ public class PaymentConfirmService { private final PaymentMapper paymentMapper; @Transactional - public PaymentConfirmResponse confirmPayment(User user, String paymentKey, String orderId, Integer amount) { - TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(orderId); - temporaryPayment.validateMatches(orderId, user.getId(), amount); + public PaymentConfirmResponse confirmPayment(User user, PaymentConfirmInfo paymentConfirmInfo) { + TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(paymentConfirmInfo.orderId()); + temporaryPayment.validateMatches(paymentConfirmInfo.orderId(), user.getId(), paymentConfirmInfo.amount()); - PgPaymentConfirmResponse pgResponse = paymentGatewayService.confirmPayment(paymentKey, orderId, amount); + PgPaymentConfirmResponse pgResponse = paymentGatewayService.confirmPayment(paymentConfirmInfo.paymentKey(), + paymentConfirmInfo.orderId(), paymentConfirmInfo.amount()); validatePaymentStatus(pgResponse.status()); OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); @@ -56,7 +59,7 @@ public PaymentConfirmResponse confirmPayment(User user, String paymentKey, Strin Payment payment = paymentMapper.toEntity(order, pgResponse); paymentRepository.save(payment); - cleanupAfterPaymentConfirm(orderId, user.getId()); + cleanupAfterPaymentConfirm(paymentConfirmInfo.orderId(), user.getId()); return PaymentConfirmResponse.of(payment, order, orderMenus); } diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index 0138b7a..cd6592b 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -4,8 +4,6 @@ import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.payment.common.auth.JwtProvider; import in.koreatech.payment.dto.request.PaymentCancelRequest; import in.koreatech.payment.dto.request.PaymentConfirmRequest; import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; @@ -14,6 +12,10 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.dto.response.PaymentResponse; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; +import in.koreatech.payment.model.domain.DeliveryPaymentInfo; +import in.koreatech.payment.model.domain.PaymentCancelInfo; +import in.koreatech.payment.model.domain.PaymentConfirmInfo; +import in.koreatech.payment.model.domain.TakeoutPaymentInfo; import lombok.RequiredArgsConstructor; @Service @@ -21,8 +23,7 @@ @Transactional(readOnly = true) public class PaymentService { - private final JwtProvider jwtProvider; - private final UserRepository userRepository; + private final UserAuthenticationService userAuthenticationService; private final TemporaryPaymentService temporaryPaymentService; private final PaymentConfirmService paymentConfirmService; private final PaymentCancelService paymentCancelService; @@ -32,37 +33,55 @@ public class PaymentService { public TemporaryPaymentResponse createTemporaryDeliveryPayment( String accessToken, TemporaryDeliveryPaymentSaveRequest request ) { - Integer userId = jwtProvider.getUserId(accessToken); - User user = userRepository.getById(userId); - return temporaryPaymentService.createDeliveryPayment(user, request); + User user = userAuthenticationService.authenticateUser(accessToken); + DeliveryPaymentInfo deliveryPaymentInfo = DeliveryPaymentInfo.of( + request.phoneNumber(), + request.address(), + request.toOwner(), + request.toRider(), + request.provideCutlery(), + request.totalMenuPrice(), + request.deliveryTip(), + request.totalAmount() + ); + return temporaryPaymentService.createDeliveryPayment(user, deliveryPaymentInfo); } @Transactional public TemporaryPaymentResponse createTemporaryTakeoutPayment( String accessToken, TemporaryTakeoutPaymentSaveRequest request ) { - Integer userId = jwtProvider.getUserId(accessToken); - User user = userRepository.getById(userId); - return temporaryPaymentService.createTakeoutPayment(user, request); + User user = userAuthenticationService.authenticateUser(accessToken); + TakeoutPaymentInfo takeoutPaymentInfo = TakeoutPaymentInfo.of( + request.phoneNumber(), + request.toOwner(), + request.provideCutlery(), + request.totalMenuPrice(), + request.totalAmount() + ); + return temporaryPaymentService.createTakeoutPayment(user, takeoutPaymentInfo); } @Transactional public PaymentConfirmResponse confirmPayment(String accessToken, PaymentConfirmRequest request) { - Integer userId = jwtProvider.getUserId(accessToken); - User user = userRepository.getById(userId); - return paymentConfirmService.confirmPayment(user, request.paymentKey(), request.orderId(), request.amount()); + User user = userAuthenticationService.authenticateUser(accessToken); + PaymentConfirmInfo paymentConfirmInfo = PaymentConfirmInfo.of( + request.paymentKey(), + request.orderId(), + request.amount() + ); + return paymentConfirmService.confirmPayment(user, paymentConfirmInfo); } @Transactional public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, PaymentCancelRequest request) { - Integer userId = jwtProvider.getUserId(accessToken); - User user = userRepository.getById(userId); - return paymentCancelService.cancelPayment(user, paymentId, request.cancelReason()); + User user = userAuthenticationService.authenticateUser(accessToken); + PaymentCancelInfo paymentCancelInfo = PaymentCancelInfo.of(request.cancelReason()); + return paymentCancelService.cancelPayment(user, paymentId, paymentCancelInfo); } public PaymentResponse getPayment(String accessToken, Integer paymentId) { - Integer userId = jwtProvider.getUserId(accessToken); - User user = userRepository.getById(userId); + User user = userAuthenticationService.authenticateUser(accessToken); return paymentQueryService.getPayment(user, paymentId); } } diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index 5f25a80..d2db23c 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -9,11 +9,10 @@ import in.koreatech.koin.domain.order.cart.repository.CartRepository; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.payment.dto.request.TemporaryDeliveryPaymentSaveRequest; -import in.koreatech.payment.dto.request.TemporaryTakeoutPaymentSaveRequest; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; -import in.koreatech.payment.exception.OrderPriceMismatchException; import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.model.domain.DeliveryPaymentInfo; +import in.koreatech.payment.model.domain.TakeoutPaymentInfo; import in.koreatech.payment.model.domain.TemporaryMenuItems; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; @@ -30,7 +29,7 @@ public class TemporaryPaymentService { private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; @Transactional - public TemporaryPaymentResponse createDeliveryPayment(User user, TemporaryDeliveryPaymentSaveRequest request) { + public TemporaryPaymentResponse createDeliveryPayment(User user, DeliveryPaymentInfo deliveryPaymentInfo) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); @@ -39,18 +38,18 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, TemporaryDelive int deliveryFee = orderableShop.calculateDeliveryFee(totalProductPrice); int finalAmount = totalProductPrice + deliveryFee; - validateDeliveryPrice(request, totalProductPrice, deliveryFee, finalAmount); + deliveryPaymentInfo.validatePrice(totalProductPrice, deliveryFee, finalAmount); String pgOrderId = paymentGatewayService.generatePgOrderId(); TemporaryPayment deliveryEntity = TemporaryPayment.toDeliveryEntity( pgOrderId, user.getId(), orderableShop.getId(), - request.phoneNumber(), - request.address(), - request.toOwner(), - request.toRider(), - request.provideCutlery(), + deliveryPaymentInfo.phoneNumber(), + deliveryPaymentInfo.address(), + deliveryPaymentInfo.toOwner(), + deliveryPaymentInfo.toRider(), + deliveryPaymentInfo.provideCutlery(), totalProductPrice, deliveryFee, finalAmount, @@ -62,7 +61,7 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, TemporaryDelive } @Transactional - public TemporaryPaymentResponse createTakeoutPayment(User user, TemporaryTakeoutPaymentSaveRequest request) { + public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentInfo takeoutPaymentInfo) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); @@ -70,16 +69,16 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TemporaryTakeout int totalProductPrice = cart.calculateItemsAmount(); int finalAmount = totalProductPrice; - validateTakeoutPrice(request, totalProductPrice, finalAmount); + takeoutPaymentInfo.validatePrice(totalProductPrice, finalAmount); String pgOrderId = paymentGatewayService.generatePgOrderId(); TemporaryPayment takeoutEntity = TemporaryPayment.toTakeOutEntity( pgOrderId, user.getId(), orderableShop.getId(), - request.phoneNumber(), - request.toOwner(), - request.provideCutlery(), + takeoutPaymentInfo.phoneNumber(), + takeoutPaymentInfo.toOwner(), + takeoutPaymentInfo.provideCutlery(), totalProductPrice, finalAmount, temporaryMenuItems @@ -88,28 +87,4 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TemporaryTakeout temporaryPaymentRedisRepository.save(takeoutEntity); return TemporaryPaymentResponse.of(pgOrderId); } - - private void validateDeliveryPrice( - TemporaryDeliveryPaymentSaveRequest request, int totalProductPrice, int deliveryFee, int finalAmount - ) { - if (!request.totalMenuPrice().equals(totalProductPrice) - || !request.deliveryTip().equals(deliveryFee) - || !request.totalAmount().equals(finalAmount) - ) { - throw OrderPriceMismatchException.withDetail( - "totalProductPrice : " + totalProductPrice + "deliveryFee : " + deliveryFee + "totalAmount : " - + totalProductPrice + "finalAmount : " + finalAmount); - } - } - - private void validateTakeoutPrice( - TemporaryTakeoutPaymentSaveRequest request, int totalProductPrice, int finalAmount - ) { - if (!request.totalMenuPrice().equals(totalProductPrice) - || !request.totalAmount().equals(finalAmount) - ) { - throw OrderPriceMismatchException.withDetail( - "totalProductPrice : " + totalProductPrice + "finalAmount : " + finalAmount); - } - } } diff --git a/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java b/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java new file mode 100644 index 0000000..ac0e504 --- /dev/null +++ b/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java @@ -0,0 +1,20 @@ +package in.koreatech.payment.service; + +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.koin.domain.user.repository.UserRepository; +import in.koreatech.payment.common.auth.JwtProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserAuthenticationService { + + private final JwtProvider jwtProvider; + private final UserRepository userRepository; + + public User authenticateUser(String accessToken) { + Integer userId = jwtProvider.getUserId(accessToken); + return userRepository.getById(userId); + } +} From 5ed16d416c1b3050496c433e7a23191a32598225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 20:49:25 +0900 Subject: [PATCH 18/29] =?UTF-8?q?chore:=20PaymentGateway=20dto=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/gateway/pg/PaymentGatewayService.java | 8 ++++---- ...onse.java => PaymentGatewayCancelResponse.java} | 2 +- ...nse.java => PaymentGatewayConfirmResponse.java} | 2 +- .../gateway/toss/TossPaymentGatewayService.java | 14 +++++++------- .../payment/mapper/PaymentCancelMapper.java | 8 ++++---- .../in/koreatech/payment/mapper/PaymentMapper.java | 4 ++-- .../payment/service/PaymentCancelService.java | 4 ++-- .../payment/service/PaymentConfirmService.java | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) rename src/main/java/in/koreatech/payment/gateway/pg/dto/{PgPaymentCancelResponse.java => PaymentGatewayCancelResponse.java} (88%) rename src/main/java/in/koreatech/payment/gateway/pg/dto/{PgPaymentConfirmResponse.java => PaymentGatewayConfirmResponse.java} (82%) diff --git a/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java index e1f50d2..b7789a6 100644 --- a/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java +++ b/src/main/java/in/koreatech/payment/gateway/pg/PaymentGatewayService.java @@ -1,10 +1,10 @@ package in.koreatech.payment.gateway.pg; -import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; -import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayConfirmResponse; public interface PaymentGatewayService { - PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount); - PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey); + PaymentGatewayConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount); + PaymentGatewayCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey); String generatePgOrderId(); } diff --git a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java b/src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayCancelResponse.java similarity index 88% rename from src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java rename to src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayCancelResponse.java index b7c1b56..918008f 100644 --- a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentCancelResponse.java +++ b/src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayCancelResponse.java @@ -2,7 +2,7 @@ import java.util.List; -public record PgPaymentCancelResponse( +public record PaymentGatewayCancelResponse( String paymentKey, String orderId, String status, diff --git a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayConfirmResponse.java similarity index 82% rename from src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java rename to src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayConfirmResponse.java index 23f5b6f..1cd934b 100644 --- a/src/main/java/in/koreatech/payment/gateway/pg/dto/PgPaymentConfirmResponse.java +++ b/src/main/java/in/koreatech/payment/gateway/pg/dto/PaymentGatewayConfirmResponse.java @@ -1,6 +1,6 @@ package in.koreatech.payment.gateway.pg.dto; -public record PgPaymentConfirmResponse( +public record PaymentGatewayConfirmResponse( String paymentKey, Integer totalAmount, String orderId, diff --git a/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java index ebb284f..31b0690 100644 --- a/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java +++ b/src/main/java/in/koreatech/payment/gateway/toss/TossPaymentGatewayService.java @@ -1,13 +1,13 @@ package in.koreatech.payment.gateway.toss; -import static in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse.CancelInfo; +import static in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse.CancelInfo; import org.springframework.stereotype.Service; import in.koreatech.payment.gateway.pg.PaymentGatewayService; import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; -import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; -import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayConfirmResponse; import in.koreatech.payment.gateway.toss.dto.response.TossPaymentCancelResponse; import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; import lombok.RequiredArgsConstructor; @@ -19,11 +19,11 @@ public class TossPaymentGatewayService implements PaymentGatewayService { private final TossPaymentClient tossPaymentClient; private final PgOrderIdGenerator pgOrderIdGenerator; - public PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount) { + public PaymentGatewayConfirmResponse confirmPayment(String paymentKey, String pgOrderId, Integer amount) { TossPaymentConfirmResponse tossPaymentConfirmResponse = tossPaymentClient.requestConfirm(paymentKey, pgOrderId, amount); - return new PgPaymentConfirmResponse( + return new PaymentGatewayConfirmResponse( tossPaymentConfirmResponse.paymentKey(), tossPaymentConfirmResponse.totalAmount(), tossPaymentConfirmResponse.orderId(), @@ -34,10 +34,10 @@ public PgPaymentConfirmResponse confirmPayment(String paymentKey, String pgOrder ); } - public PgPaymentCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey) { + public PaymentGatewayCancelResponse cancelPayment(String paymentKey, String cancelReason, String idempotencyKey) { TossPaymentCancelResponse tossPaymentCancelResponse = tossPaymentClient.requestCancel(paymentKey, cancelReason, idempotencyKey); - return new PgPaymentCancelResponse( + return new PaymentGatewayCancelResponse( tossPaymentCancelResponse.paymentKey(), tossPaymentCancelResponse.orderId(), tossPaymentCancelResponse.status(), diff --git a/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java index 327ba6c..2849a0e 100644 --- a/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java +++ b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java @@ -9,16 +9,16 @@ import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse; @Component public class PaymentCancelMapper { - public List toEntity(Payment payment, PgPaymentCancelResponse pgPaymentCancelResponse) { + public List toEntity(Payment payment, PaymentGatewayCancelResponse paymentGatewayCancelResponse) { List paymentCancels = new ArrayList<>(); - List cancels = pgPaymentCancelResponse.cancels(); + List cancels = paymentGatewayCancelResponse.cancels(); - for (PgPaymentCancelResponse.CancelInfo cancelInfo : cancels) { + for (PaymentGatewayCancelResponse.CancelInfo cancelInfo : cancels) { OffsetDateTime cancelOffsetDateTime = OffsetDateTime.parse(cancelInfo.canceledAt()); LocalDateTime canceled = cancelOffsetDateTime.toLocalDateTime(); diff --git a/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java index 7d231d0..f443e49 100644 --- a/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java +++ b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java @@ -9,12 +9,12 @@ import in.koreatech.koin.domain.order.model.Payment; import in.koreatech.koin.domain.order.model.PaymentMethod; import in.koreatech.koin.domain.order.model.PaymentStatus; -import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayConfirmResponse; @Component public class PaymentMapper { - public Payment toEntity(Order order, PgPaymentConfirmResponse response) { + public Payment toEntity(Order order, PaymentGatewayConfirmResponse response) { OffsetDateTime requestedOffsetDateTime = OffsetDateTime.parse(response.requestedAt()); OffsetDateTime approvedOffsetDateTime = OffsetDateTime.parse(response.approvedAt()); diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java index 7ec70ad..0ddb19f 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -15,7 +15,7 @@ import in.koreatech.payment.exception.PaymentAlreadyCanceledException; import in.koreatech.payment.exception.PaymentCancelException; import in.koreatech.payment.gateway.pg.PaymentGatewayService; -import in.koreatech.payment.gateway.pg.dto.PgPaymentCancelResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse; import in.koreatech.payment.mapper.PaymentCancelMapper; import in.koreatech.payment.model.domain.PaymentCancelInfo; import lombok.RequiredArgsConstructor; @@ -38,7 +38,7 @@ public PaymentCancelResponse cancelPayment(User user, Integer paymentId, Payment payment.validateUserIdMatches(user.getId()); String paymentIdempotencyKey = paymentIdempotencyKeyService.getOrCreate(user.getId()); - PgPaymentCancelResponse pgResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), paymentCancelInfo.cancelReason(), paymentIdempotencyKey); + PaymentGatewayCancelResponse pgResponse = paymentGatewayService.cancelPayment(payment.getPaymentKey(), paymentCancelInfo.cancelReason(), paymentIdempotencyKey); validatePaymentIsCanceled(pgResponse.status()); payment.cancel(); diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index dd1a042..fde23ae 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -19,7 +19,7 @@ import in.koreatech.payment.dto.response.PaymentConfirmResponse; import in.koreatech.payment.exception.PaymentConfirmException; import in.koreatech.payment.gateway.pg.PaymentGatewayService; -import in.koreatech.payment.gateway.pg.dto.PgPaymentConfirmResponse; +import in.koreatech.payment.gateway.pg.dto.PaymentGatewayConfirmResponse; import in.koreatech.payment.mapper.PaymentMapper; import in.koreatech.payment.model.domain.PaymentConfirmInfo; import in.koreatech.payment.model.redis.TemporaryPayment; @@ -45,7 +45,7 @@ public PaymentConfirmResponse confirmPayment(User user, PaymentConfirmInfo payme TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(paymentConfirmInfo.orderId()); temporaryPayment.validateMatches(paymentConfirmInfo.orderId(), user.getId(), paymentConfirmInfo.amount()); - PgPaymentConfirmResponse pgResponse = paymentGatewayService.confirmPayment(paymentConfirmInfo.paymentKey(), + PaymentGatewayConfirmResponse pgResponse = paymentGatewayService.confirmPayment(paymentConfirmInfo.paymentKey(), paymentConfirmInfo.orderId(), paymentConfirmInfo.amount()); validatePaymentStatus(pgResponse.status()); From 386f6a88ae32271032f02e0036c0c07f1ba67ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 20:54:58 +0900 Subject: [PATCH 19/29] =?UTF-8?q?fix:=20=EA=B8=B0=EC=A1=B4=20PgOrderIdGene?= =?UTF-8?q?rator=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/in/koreatech/payment/util/PgOrderIdGenerator.java | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java diff --git a/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java b/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java deleted file mode 100644 index 9b02c7b..0000000 --- a/src/main/java/in/koreatech/payment/util/PgOrderIdGenerator.java +++ /dev/null @@ -1,5 +0,0 @@ -package in.koreatech.payment.util; - -public interface PgOrderIdGenerator { - String generatePgOrderId(); -} From 0519681d7d7f8a93c4899f0cdd9753bb40a8ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 20:57:34 +0900 Subject: [PATCH 20/29] =?UTF-8?q?refactor:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EA=B2=B0=EC=A0=9C=20=EC=A0=95=EB=B3=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TemporaryPaymentService.java | 45 ++++++++++++++-- .../util/TemporaryMenuItemConverter.java | 52 ------------------- 2 files changed, 42 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/util/TemporaryMenuItemConverter.java diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index d2db23c..925339b 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -6,7 +6,11 @@ import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.order.cart.model.Cart; +import in.koreatech.koin.domain.order.cart.model.CartMenuItem; +import in.koreatech.koin.domain.order.cart.model.CartMenuItemOption; import in.koreatech.koin.domain.order.cart.repository.CartRepository; +import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption; +import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; @@ -14,9 +18,10 @@ import in.koreatech.payment.model.domain.DeliveryPaymentInfo; import in.koreatech.payment.model.domain.TakeoutPaymentInfo; import in.koreatech.payment.model.domain.TemporaryMenuItems; +import in.koreatech.payment.model.domain.TemporaryMenuOption; +import in.koreatech.payment.model.domain.TemporaryMenuPrice; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import in.koreatech.payment.util.TemporaryMenuItemConverter; import lombok.RequiredArgsConstructor; @Service @@ -33,7 +38,7 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, DeliveryPayment Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); + List temporaryMenuItems = createTemporaryMenuItemsFrom(cart); int totalProductPrice = cart.calculateItemsAmount(); int deliveryFee = orderableShop.calculateDeliveryFee(totalProductPrice); int finalAmount = totalProductPrice + deliveryFee; @@ -65,7 +70,7 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentIn Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = TemporaryMenuItemConverter.fromCart(cart); + List temporaryMenuItems = createTemporaryMenuItemsFrom(cart); int totalProductPrice = cart.calculateItemsAmount(); int finalAmount = totalProductPrice; @@ -87,4 +92,38 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentIn temporaryPaymentRedisRepository.save(takeoutEntity); return TemporaryPaymentResponse.of(pgOrderId); } + + public List createTemporaryMenuItemsFrom(Cart cart) { + return cart.getCartMenuItems().stream() + .map(this::fromCartMenuItem) + .toList(); + } + + private TemporaryMenuItems fromCartMenuItem(CartMenuItem cartMenuItem) { + List options = cartMenuItem.getCartMenuItemOptions().stream() + .map(this::fromCartMenuItemOption) + .toList(); + + OrderableShopMenuPrice price = cartMenuItem.getOrderableShopMenuPrice(); + + return new TemporaryMenuItems( + cartMenuItem.getOrderableShopMenu().getName(), + cartMenuItem.getQuantity(), + cartMenuItem.calculateTotalAmount(), + new TemporaryMenuPrice(price.getName(), price.getPrice()), + options + ); + } + + private TemporaryMenuOption fromCartMenuItemOption(CartMenuItemOption option) { + OrderableShopMenuOption shopOption = option.getOrderableShopMenuOption(); + String optionGroupName = shopOption.getOptionGroup().getName(); + + return new TemporaryMenuOption( + optionGroupName, + option.getOptionName(), + option.getQuantity(), + option.getOptionPrice() + ); + } } diff --git a/src/main/java/in/koreatech/payment/util/TemporaryMenuItemConverter.java b/src/main/java/in/koreatech/payment/util/TemporaryMenuItemConverter.java deleted file mode 100644 index e1830f6..0000000 --- a/src/main/java/in/koreatech/payment/util/TemporaryMenuItemConverter.java +++ /dev/null @@ -1,52 +0,0 @@ -package in.koreatech.payment.util; - -import java.util.List; - -import in.koreatech.koin.domain.order.cart.model.Cart; -import in.koreatech.koin.domain.order.cart.model.CartMenuItem; -import in.koreatech.koin.domain.order.cart.model.CartMenuItemOption; -import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption; -import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice; -import in.koreatech.payment.model.domain.TemporaryMenuItems; -import in.koreatech.payment.model.domain.TemporaryMenuOption; -import in.koreatech.payment.model.domain.TemporaryMenuPrice; - -public class TemporaryMenuItemConverter { - - private TemporaryMenuItemConverter() { - } - - public static List fromCart(Cart cart) { - return cart.getCartMenuItems().stream() - .map(TemporaryMenuItemConverter::fromCartMenuItem) - .toList(); - } - - public static TemporaryMenuItems fromCartMenuItem(CartMenuItem cartMenuItem) { - List options = cartMenuItem.getCartMenuItemOptions().stream() - .map(TemporaryMenuItemConverter::fromCartMenuItemOption) - .toList(); - - OrderableShopMenuPrice price = cartMenuItem.getOrderableShopMenuPrice(); - - return new TemporaryMenuItems( - cartMenuItem.getOrderableShopMenu().getName(), - cartMenuItem.getQuantity(), - cartMenuItem.calculateTotalAmount(), - new TemporaryMenuPrice(price.getName(), price.getPrice()), - options - ); - } - - private static TemporaryMenuOption fromCartMenuItemOption(CartMenuItemOption option) { - OrderableShopMenuOption shopOption = option.getOrderableShopMenuOption(); - String optionGroupName = shopOption.getOptionGroup().getName(); - - return new TemporaryMenuOption( - optionGroupName, - option.getOptionName(), - option.getQuantity(), - option.getOptionPrice() - ); - } -} From 856fc8ea5a1c515c42ceef340a222c906488dab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:01:48 +0900 Subject: [PATCH 21/29] =?UTF-8?q?feat:=20TemporaryMenuItemsMapper=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/TemporaryMenuItemsMapper.java | 52 +++++++++++++++++++ .../service/TemporaryPaymentService.java | 46 ++-------------- 2 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 src/main/java/in/koreatech/payment/mapper/TemporaryMenuItemsMapper.java diff --git a/src/main/java/in/koreatech/payment/mapper/TemporaryMenuItemsMapper.java b/src/main/java/in/koreatech/payment/mapper/TemporaryMenuItemsMapper.java new file mode 100644 index 0000000..1d898ef --- /dev/null +++ b/src/main/java/in/koreatech/payment/mapper/TemporaryMenuItemsMapper.java @@ -0,0 +1,52 @@ +package in.koreatech.payment.mapper; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.order.cart.model.Cart; +import in.koreatech.koin.domain.order.cart.model.CartMenuItem; +import in.koreatech.koin.domain.order.cart.model.CartMenuItemOption; +import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption; +import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice; +import in.koreatech.payment.model.domain.TemporaryMenuItems; +import in.koreatech.payment.model.domain.TemporaryMenuOption; +import in.koreatech.payment.model.domain.TemporaryMenuPrice; + +@Component +public class TemporaryMenuItemsMapper { + + public List fromCart(Cart cart) { + return cart.getCartMenuItems().stream() + .map(this::fromCartMenuItem) + .toList(); + } + + private TemporaryMenuItems fromCartMenuItem(CartMenuItem cartMenuItem) { + List options = cartMenuItem.getCartMenuItemOptions().stream() + .map(this::fromCartMenuItemOption) + .toList(); + + OrderableShopMenuPrice price = cartMenuItem.getOrderableShopMenuPrice(); + + return new TemporaryMenuItems( + cartMenuItem.getOrderableShopMenu().getName(), + cartMenuItem.getQuantity(), + cartMenuItem.calculateTotalAmount(), + new TemporaryMenuPrice(price.getName(), price.getPrice()), + options + ); + } + + private TemporaryMenuOption fromCartMenuItemOption(CartMenuItemOption option) { + OrderableShopMenuOption shopOption = option.getOrderableShopMenuOption(); + String optionGroupName = shopOption.getOptionGroup().getName(); + + return new TemporaryMenuOption( + optionGroupName, + option.getOptionName(), + option.getQuantity(), + option.getOptionPrice() + ); + } +} diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index 925339b..64224a7 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -6,20 +6,15 @@ import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.order.cart.model.Cart; -import in.koreatech.koin.domain.order.cart.model.CartMenuItem; -import in.koreatech.koin.domain.order.cart.model.CartMenuItemOption; import in.koreatech.koin.domain.order.cart.repository.CartRepository; -import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuOption; -import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.dto.response.TemporaryPaymentResponse; import in.koreatech.payment.gateway.pg.PaymentGatewayService; +import in.koreatech.payment.mapper.TemporaryMenuItemsMapper; import in.koreatech.payment.model.domain.DeliveryPaymentInfo; import in.koreatech.payment.model.domain.TakeoutPaymentInfo; import in.koreatech.payment.model.domain.TemporaryMenuItems; -import in.koreatech.payment.model.domain.TemporaryMenuOption; -import in.koreatech.payment.model.domain.TemporaryMenuPrice; import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import lombok.RequiredArgsConstructor; @@ -32,13 +27,14 @@ public class TemporaryPaymentService { private final CartRepository cartRepository; private final PaymentGatewayService paymentGatewayService; private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; + private final TemporaryMenuItemsMapper temporaryMenuItemsMapper; @Transactional public TemporaryPaymentResponse createDeliveryPayment(User user, DeliveryPaymentInfo deliveryPaymentInfo) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = createTemporaryMenuItemsFrom(cart); + List temporaryMenuItems = temporaryMenuItemsMapper.fromCart(cart); int totalProductPrice = cart.calculateItemsAmount(); int deliveryFee = orderableShop.calculateDeliveryFee(totalProductPrice); int finalAmount = totalProductPrice + deliveryFee; @@ -70,7 +66,7 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentIn Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); - List temporaryMenuItems = createTemporaryMenuItemsFrom(cart); + List temporaryMenuItems = temporaryMenuItemsMapper.fromCart(cart); int totalProductPrice = cart.calculateItemsAmount(); int finalAmount = totalProductPrice; @@ -92,38 +88,4 @@ public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentIn temporaryPaymentRedisRepository.save(takeoutEntity); return TemporaryPaymentResponse.of(pgOrderId); } - - public List createTemporaryMenuItemsFrom(Cart cart) { - return cart.getCartMenuItems().stream() - .map(this::fromCartMenuItem) - .toList(); - } - - private TemporaryMenuItems fromCartMenuItem(CartMenuItem cartMenuItem) { - List options = cartMenuItem.getCartMenuItemOptions().stream() - .map(this::fromCartMenuItemOption) - .toList(); - - OrderableShopMenuPrice price = cartMenuItem.getOrderableShopMenuPrice(); - - return new TemporaryMenuItems( - cartMenuItem.getOrderableShopMenu().getName(), - cartMenuItem.getQuantity(), - cartMenuItem.calculateTotalAmount(), - new TemporaryMenuPrice(price.getName(), price.getPrice()), - options - ); - } - - private TemporaryMenuOption fromCartMenuItemOption(CartMenuItemOption option) { - OrderableShopMenuOption shopOption = option.getOrderableShopMenuOption(); - String optionGroupName = shopOption.getOptionGroup().getName(); - - return new TemporaryMenuOption( - optionGroupName, - option.getOptionName(), - option.getQuantity(), - option.getOptionPrice() - ); - } } From b6a999b481ad6f601469854e70e028c84b8a5b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:04:13 +0900 Subject: [PATCH 22/29] =?UTF-8?q?fix:=20=EA=B2=B0=EC=A0=9C=20=EB=A1=A4?= =?UTF-8?q?=EB=B0=B1=20=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../event/TossPaymentRollBackEvent.java | 14 ---- .../service/PaymentRollBackService.java | 82 ------------------- .../acceptance/domain/PaymentApiTest.java | 4 - 3 files changed, 100 deletions(-) delete mode 100644 src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java delete mode 100644 src/main/java/in/koreatech/payment/service/PaymentRollBackService.java diff --git a/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java b/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java deleted file mode 100644 index 822d648..0000000 --- a/src/main/java/in/koreatech/payment/event/TossPaymentRollBackEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -package in.koreatech.payment.event; - -import in.koreatech.payment.gateway.toss.dto.response.TossPaymentConfirmResponse; -import in.koreatech.payment.model.redis.TemporaryPayment; - -public record TossPaymentRollBackEvent( - String paymentKey, - TemporaryPayment temporaryPayment, - TossPaymentConfirmResponse tossPaymentConfirmResponse -) { - public static TossPaymentRollBackEvent from(String paymentKey, TemporaryPayment temporaryPayment, TossPaymentConfirmResponse tossPaymentConfirmResponse) { - return new TossPaymentRollBackEvent(paymentKey, temporaryPayment, tossPaymentConfirmResponse); - } -} diff --git a/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java b/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java deleted file mode 100644 index 18090ae..0000000 --- a/src/main/java/in/koreatech/payment/service/PaymentRollBackService.java +++ /dev/null @@ -1,82 +0,0 @@ -package in.koreatech.payment.service; - -import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; -import static org.springframework.transaction.event.TransactionPhase.AFTER_ROLLBACK; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.event.TransactionalEventListener; - -import in.koreatech.koin.domain.order.cart.repository.CartRepository; -import in.koreatech.koin.domain.order.repository.OrderRepository; -import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; -import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; -import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; -import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.payment.gateway.toss.TossPaymentClient; -import in.koreatech.payment.event.TossPaymentRollBackEvent; -import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Service -@RequiredArgsConstructor -public class PaymentRollBackService { - - private final TossPaymentClient tossPaymentClient; - private final PaymentIdempotencyKeyRepository paymentIdempotencyKeyRepository; - private final UserRepository userRepository; - private final OrderableShopRepository orderableShopRepository; - private final OrderRepository orderRepository; - private final PaymentRepository paymentRepository; - private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; - private final CartRepository cartRepository; - private final PaymentCancelRepository paymentCancelRepository; - - private static final String PAYMENT_CANCEL_REASON = "코인 서버 오류로 인한 결제 취소"; - - @TransactionalEventListener(phase = AFTER_ROLLBACK) - @Transactional(propagation = REQUIRES_NEW) - public void paymentRollback(TossPaymentRollBackEvent event) { - // TemporaryPayment temporaryPayment = event.temporaryPayment(); - // User user = userRepository.getById(temporaryPayment.getUserId()); - // PaymentIdempotencyKey paymentIdempotencyKey = paymentIdempotencyKeyRepository - // .findByUserId(user.getId()) - // .map(idempotencyKey -> { - // if (idempotencyKey.isOlderThanExpireDays()) { - // idempotencyKey.updateIdempotencyKey(UUID.randomUUID().toString()); - // } - // return idempotencyKey; - // }) - // .orElseGet(() -> paymentIdempotencyKeyRepository.save( - // PaymentIdempotencyKey.builder() - // .userId(user.getId()) - // .idempotencyKey(UUID.randomUUID().toString()) - // .build() - // )); - // - // PaymentCancelResponse response = tossPaymentClient.requestCancel(event.paymentKey(), - // PAYMENT_CANCEL_REASON, paymentIdempotencyKey.getIdempotencyKey()); - // - // try { - // OrderableShop orderableShop = orderableShopRepository.getById(temporaryPayment.getOrderableShopId()); - // Order order = temporaryPayment.toOrder(user, orderableShop); - // orderRepository.save(order); - // - // Payment payment = event.tossPaymentConfirmResponse().toEntity(order); - // payment.cancel(); - // paymentRepository.save(payment); - // - // List paymentCancels = response.getPaymentCancels(payment); - // paymentCancelRepository.saveAll(paymentCancels); - // - // temporaryPaymentRedisRepository.deleteById(order.getPgOrderId()); - // cartRepository.deleteByUserId(user.getId()); - // } catch (Exception e) { - // log.error("결제 취소 과정에서 오류 발생 - paymentId: {}, userId: {}, orderId: {}", event.paymentKey(), - // temporaryPayment.getUserId(), temporaryPayment.getPgOrderId()); - // } - } -} diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index a01cf5e..a8db85a 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -54,7 +54,6 @@ import in.koreatech.payment.model.redis.TemporaryPayment; import in.koreatech.payment.repository.redis.TemporaryPaymentRedisRepository; import in.koreatech.payment.gateway.pg.PgOrderIdGenerator; -import in.koreatech.payment.service.PaymentRollBackService; public class PaymentApiTest extends AcceptanceTest { @@ -97,9 +96,6 @@ public class PaymentApiTest extends AcceptanceTest { @MockBean private TossPaymentClient tossPaymentClient; - @MockBean - private PaymentRollBackService paymentRollBackService; - @MockBean private PgOrderIdGenerator pgOrderIdGenerator; From ee2234e42afdadb7d1dbb09ad6d305a40557e8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:12:50 +0900 Subject: [PATCH 23/29] =?UTF-8?q?fix:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/payment/service/PaymentCancelService.java | 1 - .../in/koreatech/payment/service/PaymentConfirmService.java | 1 - .../java/in/koreatech/payment/service/PaymentService.java | 6 +----- .../koreatech/payment/service/TemporaryPaymentService.java | 1 - 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java index 0ddb19f..9b83ee7 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -22,7 +22,6 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class PaymentCancelService { private final PaymentRepository paymentRepository; diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index fde23ae..ce557f7 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -28,7 +28,6 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class PaymentConfirmService { private final PaymentGatewayService paymentGatewayService; diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index cd6592b..a843e32 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -20,7 +20,6 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class PaymentService { private final UserAuthenticationService userAuthenticationService; @@ -29,7 +28,6 @@ public class PaymentService { private final PaymentCancelService paymentCancelService; private final PaymentQueryService paymentQueryService; - @Transactional public TemporaryPaymentResponse createTemporaryDeliveryPayment( String accessToken, TemporaryDeliveryPaymentSaveRequest request ) { @@ -47,7 +45,6 @@ public TemporaryPaymentResponse createTemporaryDeliveryPayment( return temporaryPaymentService.createDeliveryPayment(user, deliveryPaymentInfo); } - @Transactional public TemporaryPaymentResponse createTemporaryTakeoutPayment( String accessToken, TemporaryTakeoutPaymentSaveRequest request ) { @@ -62,7 +59,6 @@ public TemporaryPaymentResponse createTemporaryTakeoutPayment( return temporaryPaymentService.createTakeoutPayment(user, takeoutPaymentInfo); } - @Transactional public PaymentConfirmResponse confirmPayment(String accessToken, PaymentConfirmRequest request) { User user = userAuthenticationService.authenticateUser(accessToken); PaymentConfirmInfo paymentConfirmInfo = PaymentConfirmInfo.of( @@ -73,13 +69,13 @@ public PaymentConfirmResponse confirmPayment(String accessToken, PaymentConfirmR return paymentConfirmService.confirmPayment(user, paymentConfirmInfo); } - @Transactional public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId, PaymentCancelRequest request) { User user = userAuthenticationService.authenticateUser(accessToken); PaymentCancelInfo paymentCancelInfo = PaymentCancelInfo.of(request.cancelReason()); return paymentCancelService.cancelPayment(user, paymentId, paymentCancelInfo); } + @Transactional(readOnly = true) public PaymentResponse getPayment(String accessToken, Integer paymentId) { User user = userAuthenticationService.authenticateUser(accessToken); return paymentQueryService.getPayment(user, paymentId); diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index 64224a7..7c8b663 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -21,7 +21,6 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class TemporaryPaymentService { private final CartRepository cartRepository; From 9878f8bcff6c3717e6c69d4d6a0e6c844fa0c8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:20:38 +0900 Subject: [PATCH 24/29] =?UTF-8?q?feat:=20=EB=A9=80=ED=8B=B0=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=86=8C=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/datasource/KoinDBProperties.java | 13 ++++ .../datasource/KoinDataSourceConfig.java | 67 ++++++++++++++++++ .../datasource/KoinPaymentDBProperties.java | 13 ++++ .../KoinPaymentDataSourceConfig.java | 70 +++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 src/main/java/in/koreatech/payment/common/config/datasource/KoinDBProperties.java create mode 100644 src/main/java/in/koreatech/payment/common/config/datasource/KoinDataSourceConfig.java create mode 100644 src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDBProperties.java create mode 100644 src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDataSourceConfig.java diff --git a/src/main/java/in/koreatech/payment/common/config/datasource/KoinDBProperties.java b/src/main/java/in/koreatech/payment/common/config/datasource/KoinDBProperties.java new file mode 100644 index 0000000..00246f4 --- /dev/null +++ b/src/main/java/in/koreatech/payment/common/config/datasource/KoinDBProperties.java @@ -0,0 +1,13 @@ +package in.koreatech.payment.common.config.datasource; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "spring.datasource.koin.hibernate") +public record KoinDBProperties( + String ddlAuto, + Boolean showSql, + String packagesToScan, + String formatSql +) { + +} diff --git a/src/main/java/in/koreatech/payment/common/config/datasource/KoinDataSourceConfig.java b/src/main/java/in/koreatech/payment/common/config/datasource/KoinDataSourceConfig.java new file mode 100644 index 0000000..dce81ad --- /dev/null +++ b/src/main/java/in/koreatech/payment/common/config/datasource/KoinDataSourceConfig.java @@ -0,0 +1,67 @@ +package in.koreatech.payment.common.config.datasource; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import jakarta.persistence.EntityManagerFactory; +import lombok.RequiredArgsConstructor; + +@Configuration +@RequiredArgsConstructor +@EnableTransactionManagement +@EnableJpaRepositories( + basePackages = "in.koreatech.koin", + entityManagerFactoryRef = "koinEntityManagerFactory", + transactionManagerRef = "koinTransactionManager" +) +public class KoinDataSourceConfig { + + private final KoinDBProperties koinDBProperties; + + @Bean(name = "koinDataSource") + @ConfigurationProperties("spring.datasource.koin") + public DataSource koinDataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "koinEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean koinEntityManagerFactory( + @Qualifier(value = "koinDataSource") DataSource dataSource + ) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan(koinDBProperties.packagesToScan()); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaPropertyMap(createJpaVendorProperties()); + return em; + } + + private Map createJpaVendorProperties() { + Map properties = new HashMap<>(); + properties.put("hibernate.show_sql", koinDBProperties.showSql()); + properties.put("hibernate.hbm2ddl.auto", koinDBProperties.ddlAuto()); + properties.put("hibernate.format_sql", koinDBProperties.formatSql()); + return properties; + } + + @Bean(name = "koinTransactionManager") + public PlatformTransactionManager koinTransactionManager( + @Qualifier(value = "koinEntityManagerFactory") EntityManagerFactory entityManagerFactory + ) { + return new JpaTransactionManager(entityManagerFactory); + } +} diff --git a/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDBProperties.java b/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDBProperties.java new file mode 100644 index 0000000..2e8a04b --- /dev/null +++ b/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDBProperties.java @@ -0,0 +1,13 @@ +package in.koreatech.payment.common.config.datasource; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "spring.datasource.koin-payment.hibernate") +public record KoinPaymentDBProperties( + String ddlAuto, + Boolean showSql, + String packagesToScan, + String formatSql +) { + +} diff --git a/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDataSourceConfig.java b/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDataSourceConfig.java new file mode 100644 index 0000000..a1180c0 --- /dev/null +++ b/src/main/java/in/koreatech/payment/common/config/datasource/KoinPaymentDataSourceConfig.java @@ -0,0 +1,70 @@ +package in.koreatech.payment.common.config.datasource; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import jakarta.persistence.EntityManagerFactory; +import lombok.RequiredArgsConstructor; + +@Configuration +@RequiredArgsConstructor +@EnableTransactionManagement +@EnableJpaRepositories( + basePackages = "in.koreatech.payment", + entityManagerFactoryRef = "koinPaymentEntityManagerFactory", + transactionManagerRef = "koinPaymentTransactionManager" +) +public class KoinPaymentDataSourceConfig { + + private final KoinPaymentDBProperties koinPaymentDBProperties; + + @Bean(name = "koinPaymentDataSource") + @ConfigurationProperties("spring.datasource.koin-payment") + public DataSource koinPaymentDataSource() { + return DataSourceBuilder.create().build(); + } + + @Primary + @Bean(name = "koinPaymentEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean koinPaymentEntityManagerFactory( + @Qualifier(value = "koinPaymentDataSource") DataSource dataSource + ) { + LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan(koinPaymentDBProperties.packagesToScan()); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaPropertyMap(createJpaVendorProperties()); + return em; + } + + private Map createJpaVendorProperties() { + Map properties = new HashMap<>(); + properties.put("hibernate.show_sql", koinPaymentDBProperties.showSql()); + properties.put("hibernate.hbm2ddl.auto", koinPaymentDBProperties.ddlAuto()); + properties.put("hibernate.format_sql", koinPaymentDBProperties.formatSql()); + return properties; + } + + @Primary + @Bean(name = "koinPaymentTransactionManager") + public PlatformTransactionManager koinPaymentTransactionManager( + @Qualifier(value = "koinPaymentEntityManagerFactory") EntityManagerFactory entityManagerFactory + ) { + return new JpaTransactionManager(entityManagerFactory); + } +} From 66904105f1e4f047348ef40797b1490cb80967ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:23:29 +0900 Subject: [PATCH 25/29] =?UTF-8?q?chore:=20=EA=B2=B0=EC=A0=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/PaymentCancelException.java | 22 ---------------- .../dto/response/PaymentCancelResponse.java | 2 +- .../dto/response/PaymentConfirmResponse.java | 16 ++++++------ .../payment/dto/response/PaymentResponse.java | 16 ++++++------ .../PaymentAccessDeniedException.java | 2 +- .../payment/mapper/PaymentCancelMapper.java | 4 +-- .../payment/mapper/PaymentMapper.java | 8 +++--- .../model/domain/TemporaryMenuItems.java | 6 ++--- .../model/domain/TemporaryMenuOption.java | 4 +-- .../model => payment/model/entity}/Order.java | 2 +- .../model/entity}/OrderDelivery.java | 2 +- .../model/entity}/OrderMenu.java | 2 +- .../model/entity}/OrderMenuOption.java | 2 +- .../model/entity}/OrderTakeout.java | 2 +- .../model/entity}/OrderType.java | 2 +- .../model/entity}/Payment.java | 6 ++--- .../model/entity}/PaymentCancel.java | 2 +- .../model/entity}/PaymentIdempotencyKey.java | 2 +- .../model/entity}/PaymentMethod.java | 2 +- .../model/entity}/PaymentStatus.java | 2 +- .../payment/model/redis/TemporaryPayment.java | 12 ++++----- .../mysql}/OrderDeliveryRepository.java | 4 +-- .../mysql}/OrderMenuOptionRepository.java | 4 +-- .../mysql}/OrderMenuRepository.java | 4 +-- .../repository/mysql}/OrderRepository.java | 4 +-- .../mysql}/OrderTakeoutRepository.java | 4 +-- .../mysql}/PaymentCancelRepository.java | 4 +-- .../PaymentIdempotencyKeyRepository.java | 4 +-- .../repository/mysql}/PaymentRepository.java | 4 +-- .../payment/service/PaymentCancelService.java | 10 +++---- .../service/PaymentConfirmService.java | 14 +++++----- .../service/PaymentIdempotencyKeyService.java | 4 +-- .../payment/service/PaymentQueryService.java | 10 +++---- .../acceptance/domain/PaymentApiTest.java | 26 +++++++++---------- .../fixture/PaymentIdempotencyKeyFixture.java | 4 +-- 35 files changed, 98 insertions(+), 120 deletions(-) delete mode 100644 src/main/java/in/koreatech/koin/domain/order/exception/PaymentCancelException.java rename src/main/java/in/koreatech/{koin/domain/order => payment}/exception/PaymentAccessDeniedException.java (93%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/Order.java (98%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/OrderDelivery.java (97%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/OrderMenu.java (97%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/OrderMenuOption.java (97%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/OrderTakeout.java (96%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/OrderType.java (81%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/Payment.java (93%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/PaymentCancel.java (97%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/PaymentIdempotencyKey.java (97%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/PaymentMethod.java (94%) rename src/main/java/in/koreatech/{koin/domain/order/model => payment/model/entity}/PaymentStatus.java (87%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/OrderDeliveryRepository.java (63%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/OrderMenuOptionRepository.java (65%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/OrderMenuRepository.java (71%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/OrderRepository.java (60%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/OrderTakeoutRepository.java (64%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/PaymentCancelRepository.java (72%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/PaymentIdempotencyKeyRepository.java (73%) rename src/main/java/in/koreatech/{koin/domain/order/repository => payment/repository/mysql}/PaymentRepository.java (87%) diff --git a/src/main/java/in/koreatech/koin/domain/order/exception/PaymentCancelException.java b/src/main/java/in/koreatech/koin/domain/order/exception/PaymentCancelException.java deleted file mode 100644 index 422cca8..0000000 --- a/src/main/java/in/koreatech/koin/domain/order/exception/PaymentCancelException.java +++ /dev/null @@ -1,22 +0,0 @@ -package in.koreatech.koin.domain.order.exception; - -import in.koreatech.payment.common.exception.custom.ExternalServiceException; -import in.koreatech.payment.exception.PaymentConfirmException; - -public class PaymentCancelException extends ExternalServiceException { - - private static final String DEFAULT_MESSAGE = "결제 취소 중 문제가 생겼습니다."; - private static final String ERROR_CODE = "PAYMENT_CANCEL_ERROR"; - - public PaymentCancelException(String message) { - super(message, ERROR_CODE); - } - - public PaymentCancelException(String message, String detail) { - super(message, detail, ERROR_CODE); - } - - public static PaymentConfirmException withDetail(String detail) { - return new PaymentConfirmException(DEFAULT_MESSAGE, detail); - } -} diff --git a/src/main/java/in/koreatech/payment/dto/response/PaymentCancelResponse.java b/src/main/java/in/koreatech/payment/dto/response/PaymentCancelResponse.java index eb3989c..84ad97d 100644 --- a/src/main/java/in/koreatech/payment/dto/response/PaymentCancelResponse.java +++ b/src/main/java/in/koreatech/payment/dto/response/PaymentCancelResponse.java @@ -10,7 +10,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.domain.order.model.PaymentCancel; +import in.koreatech.payment.model.entity.PaymentCancel; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(value = SnakeCaseStrategy.class) diff --git a/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java index c995b6a..32f2e87 100644 --- a/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java +++ b/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java @@ -1,8 +1,8 @@ package in.koreatech.payment.dto.response; import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import static in.koreatech.koin.domain.order.model.OrderType.DELIVERY; -import static in.koreatech.koin.domain.order.model.OrderType.TAKE_OUT; +import static in.koreatech.payment.model.entity.OrderType.DELIVERY; +import static in.koreatech.payment.model.entity.OrderType.TAKE_OUT; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @@ -13,12 +13,12 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderDelivery; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.OrderMenuOption; -import in.koreatech.koin.domain.order.model.OrderTakeout; -import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderDelivery; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.OrderMenuOption; +import in.koreatech.payment.model.entity.OrderTakeout; +import in.koreatech.payment.model.entity.Payment; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.shop.model.shop.Shop; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java b/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java index e68606d..be7a63c 100644 --- a/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java +++ b/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java @@ -1,8 +1,8 @@ package in.koreatech.payment.dto.response; import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import static in.koreatech.koin.domain.order.model.OrderType.DELIVERY; -import static in.koreatech.koin.domain.order.model.OrderType.TAKE_OUT; +import static in.koreatech.payment.model.entity.OrderType.DELIVERY; +import static in.koreatech.payment.model.entity.OrderType.TAKE_OUT; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @@ -13,12 +13,12 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderDelivery; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.OrderMenuOption; -import in.koreatech.koin.domain.order.model.OrderTakeout; -import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderDelivery; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.OrderMenuOption; +import in.koreatech.payment.model.entity.OrderTakeout; +import in.koreatech.payment.model.entity.Payment; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.shop.model.shop.Shop; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/in/koreatech/koin/domain/order/exception/PaymentAccessDeniedException.java b/src/main/java/in/koreatech/payment/exception/PaymentAccessDeniedException.java similarity index 93% rename from src/main/java/in/koreatech/koin/domain/order/exception/PaymentAccessDeniedException.java rename to src/main/java/in/koreatech/payment/exception/PaymentAccessDeniedException.java index 65ae02b..7a53ee9 100644 --- a/src/main/java/in/koreatech/koin/domain/order/exception/PaymentAccessDeniedException.java +++ b/src/main/java/in/koreatech/payment/exception/PaymentAccessDeniedException.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.exception; +package in.koreatech.payment.exception; import in.koreatech.payment.common.exception.custom.AuthorizationException; diff --git a/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java index 2849a0e..c3e1773 100644 --- a/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java +++ b/src/main/java/in/koreatech/payment/mapper/PaymentCancelMapper.java @@ -7,8 +7,8 @@ import org.springframework.stereotype.Component; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.model.entity.PaymentCancel; import in.koreatech.payment.gateway.pg.dto.PaymentGatewayCancelResponse; @Component diff --git a/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java index f443e49..6b87033 100644 --- a/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java +++ b/src/main/java/in/koreatech/payment/mapper/PaymentMapper.java @@ -5,10 +5,10 @@ import org.springframework.stereotype.Component; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentMethod; -import in.koreatech.koin.domain.order.model.PaymentStatus; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.model.entity.PaymentMethod; +import in.koreatech.payment.model.entity.PaymentStatus; import in.koreatech.payment.gateway.pg.dto.PaymentGatewayConfirmResponse; @Component diff --git a/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuItems.java b/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuItems.java index 3e427a3..9194c7a 100644 --- a/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuItems.java +++ b/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuItems.java @@ -2,9 +2,9 @@ import java.util.List; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.OrderMenuOption; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.OrderMenuOption; public record TemporaryMenuItems( String name, diff --git a/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuOption.java b/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuOption.java index 94f3ba8..6f8fca0 100644 --- a/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuOption.java +++ b/src/main/java/in/koreatech/payment/model/domain/TemporaryMenuOption.java @@ -1,7 +1,7 @@ package in.koreatech.payment.model.domain; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.OrderMenuOption; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.OrderMenuOption; public record TemporaryMenuOption( String optionGroupName, diff --git a/src/main/java/in/koreatech/koin/domain/order/model/Order.java b/src/main/java/in/koreatech/payment/model/entity/Order.java similarity index 98% rename from src/main/java/in/koreatech/koin/domain/order/model/Order.java rename to src/main/java/in/koreatech/payment/model/entity/Order.java index b101e95..7a7fb38 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/Order.java +++ b/src/main/java/in/koreatech/payment/model/entity/Order.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static jakarta.persistence.CascadeType.ALL; import static jakarta.persistence.EnumType.STRING; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java b/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java similarity index 97% rename from src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java rename to src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java index 2bbd29b..bce0534 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderDelivery.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static lombok.AccessLevel.PROTECTED; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderMenu.java b/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java similarity index 97% rename from src/main/java/in/koreatech/koin/domain/order/model/OrderMenu.java rename to src/main/java/in/koreatech/payment/model/entity/OrderMenu.java index 6033a2c..35ac4dd 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderMenu.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static jakarta.persistence.CascadeType.ALL; import static jakarta.persistence.FetchType.LAZY; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderMenuOption.java b/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java similarity index 97% rename from src/main/java/in/koreatech/koin/domain/order/model/OrderMenuOption.java rename to src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java index 733575e..8620793 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderMenuOption.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java b/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java similarity index 96% rename from src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java rename to src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java index 1f50b51..796fc44 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderTakeout.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static lombok.AccessLevel.PROTECTED; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/OrderType.java b/src/main/java/in/koreatech/payment/model/entity/OrderType.java similarity index 81% rename from src/main/java/in/koreatech/koin/domain/order/model/OrderType.java rename to src/main/java/in/koreatech/payment/model/entity/OrderType.java index e82a5e9..82c5c50 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/OrderType.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderType.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import lombok.Getter; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/Payment.java b/src/main/java/in/koreatech/payment/model/entity/Payment.java similarity index 93% rename from src/main/java/in/koreatech/koin/domain/order/model/Payment.java rename to src/main/java/in/koreatech/payment/model/entity/Payment.java index a4a0477..6e97f00 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/Payment.java +++ b/src/main/java/in/koreatech/payment/model/entity/Payment.java @@ -1,6 +1,6 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; -import static in.koreatech.koin.domain.order.model.PaymentStatus.CANCELED; +import static in.koreatech.payment.model.entity.PaymentStatus.CANCELED; import static jakarta.persistence.EnumType.STRING; import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; @@ -8,7 +8,7 @@ import java.time.LocalDateTime; -import in.koreatech.koin.domain.order.exception.PaymentAccessDeniedException; +import in.koreatech.payment.exception.PaymentAccessDeniedException; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Enumerated; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/PaymentCancel.java b/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java similarity index 97% rename from src/main/java/in/koreatech/koin/domain/order/model/PaymentCancel.java rename to src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java index a81f8ed..73687ce 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/PaymentCancel.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/PaymentIdempotencyKey.java b/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java similarity index 97% rename from src/main/java/in/koreatech/koin/domain/order/model/PaymentIdempotencyKey.java rename to src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java index 4e5bf64..5b4963a 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/PaymentIdempotencyKey.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/PaymentMethod.java b/src/main/java/in/koreatech/payment/model/entity/PaymentMethod.java similarity index 94% rename from src/main/java/in/koreatech/koin/domain/order/model/PaymentMethod.java rename to src/main/java/in/koreatech/payment/model/entity/PaymentMethod.java index 65bcfbd..1f413b1 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/PaymentMethod.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentMethod.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import java.util.Arrays; diff --git a/src/main/java/in/koreatech/koin/domain/order/model/PaymentStatus.java b/src/main/java/in/koreatech/payment/model/entity/PaymentStatus.java similarity index 87% rename from src/main/java/in/koreatech/koin/domain/order/model/PaymentStatus.java rename to src/main/java/in/koreatech/payment/model/entity/PaymentStatus.java index f56398f..e88e9f1 100644 --- a/src/main/java/in/koreatech/koin/domain/order/model/PaymentStatus.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentStatus.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.order.model; +package in.koreatech.payment.model.entity; import lombok.Getter; diff --git a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java index 465db13..d44ae16 100644 --- a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java +++ b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java @@ -1,7 +1,7 @@ package in.koreatech.payment.model.redis; -import static in.koreatech.koin.domain.order.model.OrderType.DELIVERY; -import static in.koreatech.koin.domain.order.model.OrderType.TAKE_OUT; +import static in.koreatech.payment.model.entity.OrderType.DELIVERY; +import static in.koreatech.payment.model.entity.OrderType.TAKE_OUT; import java.time.LocalDateTime; import java.util.List; @@ -10,10 +10,10 @@ import org.springframework.data.redis.core.RedisHash; import org.springframework.data.redis.core.TimeToLive; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderDelivery; -import in.koreatech.koin.domain.order.model.OrderTakeout; -import in.koreatech.koin.domain.order.model.OrderType; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderDelivery; +import in.koreatech.payment.model.entity.OrderTakeout; +import in.koreatech.payment.model.entity.OrderType; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.exception.InvalidTemporaryPaymentException; diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderDeliveryRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/OrderDeliveryRepository.java similarity index 63% rename from src/main/java/in/koreatech/koin/domain/order/repository/OrderDeliveryRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/OrderDeliveryRepository.java index 4691a83..f1e7c9a 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderDeliveryRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/OrderDeliveryRepository.java @@ -1,8 +1,8 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.OrderDelivery; +import in.koreatech.payment.model.entity.OrderDelivery; public interface OrderDeliveryRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuOptionRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/OrderMenuOptionRepository.java similarity index 65% rename from src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuOptionRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/OrderMenuOptionRepository.java index 56653fb..8dd36ab 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuOptionRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/OrderMenuOptionRepository.java @@ -1,8 +1,8 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.OrderMenuOption; +import in.koreatech.payment.model.entity.OrderMenuOption; public interface OrderMenuOptionRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/OrderMenuRepository.java similarity index 71% rename from src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/OrderMenuRepository.java index bfb99df..4bda8cc 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderMenuRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/OrderMenuRepository.java @@ -1,10 +1,10 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import java.util.List; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.OrderMenu; +import in.koreatech.payment.model.entity.OrderMenu; public interface OrderMenuRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/OrderRepository.java similarity index 60% rename from src/main/java/in/koreatech/koin/domain/order/repository/OrderRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/OrderRepository.java index 92693ae..70314b7 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/OrderRepository.java @@ -1,8 +1,8 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.Order; +import in.koreatech.payment.model.entity.Order; public interface OrderRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/OrderTakeoutRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/OrderTakeoutRepository.java similarity index 64% rename from src/main/java/in/koreatech/koin/domain/order/repository/OrderTakeoutRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/OrderTakeoutRepository.java index b7dc2b1..7c9cfa9 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/OrderTakeoutRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/OrderTakeoutRepository.java @@ -1,8 +1,8 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.OrderTakeout; +import in.koreatech.payment.model.entity.OrderTakeout; public interface OrderTakeoutRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentCancelRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/PaymentCancelRepository.java similarity index 72% rename from src/main/java/in/koreatech/koin/domain/order/repository/PaymentCancelRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/PaymentCancelRepository.java index d54dd1e..cc7c506 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentCancelRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/PaymentCancelRepository.java @@ -1,10 +1,10 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import java.util.List; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.PaymentCancel; +import in.koreatech.payment.model.entity.PaymentCancel; public interface PaymentCancelRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentIdempotencyKeyRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/PaymentIdempotencyKeyRepository.java similarity index 73% rename from src/main/java/in/koreatech/koin/domain/order/repository/PaymentIdempotencyKeyRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/PaymentIdempotencyKeyRepository.java index bfe9c3d..0d89d4d 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentIdempotencyKeyRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/PaymentIdempotencyKeyRepository.java @@ -1,10 +1,10 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import java.util.Optional; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; +import in.koreatech.payment.model.entity.PaymentIdempotencyKey; public interface PaymentIdempotencyKeyRepository extends Repository { diff --git a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentRepository.java b/src/main/java/in/koreatech/payment/repository/mysql/PaymentRepository.java similarity index 87% rename from src/main/java/in/koreatech/koin/domain/order/repository/PaymentRepository.java rename to src/main/java/in/koreatech/payment/repository/mysql/PaymentRepository.java index 8a74e6e..a766f94 100644 --- a/src/main/java/in/koreatech/koin/domain/order/repository/PaymentRepository.java +++ b/src/main/java/in/koreatech/payment/repository/mysql/PaymentRepository.java @@ -1,10 +1,10 @@ -package in.koreatech.koin.domain.order.repository; +package in.koreatech.payment.repository.mysql; import java.util.Optional; import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.order.model.Payment; +import in.koreatech.payment.model.entity.Payment; import in.koreatech.payment.exception.PaymentNotFoundException; public interface PaymentRepository extends Repository { diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java index 9b83ee7..e6fa33d 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -5,11 +5,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.koin.domain.order.model.PaymentStatus; -import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.model.entity.PaymentCancel; +import in.koreatech.payment.model.entity.PaymentStatus; +import in.koreatech.payment.repository.mysql.PaymentCancelRepository; +import in.koreatech.payment.repository.mysql.PaymentRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.dto.response.PaymentCancelResponse; import in.koreatech.payment.exception.PaymentAlreadyCanceledException; diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index ce557f7..95d4804 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -6,13 +6,13 @@ import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.order.cart.repository.CartRepository; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentStatus; -import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.OrderRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.model.entity.PaymentStatus; +import in.koreatech.payment.repository.mysql.OrderMenuRepository; +import in.koreatech.payment.repository.mysql.OrderRepository; +import in.koreatech.payment.repository.mysql.PaymentRepository; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; import in.koreatech.koin.domain.user.model.User; diff --git a/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java index ccb9f06..afd978b 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java @@ -4,8 +4,8 @@ import org.springframework.stereotype.Service; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; -import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; +import in.koreatech.payment.model.entity.PaymentIdempotencyKey; +import in.koreatech.payment.repository.mysql.PaymentIdempotencyKeyRepository; import lombok.RequiredArgsConstructor; @Service diff --git a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java index b7786da..e7a81e9 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java @@ -1,10 +1,10 @@ package in.koreatech.payment.service; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.repository.mysql.OrderMenuRepository; +import in.koreatech.payment.repository.mysql.PaymentRepository; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.dto.response.PaymentResponse; import lombok.RequiredArgsConstructor; diff --git a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java index a8db85a..bdce69d 100644 --- a/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java +++ b/src/test/java/in/koreatech/payment/acceptance/domain/PaymentApiTest.java @@ -21,19 +21,19 @@ import org.springframework.http.MediaType; import in.koreatech.koin.domain.order.cart.model.Cart; -import in.koreatech.koin.domain.order.model.Order; -import in.koreatech.koin.domain.order.model.OrderDelivery; -import in.koreatech.koin.domain.order.model.OrderMenu; -import in.koreatech.koin.domain.order.model.OrderTakeout; -import in.koreatech.koin.domain.order.model.OrderType; -import in.koreatech.koin.domain.order.model.Payment; -import in.koreatech.koin.domain.order.model.PaymentCancel; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; -import in.koreatech.koin.domain.order.model.PaymentMethod; -import in.koreatech.koin.domain.order.model.PaymentStatus; -import in.koreatech.koin.domain.order.repository.OrderMenuRepository; -import in.koreatech.koin.domain.order.repository.PaymentCancelRepository; -import in.koreatech.koin.domain.order.repository.PaymentRepository; +import in.koreatech.payment.model.entity.Order; +import in.koreatech.payment.model.entity.OrderDelivery; +import in.koreatech.payment.model.entity.OrderMenu; +import in.koreatech.payment.model.entity.OrderTakeout; +import in.koreatech.payment.model.entity.OrderType; +import in.koreatech.payment.model.entity.Payment; +import in.koreatech.payment.model.entity.PaymentCancel; +import in.koreatech.payment.model.entity.PaymentIdempotencyKey; +import in.koreatech.payment.model.entity.PaymentMethod; +import in.koreatech.payment.model.entity.PaymentStatus; +import in.koreatech.payment.repository.mysql.OrderMenuRepository; +import in.koreatech.payment.repository.mysql.PaymentCancelRepository; +import in.koreatech.payment.repository.mysql.PaymentRepository; import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenu; import in.koreatech.koin.domain.order.shop.model.entity.menu.OrderableShopMenuPrice; import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; diff --git a/src/test/java/in/koreatech/payment/acceptance/fixture/PaymentIdempotencyKeyFixture.java b/src/test/java/in/koreatech/payment/acceptance/fixture/PaymentIdempotencyKeyFixture.java index 13e0e58..1eed205 100644 --- a/src/test/java/in/koreatech/payment/acceptance/fixture/PaymentIdempotencyKeyFixture.java +++ b/src/test/java/in/koreatech/payment/acceptance/fixture/PaymentIdempotencyKeyFixture.java @@ -2,8 +2,8 @@ import org.springframework.stereotype.Component; -import in.koreatech.koin.domain.order.model.PaymentIdempotencyKey; -import in.koreatech.koin.domain.order.repository.PaymentIdempotencyKeyRepository; +import in.koreatech.payment.model.entity.PaymentIdempotencyKey; +import in.koreatech.payment.repository.mysql.PaymentIdempotencyKeyRepository; import in.koreatech.koin.domain.user.model.User; @Component From 39a14d2735880a2aa365c6ce2e9a53604a58155a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:32:38 +0900 Subject: [PATCH 26/29] =?UTF-8?q?feat:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EB=A7=A4=EB=8B=88=EC=A0=B8=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/payment/service/PaymentCancelService.java | 2 +- .../in/koreatech/payment/service/PaymentConfirmService.java | 2 +- .../payment/service/PaymentIdempotencyKeyService.java | 2 ++ .../in/koreatech/payment/service/PaymentQueryService.java | 2 +- .../java/in/koreatech/payment/service/PaymentService.java | 1 - .../koreatech/payment/service/TemporaryPaymentService.java | 2 -- .../koreatech/payment/service/UserAuthenticationService.java | 5 ++++- 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java index e6fa33d..2d9d173 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentCancelService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentCancelService.java @@ -30,7 +30,7 @@ public class PaymentCancelService { private final PaymentIdempotencyKeyService paymentIdempotencyKeyService; private final PaymentCancelMapper paymentCancelMapper; - @Transactional + @Transactional(transactionManager = "koinPaymentTransactionManager") public PaymentCancelResponse cancelPayment(User user, Integer paymentId, PaymentCancelInfo paymentCancelInfo) { Payment payment = paymentRepository.getById(paymentId); validatePaymentStatusIsNotCanceled(payment); diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index 95d4804..0c59601 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -39,7 +39,7 @@ public class PaymentConfirmService { private final CartRepository cartRepository; private final PaymentMapper paymentMapper; - @Transactional + @Transactional(transactionManager = "koinPaymentTransactionManager") public PaymentConfirmResponse confirmPayment(User user, PaymentConfirmInfo paymentConfirmInfo) { TemporaryPayment temporaryPayment = temporaryPaymentRedisRepository.getById(paymentConfirmInfo.orderId()); temporaryPayment.validateMatches(paymentConfirmInfo.orderId(), user.getId(), paymentConfirmInfo.amount()); diff --git a/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java index afd978b..e260bd2 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentIdempotencyKeyService.java @@ -3,6 +3,7 @@ import java.util.UUID; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import in.koreatech.payment.model.entity.PaymentIdempotencyKey; import in.koreatech.payment.repository.mysql.PaymentIdempotencyKeyRepository; @@ -14,6 +15,7 @@ public class PaymentIdempotencyKeyService { private final PaymentIdempotencyKeyRepository paymentIdempotencyKeyRepository; + @Transactional(transactionManager = "koinPaymentTransactionManager") public String getOrCreate(Integer userId) { return paymentIdempotencyKeyRepository .findByUserId(userId) diff --git a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java index e7a81e9..09bec3d 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java @@ -15,7 +15,7 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) +@Transactional(transactionManager = "koinPaymentTransactionManager", readOnly = true) public class PaymentQueryService { private final PaymentRepository paymentRepository; diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index a843e32..763c577 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -75,7 +75,6 @@ public PaymentCancelResponse cancelPayment(String accessToken, Integer paymentId return paymentCancelService.cancelPayment(user, paymentId, paymentCancelInfo); } - @Transactional(readOnly = true) public PaymentResponse getPayment(String accessToken, Integer paymentId) { User user = userAuthenticationService.authenticateUser(accessToken); return paymentQueryService.getPayment(user, paymentId); diff --git a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java index 7c8b663..ef2191a 100644 --- a/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java +++ b/src/main/java/in/koreatech/payment/service/TemporaryPaymentService.java @@ -28,7 +28,6 @@ public class TemporaryPaymentService { private final TemporaryPaymentRedisRepository temporaryPaymentRedisRepository; private final TemporaryMenuItemsMapper temporaryMenuItemsMapper; - @Transactional public TemporaryPaymentResponse createDeliveryPayment(User user, DeliveryPaymentInfo deliveryPaymentInfo) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); @@ -60,7 +59,6 @@ public TemporaryPaymentResponse createDeliveryPayment(User user, DeliveryPayment return TemporaryPaymentResponse.of(pgOrderId); } - @Transactional public TemporaryPaymentResponse createTakeoutPayment(User user, TakeoutPaymentInfo takeoutPaymentInfo) { Cart cart = cartRepository.getCartByUserId(user.getId()); OrderableShop orderableShop = cart.getOrderableShop(); diff --git a/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java b/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java index ac0e504..947643f 100644 --- a/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java +++ b/src/main/java/in/koreatech/payment/service/UserAuthenticationService.java @@ -1,13 +1,16 @@ package in.koreatech.payment.service; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.repository.UserRepository; import in.koreatech.payment.common.auth.JwtProvider; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor +@Transactional(transactionManager = "koinTransactionManager", readOnly = true) public class UserAuthenticationService { private final JwtProvider jwtProvider; From 87ad2595398dd06bba335bc3dfca30319d705fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 21:34:03 +0900 Subject: [PATCH 27/29] =?UTF-8?q?build:=20flyway=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ src/main/java/in/koreatech/payment/service/PaymentService.java | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f066d01..df8ffea 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,9 @@ dependencies { // slack Notification implementation 'com.github.maricn:logback-slack-appender:1.4.0' + // flyway + implementation 'org.flywaydb:flyway-mysql' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'com.squareup.okhttp3:mockwebserver' diff --git a/src/main/java/in/koreatech/payment/service/PaymentService.java b/src/main/java/in/koreatech/payment/service/PaymentService.java index 763c577..c698e75 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentService.java @@ -1,7 +1,6 @@ package in.koreatech.payment.service; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.user.model.User; import in.koreatech.payment.dto.request.PaymentCancelRequest; From eb4ee5a6dc8cb6f0ff29229f391d1fb331cf7505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 22:43:08 +0900 Subject: [PATCH 28/29] =?UTF-8?q?feat:=20flyway=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shop/model/entity/shop/OrderableShop.java | 2 +- .../payment/KoinPaymentApplication.java | 15 +-- .../dto/response/PaymentConfirmResponse.java | 2 +- .../payment/dto/response/PaymentResponse.java | 2 +- .../koreatech/payment/model/entity/Order.java | 22 ++-- .../payment/model/entity/OrderDelivery.java | 2 +- .../payment/model/entity/OrderMenu.java | 2 +- .../payment/model/entity/OrderMenuOption.java | 2 +- .../payment/model/entity/OrderTakeout.java | 2 +- .../payment/model/entity/Payment.java | 4 +- .../payment/model/entity/PaymentCancel.java | 2 +- .../model/entity/PaymentIdempotencyKey.java | 1 + .../payment/model/redis/TemporaryPayment.java | 4 +- .../service/PaymentConfirmService.java | 2 +- .../payment/service/PaymentQueryService.java | 6 +- src/main/resources/db/migration/V1__init.sql | 103 ++++++++++++++++++ 16 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 src/main/resources/db/migration/V1__init.sql diff --git a/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java b/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java index 39f55b0..022e1c8 100644 --- a/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java +++ b/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java @@ -29,7 +29,7 @@ @Entity @Getter @NoArgsConstructor(access = PROTECTED) -@Table(name = "orderable_shop") +@Table(schema = "koin", name = "orderable_shop") @Where(clause = "is_deleted=0") public class OrderableShop extends BaseEntity { diff --git a/src/main/java/in/koreatech/payment/KoinPaymentApplication.java b/src/main/java/in/koreatech/payment/KoinPaymentApplication.java index a072058..0eac7d6 100644 --- a/src/main/java/in/koreatech/payment/KoinPaymentApplication.java +++ b/src/main/java/in/koreatech/payment/KoinPaymentApplication.java @@ -7,20 +7,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @ConfigurationPropertiesScan -@SpringBootApplication( - scanBasePackages = { - "in.koreatech.payment", - "in.koreatech.koin" - } -) -@EnableJpaRepositories(basePackages = { - "in.koreatech.payment", - "in.koreatech.koin" -}) -@EntityScan(basePackages = { - "in.koreatech.payment", - "in.koreatech.koin" -}) +@SpringBootApplication public class KoinPaymentApplication { public static void main(String[] args) { diff --git a/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java b/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java index 32f2e87..20cb3b8 100644 --- a/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java +++ b/src/main/java/in/koreatech/payment/dto/response/PaymentConfirmResponse.java @@ -113,9 +113,9 @@ public static InnerMenuOptionResponse from(OrderMenuOption orderMenuOption) { public static PaymentConfirmResponse of( Payment payment, Order order, + OrderableShop orderableShop, List orderMenus ) { - OrderableShop orderableShop = order.getOrderableShop(); Shop shop = orderableShop.getShop(); String deliveryAddress = null; diff --git a/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java b/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java index be7a63c..b1e6626 100644 --- a/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java +++ b/src/main/java/in/koreatech/payment/dto/response/PaymentResponse.java @@ -113,9 +113,9 @@ public static InnerMenuOptionResponse from(OrderMenuOption orderMenuOption) { public static PaymentResponse of( Payment payment, Order order, + OrderableShop orderableShop, List orderMenus ) { - OrderableShop orderableShop = order.getOrderableShop(); Shop shop = orderableShop.getShop(); String deliveryAddress = null; diff --git a/src/main/java/in/koreatech/payment/model/entity/Order.java b/src/main/java/in/koreatech/payment/model/entity/Order.java index 7a7fb38..d27872e 100644 --- a/src/main/java/in/koreatech/payment/model/entity/Order.java +++ b/src/main/java/in/koreatech/payment/model/entity/Order.java @@ -30,7 +30,7 @@ @Getter @Entity -@Table(schema = "koin", name = "`order`") +@Table(schema = "koin_payment", name = "`order`") @Where(clause = "is_deleted=0") @NoArgsConstructor(access = PROTECTED) public class Order extends BaseEntity { @@ -66,13 +66,13 @@ public class Order extends BaseEntity { @Column(name = "is_deleted", nullable = false) private Boolean isDeleted = FALSE; - @JoinColumn(name = "orderable_shop_id", nullable = false, updatable = false) - @ManyToOne(fetch = LAZY) - private OrderableShop orderableShop; + @NotNull + @Column(name = "orderable_shop_id", nullable = false, updatable = false) + private Integer orderableShopId; - @JoinColumn(name = "user_id", nullable = false, updatable = false) - @ManyToOne(fetch = LAZY) - private User user; + @NotNull + @Column(name = "user_id", nullable = false, updatable = false) + private Integer userId; @OneToOne(mappedBy = "order", fetch = LAZY, cascade = ALL) private OrderDelivery orderDelivery; @@ -89,8 +89,8 @@ private Order( Integer totalProductPrice, Integer totalPrice, Boolean isDeleted, - OrderableShop orderableShop, - User user, + Integer orderableShopId, + Integer userId, OrderDelivery orderDelivery, OrderTakeout orderTakeout ) { @@ -101,8 +101,8 @@ private Order( this.totalProductPrice = totalProductPrice; this.totalPrice = totalPrice; this.isDeleted = isDeleted; - this.orderableShop = orderableShop; - this.user = user; + this.orderableShopId = orderableShopId; + this.userId = userId; this.orderDelivery = orderDelivery; this.orderTakeout = orderTakeout; } diff --git a/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java b/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java index bce0534..1f4c2cc 100644 --- a/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderDelivery.java @@ -18,7 +18,7 @@ @Getter @Entity -@Table(name = "order_delivery") +@Table(schema = "koin_payment", name = "order_delivery") @NoArgsConstructor(access = PROTECTED) public class OrderDelivery { diff --git a/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java b/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java index 35ac4dd..4572c37 100644 --- a/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderMenu.java @@ -24,7 +24,7 @@ @Entity @Getter -@Table(schema = "koin", name = "order_menu") +@Table(schema = "koin_payment", name = "order_menu") @NoArgsConstructor(access = PROTECTED) public class OrderMenu { diff --git a/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java b/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java index 8620793..7c107b5 100644 --- a/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderMenuOption.java @@ -19,7 +19,7 @@ @Entity @Getter -@Table(schema = "koin", name = "order_menu_option") +@Table(schema = "koin_payment", name = "order_menu_option") @NoArgsConstructor(access = PROTECTED) public class OrderMenuOption { diff --git a/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java b/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java index 796fc44..e68fdbc 100644 --- a/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java +++ b/src/main/java/in/koreatech/payment/model/entity/OrderTakeout.java @@ -17,7 +17,7 @@ @Getter @Entity -@Table(name = "order_takeout") +@Table(schema = "koin_payment", name = "order_takeout") @NoArgsConstructor(access = PROTECTED) public class OrderTakeout { diff --git a/src/main/java/in/koreatech/payment/model/entity/Payment.java b/src/main/java/in/koreatech/payment/model/entity/Payment.java index 6e97f00..57f6f1b 100644 --- a/src/main/java/in/koreatech/payment/model/entity/Payment.java +++ b/src/main/java/in/koreatech/payment/model/entity/Payment.java @@ -26,7 +26,7 @@ @Entity @Getter -@Table(schema = "koin", name = "payment") +@Table(schema = "koin_payment", name = "payment") @NoArgsConstructor(access = PROTECTED) public class Payment { @@ -86,7 +86,7 @@ private Payment( } public void validateUserIdMatches(Integer userId) { - if (!userId.equals(this.order.getUser().getId())) { + if (!userId.equals(this.order.getUserId())) { throw PaymentAccessDeniedException.withDetail("userId : " + userId); } } diff --git a/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java b/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java index 73687ce..47463c3 100644 --- a/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentCancel.java @@ -21,7 +21,7 @@ @Entity @Getter -@Table(name = "payment_cancel") +@Table(schema = "koin_payment", name = "payment_cancel") @NoArgsConstructor(access = PROTECTED) public class PaymentCancel { diff --git a/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java b/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java index 5b4963a..bdd05f0 100644 --- a/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java +++ b/src/main/java/in/koreatech/payment/model/entity/PaymentIdempotencyKey.java @@ -22,6 +22,7 @@ @Getter @Entity @Table( + schema = "koin_payment", name = "payment_idempotency_key", uniqueConstraints = @UniqueConstraint(name = "uk_idempotency_key_user_id", columnNames = "user_id") ) diff --git a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java index d44ae16..3a8de9b 100644 --- a/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java +++ b/src/main/java/in/koreatech/payment/model/redis/TemporaryPayment.java @@ -156,8 +156,8 @@ public Order toOrder(User user, OrderableShop orderableShop) { .phoneNumber(phoneNumber) .totalProductPrice(totalProductPrice) .totalPrice(totalPrice) - .orderableShop(orderableShop) - .user(user) + .orderableShopId(orderableShop.getId()) + .userId(user.getId()) .isDeleted(false) .build(); diff --git a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java index 0c59601..42f4f03 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentConfirmService.java @@ -60,7 +60,7 @@ public PaymentConfirmResponse confirmPayment(User user, PaymentConfirmInfo payme cleanupAfterPaymentConfirm(paymentConfirmInfo.orderId(), user.getId()); - return PaymentConfirmResponse.of(payment, order, orderMenus); + return PaymentConfirmResponse.of(payment, order, orderableShop, orderMenus); } private void validatePaymentStatus(String status) { diff --git a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java index 09bec3d..b780d7e 100644 --- a/src/main/java/in/koreatech/payment/service/PaymentQueryService.java +++ b/src/main/java/in/koreatech/payment/service/PaymentQueryService.java @@ -1,5 +1,7 @@ package in.koreatech.payment.service; +import in.koreatech.koin.domain.order.shop.model.entity.shop.OrderableShop; +import in.koreatech.koin.domain.order.shop.repository.OrderableShopRepository; import in.koreatech.payment.model.entity.Order; import in.koreatech.payment.model.entity.OrderMenu; import in.koreatech.payment.model.entity.Payment; @@ -20,6 +22,7 @@ public class PaymentQueryService { private final PaymentRepository paymentRepository; private final OrderMenuRepository orderMenuRepository; + private final OrderableShopRepository orderableShopRepository; public PaymentResponse getPayment(User user, Integer paymentId) { Payment payment = paymentRepository.getById(paymentId); @@ -27,7 +30,8 @@ public PaymentResponse getPayment(User user, Integer paymentId) { Order order = payment.getOrder(); List orderMenus = orderMenuRepository.findAllByOrderId(order.getId()); + OrderableShop orderableShop = orderableShopRepository.getById(order.getOrderableShopId()); - return PaymentResponse.of(payment, order, orderMenus); + return PaymentResponse.of(payment, order, orderableShop, orderMenus); } } diff --git a/src/main/resources/db/migration/V1__init.sql b/src/main/resources/db/migration/V1__init.sql new file mode 100644 index 0000000..2f9c25c --- /dev/null +++ b/src/main/resources/db/migration/V1__init.sql @@ -0,0 +1,103 @@ +CREATE TABLE IF NOT EXISTS `koin_payment`.`order` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '주문 ID', + `pg_order_id` VARCHAR(64) NOT NULL COMMENT 'pg 주문 ID', + `order_type` VARCHAR(10) NOT NULL COMMENT '주문 타입', + `phone_number` VARCHAR(20) NOT NULL COMMENT '주문자 전화번호', + `total_product_price` INT UNSIGNED NOT NULL COMMENT '상품 총 금액', + `total_price` INT UNSIGNED NOT NULL COMMENT '주문 총 금액', + `is_deleted` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT '삭제 여부', + `orderable_shop_id` INT UNSIGNED NOT NULL COMMENT '주문한 상점 ID', + `user_id` INT UNSIGNED NOT NULL COMMENT '주문자 사용자 ID', + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 일시', + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정 일시', + PRIMARY KEY (`id`) +); + +CREATE INDEX idx_user_id ON `koin_payment`.`order` (user_id); +CREATE INDEX idx_orderable_shop_id ON `koin_payment`.`order` (orderable_shop_id); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`order_delivery` +( + `order_id` INT UNSIGNED NOT NULL COMMENT '주문 ID', + `address` VARCHAR(100) NOT NULL COMMENT '배달 주소', + `to_owner` VARCHAR(50) NOT NULL COMMENT '사장님 전달 메시지', + `to_rider` VARCHAR(50) NOT NULL COMMENT '라이더 전달 메시지', + `delivery_tip` INT UNSIGNED NOT NULL COMMENT '배달비', + `provide_cutlery` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '수저, 포크 수령 여부', + PRIMARY KEY (order_id), + CONSTRAINT `fk_order_delivery_order` FOREIGN KEY (`order_id`) REFERENCES `koin_payment`.`order` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`order_takeout` +( + `order_id` INT UNSIGNED NOT NULL COMMENT '주문 ID', + `to_owner` VARCHAR(50) NOT NULL COMMENT '사장님 전달 메시지', + `provide_cutlery` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '수저, 포크 수령 여부', + PRIMARY KEY (order_id), + CONSTRAINT `fk_order_pack_order` FOREIGN KEY (`order_id`) REFERENCES `koin_payment`.`order` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`payment` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '고유 ID', + `payment_key` VARCHAR(200) NOT NULL COMMENT '결제 키', + `amount` INT UNSIGNED NOT NULL COMMENT '결제 금액', + `status` VARCHAR(30) NOT NULL COMMENT '결제 상태', + `method` VARCHAR(30) NOT NULL COMMENT '결제 수단', + `requested_at` TIMESTAMP NOT NULL COMMENT '결제 요청 일시', + `approved_at` TIMESTAMP NOT NULL COMMENT '결제 승인 일시', + `order_id` INT UNSIGNED NOT NULL COMMENT '주문 번호', + PRIMARY KEY (`id`), + UNIQUE KEY uq_payment_key (`id`), + CONSTRAINT fk_payment_order FOREIGN KEY (`order_id`) REFERENCES `koin_payment`.`order` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`payment_cancel` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '결제 취소 ID', + `transaction_key` VARCHAR(64) NOT NULL COMMENT '취소 트랜잭션 키', + `cancel_reason` VARCHAR(200) NOT NULL COMMENT '취소 사유', + `cancel_amount` INT UNSIGNED NOT NULL COMMENT '취소 금액', + `canceled_at` TIMESTAMP NOT NULL COMMENT '취소 일시', + `payment_id` INT UNSIGNED NOT NULL COMMENT '결제 ID', + PRIMARY KEY (`id`), + CONSTRAINT `fk_payment_cancel_payment` FOREIGN KEY (`payment_id`) REFERENCES `koin_payment`.`payment` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`order_menu` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '주문 메뉴 ID', + `menu_name` VARCHAR(255) NOT NULL COMMENT '메뉴 이름', + `menu_price` INT UNSIGNED NOT NULL COMMENT '메뉴 금액', + `menu_price_name` VARCHAR(255) NULL COMMENT '메뉴 가격 이름', + `quantity` INT UNSIGNED NOT NULL COMMENT '수량', + `order_id` INT UNSIGNED NOT NULL COMMENT '주문 ID', + PRIMARY KEY (`id`), + CONSTRAINT `fk_order_menu_order` FOREIGN KEY (`order_id`) REFERENCES `koin_payment`.`order` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`order_menu_option` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '메뉴 옵션 ID', + `option_group_name` VARCHAR(255) NOT NULL COMMENT '주문 메뉴 옵션 이름', + `option_name` VARCHAR(255) NOT NULL COMMENT '옵션 이름', + `option_price` INT UNSIGNED NOT NULL COMMENT '옵션 가격', + `quantity` INT UNSIGNED NOT NULL COMMENT '옵션 수량', + `order_menu_id` INT UNSIGNED NOT NULL COMMENT '주문 메뉴 ID', + PRIMARY KEY (`id`), + CONSTRAINT `fk_order_menu_option_menu` FOREIGN KEY (`order_menu_id`) REFERENCES `koin_payment`.`order_menu` (`id`) +); + +CREATE TABLE IF NOT EXISTS `koin_payment`.`payment_idempotency_key` +( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '결제 멱등키 ID', + `user_id` INT UNSIGNED NOT NULL COMMENT '유저 ID', + `idempotency_key` VARCHAR(300) NOT NULL COMMENT '결제 멱등키', + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 일시', + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정 일시', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_idempotency_key_user_id` (`user_id`) +); + +CREATE INDEX idx_user_id ON `koin_payment`.`payment_idempotency_key` (user_id); From e769583dbc21cc07762ac95ee3f4c6b7aac4233a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=A0=EA=B4=80=EA=B7=9C?= Date: Mon, 1 Sep 2025 22:49:55 +0900 Subject: [PATCH 29/29] =?UTF-8?q?chore:=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/order/shop/model/entity/shop/OrderableShop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java b/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java index 022e1c8..39f55b0 100644 --- a/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java +++ b/src/main/java/in/koreatech/koin/domain/order/shop/model/entity/shop/OrderableShop.java @@ -29,7 +29,7 @@ @Entity @Getter @NoArgsConstructor(access = PROTECTED) -@Table(schema = "koin", name = "orderable_shop") +@Table(name = "orderable_shop") @Where(clause = "is_deleted=0") public class OrderableShop extends BaseEntity {