Skip to content

Commit 2059222

Browse files
authored
OrderController 구현 (#170)
1 parent de31931 commit 2059222

File tree

9 files changed

+508
-84
lines changed

9 files changed

+508
-84
lines changed

src/main/java/com/back/domain/cart/repository/CartRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,8 @@ public interface CartRepository extends JpaRepository<Cart, Long> {
4040
@Modifying
4141
@Query("DELETE FROM Cart c WHERE c.user = :user AND c.product.id IN :productIds")
4242
void deleteByUserAndProductIdIn(@Param("user") User user, @Param("productIds") List<Long> productIds);
43+
44+
@Modifying
45+
@Query("DELETE FROM Cart c WHERE c.user = :user AND c.product.productUuid IN :productUuids")
46+
void deleteByUserAndProductUuidIn(@Param("user") User user, @Param("productUuids") List<java.util.UUID> productUuids);
4347
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.back.domain.order.order.controller;
2+
3+
import com.back.domain.order.order.dto.request.OrderCancelRequestDto;
4+
import com.back.domain.order.order.dto.request.OrderExchangeRequestDto;
5+
import com.back.domain.order.order.dto.request.OrderRefundRequestDto;
6+
import com.back.domain.order.order.dto.request.OrderRequestDto;
7+
import com.back.domain.order.order.dto.request.OrderStatusChangeRequestDto;
8+
import com.back.domain.order.order.dto.response.OrderResponseDto;
9+
import com.back.domain.order.order.service.OrderService;
10+
import com.back.domain.user.entity.User;
11+
import io.swagger.v3.oas.annotations.Operation;
12+
import io.swagger.v3.oas.annotations.tags.Tag;
13+
import jakarta.validation.Valid;
14+
import lombok.RequiredArgsConstructor;
15+
import org.springframework.data.domain.Page;
16+
import org.springframework.data.domain.Pageable;
17+
import org.springframework.data.domain.Sort;
18+
import org.springframework.data.web.PageableDefault;
19+
import org.springframework.http.HttpStatus;
20+
import org.springframework.http.ResponseEntity;
21+
import org.springframework.security.access.prepost.PreAuthorize;
22+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
23+
import org.springframework.web.bind.annotation.*;
24+
25+
@RestController
26+
@RequestMapping("/api/orders")
27+
@RequiredArgsConstructor
28+
@Tag(name = "주문", description = "주문 관련 API")
29+
public class OrderController {
30+
31+
private final OrderService orderService;
32+
33+
/**
34+
* 주문 생성
35+
*/
36+
@PostMapping
37+
@Operation(summary = "주문 생성", description = "장바구니 상품을 주문으로 변환하여 주문을 생성합니다.")
38+
public ResponseEntity<OrderResponseDto> createOrder(
39+
@Valid @RequestBody OrderRequestDto requestDto,
40+
@AuthenticationPrincipal User user
41+
) {
42+
OrderResponseDto responseDto = orderService.createOrder(user, requestDto);
43+
return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
44+
}
45+
46+
/**
47+
* 주문 목록 조회 (페이징) - 모든 상품 상세 정보 포함
48+
*/
49+
@GetMapping
50+
@Operation(summary = "주문 목록 조회", description = "사용자의 주문 목록을 조회합니다. 한 페이지에 8개씩 표시됩니다.")
51+
public ResponseEntity<Page<OrderResponseDto>> getOrderList(
52+
@PageableDefault(
53+
size = 8,
54+
sort = "orderDate",
55+
direction = Sort.Direction.DESC
56+
) Pageable pageable,
57+
@AuthenticationPrincipal User user
58+
) {
59+
Page<OrderResponseDto> result = orderService.getOrderList(user, pageable);
60+
return ResponseEntity.ok(result);
61+
}
62+
63+
/**
64+
* 주문 상세 조회
65+
*/
66+
@GetMapping("/{orderId}")
67+
@Operation(summary = "주문 상세 조회", description = "특정 주문의 상세 정보를 조회합니다.")
68+
public ResponseEntity<OrderResponseDto> getOrderDetail(
69+
@PathVariable Long orderId,
70+
@AuthenticationPrincipal User user
71+
) {
72+
OrderResponseDto result = orderService.getOrderDetail(orderId, user);
73+
return ResponseEntity.ok(result);
74+
}
75+
76+
/**
77+
* 주문 취소
78+
*/
79+
@PostMapping("/{orderId}/cancel")
80+
@Operation(summary = "주문 취소", description = "결제완료된 주문을 취소합니다.")
81+
public ResponseEntity<Void> cancelOrder(
82+
@PathVariable Long orderId,
83+
@Valid @RequestBody OrderCancelRequestDto requestDto,
84+
@AuthenticationPrincipal User user
85+
) {
86+
orderService.cancelOrder(orderId, user, requestDto);
87+
return ResponseEntity.ok().build();
88+
}
89+
90+
/**
91+
* 환불 신청
92+
*/
93+
@PostMapping("/{orderId}/refund")
94+
@Operation(summary = "환불 신청", description = "배송완료된 주문에 대해 환불을 신청합니다.")
95+
public ResponseEntity<Void> requestRefund(
96+
@PathVariable Long orderId,
97+
@Valid @RequestBody OrderRefundRequestDto requestDto,
98+
@AuthenticationPrincipal User user
99+
) {
100+
orderService.requestRefund(orderId, user, requestDto);
101+
return ResponseEntity.ok().build();
102+
}
103+
104+
/**
105+
* 교환 신청
106+
*/
107+
@PostMapping("/{orderId}/exchange")
108+
@Operation(summary = "교환 신청", description = "배송완료된 주문에 대해 교환을 신청합니다.")
109+
public ResponseEntity<Void> requestExchange(
110+
@PathVariable Long orderId,
111+
@Valid @RequestBody OrderExchangeRequestDto requestDto,
112+
@AuthenticationPrincipal User user
113+
) {
114+
orderService.requestExchange(orderId, user, requestDto);
115+
return ResponseEntity.ok().build();
116+
}
117+
118+
/**
119+
* 주문 상태 변경 (관리자용)
120+
*/
121+
@PatchMapping("/{orderId}/status")
122+
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_ROOT')")
123+
@Operation(summary = "주문 상태 변경", description = "관리자가 주문 상태를 변경합니다. (관리자 전용)")
124+
public ResponseEntity<Void> changeOrderStatus(
125+
@PathVariable Long orderId,
126+
@Valid @RequestBody OrderStatusChangeRequestDto requestDto,
127+
@AuthenticationPrincipal User admin
128+
) {
129+
orderService.changeOrderStatus(orderId, requestDto, admin);
130+
return ResponseEntity.ok().build();
131+
}
132+
}

src/main/java/com/back/domain/order/order/dto/request/OrderRequestDto.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import jakarta.validation.constraints.Pattern;
88

99
import java.util.List;
10+
import java.util.UUID;
1011

1112
/**
1213
* 주문 생성 요청 DTO
@@ -40,8 +41,8 @@ public record OrderRequestDto(
4041
* 주문 상품 요청 DTO
4142
*/
4243
public record OrderItemRequestDto(
43-
@NotNull(message = "상품 ID는 필수입니다.")
44-
Long productId,
44+
@NotNull(message = "상품 UUID는 필수입니다.")
45+
UUID productUuid,
4546

4647
@NotNull(message = "수량은 필수입니다.")
4748
Integer quantity,

src/main/java/com/back/domain/order/order/dto/response/OrderListResponseDto.java

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/main/java/com/back/domain/order/order/entity/Order.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ public static Order createOrder(User user, List<OrderItem> orderItems,
101101
OrderAmountCalculator.OrderAmountInfo amountInfo = OrderAmountCalculator.calculateOrderAmount(orderItems);
102102

103103
// 주문 생성
104-
Order order = Order.builder()
105-
.user(user)
106-
.orderNumber(orderNumber)
107-
.status(OrderStatus.PENDING)
104+
Order order = Order.builder()
105+
.user(user)
106+
.orderNumber(orderNumber)
107+
.status(OrderStatus.PAYMENT_COMPLETED)
108108
.totalQuantity(amountInfo.totalQuantity())
109109
.totalAmount(amountInfo.totalAmount())
110110
.shippingFee(amountInfo.shippingFee())

src/main/java/com/back/domain/order/order/entity/OrderStatus.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.back.domain.order.order.entity;
22

33
public enum OrderStatus {
4-
PENDING, // 주문 대기
5-
CONFIRMED, // 주문 확인
6-
SHIPPED, // 배송 중
7-
DELIVERED, // 배송 완료
4+
PAYMENT_COMPLETED, // 결제완료
5+
PREPARING_SHIPMENT, // 배송준비중
6+
SHIPPING, // 배송중
7+
DELIVERED, // 배송완료
88
CANCELLED, // 주문 취소
99
REFUNDED, // 환불 완료
1010
REFUND_REQUESTED, // 환불 신청

src/main/java/com/back/domain/order/order/service/OrderService.java

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.back.domain.cart.entity.Cart;
44
import com.back.domain.cart.repository.CartRepository;
55
import com.back.domain.order.order.dto.request.*;
6-
import com.back.domain.order.order.dto.response.OrderListResponseDto;
76
import com.back.domain.order.order.dto.response.OrderResponseDto;
87
import com.back.domain.order.order.entity.Order;
98
import com.back.domain.order.order.entity.OrderStatus;
@@ -65,30 +64,14 @@ public OrderResponseDto createOrder(User user, OrderRequestDto requestDto) {
6564
}
6665

6766
/**
68-
* 주문 목록 조회 (페이징)
67+
* 주문 목록 조회 (페이징) - 모든 상품 상세 정보 포함
6968
*/
70-
public Page<OrderListResponseDto> getOrderList(User user, Pageable pageable) {
69+
public Page<OrderResponseDto> getOrderList(User user, Pageable pageable) {
7170
Page<Order> orders = orderRepository.findByUserOrderByOrderDateDesc(user, pageable);
7271

7372
return orders.map(order -> {
74-
// 대표 상품 정보 (첫 번째 상품)
75-
Product firstProduct = order.getOrderItems().get(0).getProduct();
76-
String representativeProductName = firstProduct.getName();
77-
String representativeProductThumbnailUrl = getProductThumbnailUrl(firstProduct);
78-
79-
return new OrderListResponseDto(
80-
order.getId(),
81-
order.getOrderNumber(),
82-
order.getStatus(),
83-
order.getTotalQuantity(),
84-
order.getTotalAmount(),
85-
order.getShippingFee(),
86-
order.getFinalAmount(),
87-
order.getPaymentMethod(),
88-
order.getOrderDate(),
89-
representativeProductName,
90-
representativeProductThumbnailUrl
91-
);
73+
// 주문 상세 조회와 동일한 로직 사용
74+
return convertToOrderResponseDto(order);
9275
});
9376
}
9477

@@ -117,8 +100,10 @@ public void cancelOrder(Long orderId, User user, OrderCancelRequestDto requestDt
117100
order.validateOwnership(user);
118101

119102
// 취소 가능 여부 체크
120-
if (order.getStatus() == OrderStatus.DELIVERED || order.getStatus() == OrderStatus.SHIPPED) {
121-
throw new IllegalStateException("발송준비중으로 상태가 변경된 이후에는 취소할 수 없습니다.");
103+
if (order.getStatus() == OrderStatus.PREPARING_SHIPMENT ||
104+
order.getStatus() == OrderStatus.SHIPPING ||
105+
order.getStatus() == OrderStatus.DELIVERED) {
106+
throw new IllegalStateException("배송준비중으로 상태가 변경된 이후에는 취소할 수 없습니다.");
122107
}
123108

124109
// 취소 실행
@@ -184,7 +169,7 @@ public void requestExchange(Long orderId, User user, OrderExchangeRequestDto req
184169
* 주문 상태 변경 (관리자용)
185170
*/
186171
@Transactional
187-
public void changeOrderStatus(Long orderId, OrderStatusChangeRequestDto requestDto) {
172+
public void changeOrderStatus(Long orderId, OrderStatusChangeRequestDto requestDto, User admin) {
188173
Order order = orderRepository.findById(orderId)
189174
.orElseThrow(() -> new IllegalArgumentException("주문을 찾을 수 없습니다."));
190175

@@ -200,7 +185,7 @@ public void changeOrderStatus(Long orderId, OrderStatusChangeRequestDto requestD
200185
private List<OrderItem> createOrderItems(List<OrderRequestDto.OrderItemRequestDto> orderItemRequests) {
201186
return orderItemRequests.stream()
202187
.map(itemRequest -> {
203-
Product product = productRepository.findById(itemRequest.productId())
188+
Product product = productRepository.findByProductUuid(itemRequest.productUuid())
204189
.orElseThrow(() -> new IllegalArgumentException("상품을 찾을 수 없습니다."));
205190

206191
return OrderItem.createOrderItem(product, itemRequest.quantity(), itemRequest.optionInfo());
@@ -212,11 +197,11 @@ private List<OrderItem> createOrderItems(List<OrderRequestDto.OrderItemRequestDt
212197
* 장바구니에서 제거
213198
*/
214199
private void removeFromCart(User user, List<OrderRequestDto.OrderItemRequestDto> orderItems) {
215-
List<Long> productIds = orderItems.stream()
216-
.map(OrderRequestDto.OrderItemRequestDto::productId)
200+
List<UUID> productUuids = orderItems.stream()
201+
.map(OrderRequestDto.OrderItemRequestDto::productUuid)
217202
.toList();
218203

219-
cartRepository.deleteByUserAndProductIdIn(user, productIds);
204+
cartRepository.deleteByUserAndProductUuidIn(user, productUuids);
220205
}
221206

222207
/**

0 commit comments

Comments
 (0)