diff --git a/src/main/java/hekireki/sanjijiksong/domain/item/repository/ItemSearchRepository.java b/src/main/java/hekireki/sanjijiksong/domain/item/repository/ItemSearchRepository.java index 8776829..dc01bf4 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/item/repository/ItemSearchRepository.java +++ b/src/main/java/hekireki/sanjijiksong/domain/item/repository/ItemSearchRepository.java @@ -5,7 +5,9 @@ import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import java.util.List; +import org.springframework.stereotype.Repository; +@Repository public interface ItemSearchRepository extends ElasticsearchRepository { @Query(""" diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/controller/OrderController.java b/src/main/java/hekireki/sanjijiksong/domain/order/controller/OrderController.java index 6fe2f68..faeb817 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/order/controller/OrderController.java +++ b/src/main/java/hekireki/sanjijiksong/domain/order/controller/OrderController.java @@ -4,6 +4,7 @@ import hekireki.sanjijiksong.domain.order.dto.OrderListUpdateRequest; import hekireki.sanjijiksong.domain.order.dto.OrderRequest; import hekireki.sanjijiksong.domain.order.dto.OrderResponse; +import hekireki.sanjijiksong.domain.order.dto.PaymentRequest; import hekireki.sanjijiksong.domain.order.service.OrderService; import hekireki.sanjijiksong.global.security.dto.CustomUserDetails; import jakarta.validation.Valid; @@ -15,9 +16,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/orders") @@ -30,19 +36,27 @@ public class OrderController implements OrderApi { // 주문 생성 @PostMapping public ResponseEntity createOrder( - @RequestBody @Valid OrderRequest request, - @AuthenticationPrincipal CustomUserDetails userDetails + @RequestBody @Valid OrderRequest request, + @AuthenticationPrincipal CustomUserDetails userDetails ) { OrderResponse response = orderService.createOrder(userDetails.getUser(), request); return ResponseEntity.status(HttpStatus.CREATED).body(response); } + @PostMapping("/confirm") + public ResponseEntity confirmOrder( + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestBody PaymentRequest paymentRequest + ) { + return ResponseEntity.ok().body(orderService.confirmOrder(paymentRequest)); + } + // 주문 취소 @PatchMapping("/{orderId}/cancel") public ResponseEntity cancelOrder( - @PathVariable("orderId") Long orderId, - @AuthenticationPrincipal CustomUserDetails userDetails + @PathVariable("orderId") Long orderId, + @AuthenticationPrincipal CustomUserDetails userDetails ) { orderService.cancelOrder(orderId, userDetails.getUser()); return ResponseEntity.noContent().build(); @@ -51,9 +65,9 @@ public ResponseEntity cancelOrder( // 주문 수정 @PatchMapping("/{orderId}/items/{itemId}") public ResponseEntity updateOrderItems( - @PathVariable("orderId") Long orderId, - @RequestBody @Valid OrderListUpdateRequest request, - @AuthenticationPrincipal CustomUserDetails userDetails) { + @PathVariable("orderId") Long orderId, + @RequestBody @Valid OrderListUpdateRequest request, + @AuthenticationPrincipal CustomUserDetails userDetails) { OrderResponse response = orderService.updateOrderItems(request, userDetails.getUser()); return ResponseEntity.ok(response); } @@ -62,8 +76,8 @@ public ResponseEntity updateOrderItems( // 단일 주문 조회 @GetMapping("/{orderId}") public ResponseEntity getOrderDetail( - @PathVariable("orderId") Long orderId, - @AuthenticationPrincipal CustomUserDetails userDetails + @PathVariable("orderId") Long orderId, + @AuthenticationPrincipal CustomUserDetails userDetails ) { OrderResponse response = orderService.getOrderDetail(orderId, userDetails.getUser()); return ResponseEntity.ok(response); @@ -72,9 +86,9 @@ public ResponseEntity getOrderDetail( // 내 주문 전체 조회 @GetMapping public ResponseEntity> getMyOrders( - @AuthenticationPrincipal CustomUserDetails userDetails, - @RequestParam(value = "page", defaultValue = "0") int page, - @RequestParam(value = "size", defaultValue = "10") int size + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestParam(value = "page", defaultValue = "0") int page, + @RequestParam(value = "size", defaultValue = "10") int size ) { Pageable pageable = PageRequest.of(page, size); Page orders = orderService.getMyOrders(userDetails.getUser(), pageable); diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/dto/OrderResponse.java b/src/main/java/hekireki/sanjijiksong/domain/order/dto/OrderResponse.java index 853e351..dc7016d 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/order/dto/OrderResponse.java +++ b/src/main/java/hekireki/sanjijiksong/domain/order/dto/OrderResponse.java @@ -3,48 +3,53 @@ import hekireki.sanjijiksong.domain.order.entity.Order; import hekireki.sanjijiksong.domain.order.entity.OrderList; import hekireki.sanjijiksong.domain.order.entity.OrderStatus; -import lombok.Builder; - import java.util.List; +import lombok.Builder; public record OrderResponse( - Long orderId, - OrderStatus orderStatus, - int totalCount, - int totalPrice, - List orderLists + Long orderId, + OrderStatus orderStatus, + int totalCount, + int totalPrice, + String payOrderId, + String paymentKey, + List orderLists ) { + @Builder public static OrderResponse from(Order order) { return new OrderResponse( - order.getId(), - order.getOrderStatus(), - order.getStock(), - order.getTotalPrice(), - order.getOrderLists().stream() - .map(OrderListResponse::from) - .toList() + order.getId(), + order.getOrderStatus(), + order.getStock(), + order.getTotalPrice(), + order.getOrderId().toString(), + order.getTossPaymentKey(), + order.getOrderLists().stream() + .map(OrderListResponse::from) + .toList() ); } public record OrderListResponse( - Long itemId, - String itemName, - int price, - int count, - int totalPrice, - Long storeId, - String storeName + Long itemId, + String itemName, + int price, + int count, + int totalPrice, + Long storeId, + String storeName ) { + public static OrderListResponse from(OrderList ol) { return new OrderListResponse( - ol.getItem().getId(), - ol.getItem().getName(), - ol.getItem().getPrice(), - ol.getCount(), - ol.getCountPrice(), - ol.getStore().getId(), - ol.getStore().getName() + ol.getItem().getId(), + ol.getItem().getName(), + ol.getItem().getPrice(), + ol.getCount(), + ol.getCountPrice(), + ol.getStore().getId(), + ol.getStore().getName() ); } } diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/dto/PaymentRequest.java b/src/main/java/hekireki/sanjijiksong/domain/order/dto/PaymentRequest.java new file mode 100644 index 0000000..f9182ef --- /dev/null +++ b/src/main/java/hekireki/sanjijiksong/domain/order/dto/PaymentRequest.java @@ -0,0 +1,5 @@ +package hekireki.sanjijiksong.domain.order.dto; + +public record PaymentRequest(String orderId, String amount, String paymentKey) { + +} diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/entity/Order.java b/src/main/java/hekireki/sanjijiksong/domain/order/entity/Order.java index 13407d6..85e1e35 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/order/entity/Order.java +++ b/src/main/java/hekireki/sanjijiksong/domain/order/entity/Order.java @@ -3,14 +3,27 @@ import hekireki.sanjijiksong.domain.user.entity.User; import hekireki.sanjijiksong.global.common.BaseTimeEntity; import hekireki.sanjijiksong.global.common.exception.OrderException; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; +import lombok.Setter; @NoArgsConstructor @AllArgsConstructor @@ -20,74 +33,90 @@ @Table(name = "`ORDER`") public class Order extends BaseTimeEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") - private User user; - - @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) - private List orderLists = new ArrayList<>(); - - @Enumerated(EnumType.STRING) - private OrderStatus orderStatus; - - @Column(nullable = false) - private int stock; // 총 수량 - - @Column(nullable = false) - private int totalPrice; // 총 금액 - - // 주문 항목 추가 - public void addOrderItem(OrderList item) { - this.orderLists.add(item); - this.stock += item.getCount(); - this.totalPrice += item.getCountPrice(); - } - - // 총 주문 금액 재계산 - public int calculateTotalAmount() { - return orderLists.stream() - .mapToInt(OrderList::calculateTotalPrice) - .sum(); - } - - // 총 주문 수량 재계산 - public int calculateTotalQuantity() { - return orderLists.stream() - .mapToInt(OrderList::getCount) - .sum(); - } - - // 취소 가능 여부 - public boolean isCancelable() { - return this.orderStatus == OrderStatus.ORDERED|| this.orderStatus == OrderStatus.PAID; - } - - // 주문 취소 처리 - public void cancel() { - if (!isCancelable()) { - throw new OrderException.OrderNotCancelableException(); - } - this.orderStatus = OrderStatus.CANCELED; - } - - // 수정 가능 여부 - public boolean isUpdatable() { - return this.orderStatus == OrderStatus.ORDERED; - } - - // 주문 수정 - public void updateOrderSummary(int oldCount, int oldPrice, int newCount, int newPrice) { - this.stock = this.stock - oldCount + newCount; - this.totalPrice = this.totalPrice - oldPrice + newPrice; - } - - public Order(User user, OrderStatus orderStatus) { - this.user = user; - this.orderStatus = orderStatus; - this.stock = 0; - this.totalPrice = 0; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) + private List orderLists = new ArrayList<>(); + + @Enumerated(EnumType.STRING) + private OrderStatus orderStatus; + + @Column(nullable = false) + private int stock; // 총 수량 + + @Column(nullable = false) + private int totalPrice; // 총 금액 + + @Builder.Default + private UUID orderId = UUID.randomUUID(); + + @Setter + private String tossPaymentKey; + + public Order(User user, OrderStatus orderStatus) { + this.user = user; + this.orderStatus = orderStatus; + this.stock = 0; + this.totalPrice = 0; + this.orderId = UUID.randomUUID(); + } + + // 주문 항목 추가 + public void addOrderItem(OrderList item) { + this.orderLists.add(item); + this.stock += item.getCount(); + this.totalPrice += item.getCountPrice(); + } + + // 총 주문 금액 재계산 + public int calculateTotalAmount() { + return orderLists.stream() + .mapToInt(OrderList::calculateTotalPrice) + .sum(); + } + + // 총 주문 수량 재계산 + public int calculateTotalQuantity() { + return orderLists.stream() + .mapToInt(OrderList::getCount) + .sum(); + } + + // 취소 가능 여부 + public boolean isCancelable() { + return this.orderStatus == OrderStatus.ORDERED || this.orderStatus == OrderStatus.PAID; + } + + // 주문 취소 처리 + public void cancel() { + if (!isCancelable()) { + throw new OrderException.OrderNotCancelableException(); + } + this.orderStatus = OrderStatus.CANCELED; + } + + // 수정 가능 여부 + public boolean isUpdatable() { + return this.orderStatus == OrderStatus.ORDERED; + } + + public void paid(String paymentKey) { + if (this.orderStatus == OrderStatus.PAID) { + throw new OrderException.OrderAlreadyPaidException(); + } + this.orderStatus = OrderStatus.PAID; + this.tossPaymentKey = paymentKey; + } + + // 주문 수정 + public void updateOrderSummary(int oldCount, int oldPrice, int newCount, int newPrice) { + this.stock = this.stock - oldCount + newCount; + this.totalPrice = this.totalPrice - oldPrice + newPrice; + } } diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/repository/OrderRepository.java b/src/main/java/hekireki/sanjijiksong/domain/order/repository/OrderRepository.java index 49b3464..5fceb79 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/order/repository/OrderRepository.java +++ b/src/main/java/hekireki/sanjijiksong/domain/order/repository/OrderRepository.java @@ -2,25 +2,27 @@ import hekireki.sanjijiksong.domain.order.entity.Order; import hekireki.sanjijiksong.domain.user.entity.User; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; -import java.util.Optional; - public interface OrderRepository extends JpaRepository { Page findAllByUser(User user, Pageable pageable); - + @Query("SELECT o FROM Order o JOIN FETCH o.orderLists ol JOIN FETCH ol.item JOIN FETCH ol.store WHERE o.id = :id") Optional findByIdWithDetails(@Param("id") Long id); - + @Query("SELECT DISTINCT o FROM Order o WHERE o.user = :user") Page findAllByUserPaged(@Param("user") User user, Pageable pageable); - + @Query("SELECT DISTINCT o FROM Order o JOIN FETCH o.orderLists ol JOIN FETCH ol.item JOIN FETCH ol.store WHERE o.id IN :ids") List findByIdInWithDetails(@Param("ids") List ids); + + Optional findByOrderId(UUID orderId); } diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/service/OrderService.java b/src/main/java/hekireki/sanjijiksong/domain/order/service/OrderService.java index b2feb2a..4fa36ed 100644 --- a/src/main/java/hekireki/sanjijiksong/domain/order/service/OrderService.java +++ b/src/main/java/hekireki/sanjijiksong/domain/order/service/OrderService.java @@ -5,6 +5,7 @@ import hekireki.sanjijiksong.domain.order.dto.OrderListUpdateRequest; import hekireki.sanjijiksong.domain.order.dto.OrderRequest; import hekireki.sanjijiksong.domain.order.dto.OrderResponse; +import hekireki.sanjijiksong.domain.order.dto.PaymentRequest; import hekireki.sanjijiksong.domain.order.entity.Order; import hekireki.sanjijiksong.domain.order.entity.OrderList; import hekireki.sanjijiksong.domain.order.entity.OrderStatus; @@ -12,6 +13,11 @@ import hekireki.sanjijiksong.domain.user.entity.User; import hekireki.sanjijiksong.global.common.exception.ItemException; import hekireki.sanjijiksong.global.common.exception.OrderException; +import hekireki.sanjijiksong.global.common.exception.OrderException.OrderNotFoundException; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -19,9 +25,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.stream.Collectors; - @Slf4j @Service @RequiredArgsConstructor @@ -30,6 +33,7 @@ public class OrderService { private final OrderRepository orderRepository; private final ItemRepository itemRepository; + private final PaymentService paymentService; // 주문 생성 @Transactional @@ -39,7 +43,7 @@ public OrderResponse createOrder(User user, OrderRequest request) { for (OrderRequest.OrderListRequest itemReq : request.orderLists()) { Item item = itemRepository.findById(itemReq.itemId()) - .orElseThrow(ItemException.ItemNotFoundException::new); + .orElseThrow(ItemException.ItemNotFoundException::new); if (item.getStock() < itemReq.count()) { log.warn("재고 부족 - itemId={}, 요청 수량={}, 현재 재고={}", item.getId(), itemReq.count(), item.getStock()); @@ -59,13 +63,27 @@ public OrderResponse createOrder(User user, OrderRequest request) { return OrderResponse.from(order); } + @Transactional + public OrderResponse confirmOrder(PaymentRequest paymentRequest) { + Order order = orderRepository.findByOrderId(UUID.fromString(paymentRequest.orderId())) + .orElseThrow(OrderNotFoundException::new); + + Map confirm = paymentService.confirm(paymentRequest); + + var paymentKey = confirm.get("paymentKey"); + + order.paid(paymentKey.toString()); + + return OrderResponse.from(order); + } + // 주문 취소 @Transactional public void cancelOrder(Long orderId, User user) { log.info("주문 취소 요청 - userId={}, orderId={}", user.getId(), orderId); Order order = orderRepository.findById(orderId) - .orElseThrow(OrderException.OrderNotFoundException::new); + .orElseThrow(OrderException.OrderNotFoundException::new); order.cancel(); @@ -84,7 +102,7 @@ public OrderResponse updateOrderItems(OrderListUpdateRequest request, User user) log.info("주문 수정 요청 - userId={}, orderId={}", user.getId(), request.orderId()); Order order = orderRepository.findById(request.orderId()) - .orElseThrow(OrderException.OrderNotFoundException::new); + .orElseThrow(OrderException.OrderNotFoundException::new); if (!order.isUpdatable()) { log.warn("수정 불가 상태 - orderId={}, status={}", order.getId(), order.getOrderStatus()); @@ -93,9 +111,9 @@ public OrderResponse updateOrderItems(OrderListUpdateRequest request, User user) for (OrderListUpdateRequest.OrderListItemUpdate update : request.orderLists()) { OrderList target = order.getOrderLists().stream() - .filter(ol -> ol.getItem().getId().equals(update.itemId())) - .findFirst() - .orElseThrow(OrderException.OrderItemNotFoundException::new); + .filter(ol -> ol.getItem().getId().equals(update.itemId())) + .findFirst() + .orElseThrow(OrderException.OrderItemNotFoundException::new); Item item = target.getItem(); @@ -110,7 +128,7 @@ public OrderResponse updateOrderItems(OrderListUpdateRequest request, User user) order.updateOrderSummary(oldCount, oldPrice, target.getCount(), target.getCountPrice()); log.info("주문 항목 수정 - orderId={}, itemId={}, 기존 수량={}, 변경 수량={}, 현재 재고={}", - order.getId(), item.getId(), oldCount, update.count(), item.getStock()); + order.getId(), item.getId(), oldCount, update.count(), item.getStock()); } log.info("주문 수정 완료 - userId={}, orderId={}", user.getId(), order.getId()); @@ -123,7 +141,7 @@ public OrderResponse getOrderDetail(Long orderId, User user) { log.info("주문 상세 조회 요청 - userId={}, orderId={}", user.getId(), orderId); Order order = orderRepository.findByIdWithDetails(orderId) - .orElseThrow(OrderException.OrderNotFoundException::new); + .orElseThrow(OrderException.OrderNotFoundException::new); return OrderResponse.from(order); } @@ -134,26 +152,26 @@ public Page getMyOrders(User user, Pageable pageable) { // 페이징을 적용하여 주문 ID 목록 조회 Page orderPage = orderRepository.findAllByUserPaged(user, pageable); - + // 조회된 ID가 없으면 빈 페이지 반환 - if(orderPage.isEmpty()) { + if (orderPage.isEmpty()) { return orderPage.map(OrderResponse::from); } - + // 조회된 ID로 페치 조인을 통해 상세 정보 로딩 List orderIds = orderPage.getContent().stream() - .map(Order::getId) - .collect(Collectors.toList()); - + .map(Order::getId) + .collect(Collectors.toList()); + List ordersWithDetails = orderRepository.findByIdInWithDetails(orderIds); - + // ID별로 정렬된 맵 생성 return orderPage.map(order -> { Order detailedOrder = ordersWithDetails.stream() - .filter(o -> o.getId().equals(order.getId())) - .findFirst() - .orElse(order); // 못 찾으면 기본 order 사용 - + .filter(o -> o.getId().equals(order.getId())) + .findFirst() + .orElse(order); // 못 찾으면 기본 order 사용 + return OrderResponse.from(detailedOrder); }); } diff --git a/src/main/java/hekireki/sanjijiksong/domain/order/service/PaymentService.java b/src/main/java/hekireki/sanjijiksong/domain/order/service/PaymentService.java new file mode 100644 index 0000000..f44acdb --- /dev/null +++ b/src/main/java/hekireki/sanjijiksong/domain/order/service/PaymentService.java @@ -0,0 +1,48 @@ +package hekireki.sanjijiksong.domain.order.service; + +import hekireki.sanjijiksong.domain.order.dto.PaymentRequest; +import hekireki.sanjijiksong.global.common.exception.ErrorCode; +import hekireki.sanjijiksong.global.common.exception.OrderException; +import java.util.Base64; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +@Service +@RequiredArgsConstructor +public class PaymentService { + + @Value("${tosspayments.url.confirm}") + private String confirmUrl; + + @Value("${tosspayments.secret}") + private String secretKey; + + @Transactional + public Map confirm(PaymentRequest paymentRequest) { + String auth = Base64.getEncoder().encodeToString((secretKey + ":").getBytes()); + + RestTemplate restTemplate = new RestTemplate(); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", "Basic " + auth); + + HttpEntity entity = new HttpEntity<>(paymentRequest, headers); + + ResponseEntity response = restTemplate.postForEntity(confirmUrl, entity, Map.class); + + if (!response.getStatusCode().is2xxSuccessful()) { + throw new OrderException(ErrorCode.PAYMENT_SERVER_INTERVAL); + } + + return response.getBody(); + } +} diff --git a/src/main/java/hekireki/sanjijiksong/global/common/exception/ErrorCode.java b/src/main/java/hekireki/sanjijiksong/global/common/exception/ErrorCode.java index bbaad88..1c6ddf6 100644 --- a/src/main/java/hekireki/sanjijiksong/global/common/exception/ErrorCode.java +++ b/src/main/java/hekireki/sanjijiksong/global/common/exception/ErrorCode.java @@ -1,9 +1,12 @@ package hekireki.sanjijiksong.global.common.exception; import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; + @Getter +@RequiredArgsConstructor public enum ErrorCode { //Member USER_ALREADY_EXIST(HttpStatus.BAD_REQUEST, "이미 존재하는 회원입니다."), @@ -27,6 +30,7 @@ public enum ErrorCode { ORDER_NOT_CANCELABLE(HttpStatus.BAD_REQUEST, "취소할 수 없는 주문 상태입니다."), ORDER_ITEM_NOT_FOUND(HttpStatus.NOT_FOUND, "주문 항목이 존재하지 않습니다."), ORDER_NOT_UPDATABLE(HttpStatus.BAD_REQUEST, "현재 상태에서는 주문을 수정할 수 없습니다."), + ORDER_ALREADY_PAID(HttpStatus.BAD_REQUEST, "이미 결제된 상태입니다."), //Security NO_REFRESH_TOKEN_COOKIE(HttpStatus.BAD_REQUEST, "리프레시 토큰 쿠키가 존재하지 않습니다."), @@ -50,13 +54,11 @@ public enum ErrorCode { // Following 관련 에러 ALREADY_FOLLOWING(HttpStatus.BAD_REQUEST, "이미 팔로우 중인 가게입니다."), - FOLLOWING_NOT_FOUND(HttpStatus.NOT_FOUND, "팔로우 정보를 찾을 수 없습니다."); + FOLLOWING_NOT_FOUND(HttpStatus.NOT_FOUND, "팔로우 정보를 찾을 수 없습니다."), + PAYMENT_SERVER_INTERVAL(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류로 결제에 실패했습니다."); + private final HttpStatus status; private final String message; - ErrorCode(HttpStatus status, String message) { - this.status = status; - this.message = message; - } } diff --git a/src/main/java/hekireki/sanjijiksong/global/common/exception/OrderException.java b/src/main/java/hekireki/sanjijiksong/global/common/exception/OrderException.java index 8d6d11f..77ff494 100644 --- a/src/main/java/hekireki/sanjijiksong/global/common/exception/OrderException.java +++ b/src/main/java/hekireki/sanjijiksong/global/common/exception/OrderException.java @@ -36,4 +36,10 @@ public OrderNotUpdatableException() { } } + public static class OrderAlreadyPaidException extends OrderException { + public OrderAlreadyPaidException() { + super(ErrorCode.ORDER_NOT_CANCELABLE); + } + } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a98fef3..78b2a13 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -34,7 +34,7 @@ spring: port: 6379 cache: type: redis - + elasticsearch: repositories: enabled: true @@ -62,12 +62,19 @@ cloud: bucket: ${AWS_BUCKET} kamis: - cert: - id: ${KAMIS_CERT_ID} - key: ${KAMIS_CERT_KEY} + cert: + id: ${KAMIS_CERT_ID} + key: ${KAMIS_CERT_KEY} management: endpoints: web: exposure: include: prometheus + +tosspayments: + url: + confirm: https://api.tosspayments.com/v1/payments/confirm + secret: ${TOSS_SECRET} + +