OrderRepository@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("""
DELETE FROM Order o
WHERE o.status = :status
AND o.orderDate < :date
""")
int deleteOldOrders(@Param("status") OrderStatus status,
@Param("date") LocalDateTime date);
기존코드
@Transactional
public OrderResponse createOrder(String email, String address, int zipcode, Long productId , int quantity) {
// 유저생성
User user = userRepository.findByEmail(email)
.orElseGet(() ->
userRepository.save(
User.builder()
.email(email)
.address(address)
.zipcode(zipcode)
.build()
)
);
// 수량 검증
if (quantity <= 0) {
throw new OrderException(OrderErrorCode.INVALID_QUANTITY);
}
// 상품 조회
Product product = productRepository.findById(productId)
.orElseThrow(() ->
new ProductException(
ProductErrorCode.UNKNOWN_PRODUCT,
"상품이 존재하지 않습니다. productId=" + productId
)
);
// 오늘 오늘 READY 주문 기준 shipmentId 결정
LocalDateTime startOfToday = LocalDate.now().atStartOfDay();
LocalDateTime endOfToday = LocalDate.now().atTime(23, 59, 59);
Long shipmentId = orderRepository
.findFirstByUserAndStatusAndOrderDateBetween(
user,
OrderStatus.READY,
startOfToday,
endOfToday
)
.map(Order::getShipmentId)
.orElseGet(() -> System.currentTimeMillis());
// 같은 상품 + 같은 shipment + READY 주문 있는지 확인
Optional<Order> existingOrder =
orderRepository.findByUserAndProductAndShipmentIdAndStatus(
user,
product,
shipmentId,
OrderStatus.READY
);
// 있으면 quantity 누적
if (existingOrder.isPresent()) {
Order order = existingOrder.get();
order.addQuantity(quantity);
return OrderResponse.from(order);
}
// 없을 경우 주문 생성
Order order = Order.builder()
.shipmentId(shipmentId)
.user(user)
.product(product)
.quantity(quantity)
.totalPrice(product.getCost() * quantity)
.status(OrderStatus.READY)
.build();
Order saveorder = orderRepository.save(order);
return OrderResponse.from(saveorder);
}
변경 코드
CreateOrderResponse 생성
public record CreateOrderResponse(
Long shipmentId,
List<OrderResponse> orders
) {}
CreateOrderRequest 수정
public record CreateOrderRequest(
String email,
String address,
int zipcode,
List<OrderDetail> details
) {
public record OrderDetail(
Long productId,
int quantity
) {}
}
Controller 수정
@PostMapping("/create")
public ResponseEntity<Response<CreateOrderResponse>> createOrder(@RequestBody CreateOrderRequest req) {
CreateOrderResponse res = orderService.createOrder(req);
return ResponseEntity.status(201)
.body(CommonResponse.success(res, "주문 생성을 성공하였습니다."));
}
Service 수정
/ 주문하기
@Transactional
public CreateOrderResponse createOrder(CreateOrderRequest dto) {
// 유저생성
User user = userRepository.findByEmail(dto.email())
.orElseGet(() -> userRepository.save(
User.builder()
.email(dto.email())
.address(dto.address())
.zipcode(dto.zipcode())
.build()
));
// details 검증
// 수량 검증
if (dto.details() == null || dto.details().isEmpty()) {
throw new OrderException(OrderErrorCode.INVALID_QUANTITY);
}
if (dto.details().stream().anyMatch(d -> d.quantity() <= 0)) {
throw new OrderException(OrderErrorCode.INVALID_QUANTITY);
}
// 같은 상품이 여러번 들어오면 수량 합치기
Map<Long, Integer> quantityMap = dto.details().stream()
.collect(Collectors.toMap(
CreateOrderRequest.OrderDetail::productId,
CreateOrderRequest.OrderDetail::quantity,
Integer::sum
));
// 상품을 한번에 조회
Set<Long> productIds = quantityMap.keySet();
List<Product> products = productRepository.findAllById(productIds);
// 없는 상품 섞였는지 체크
if (products.size() != productIds.size()) {
throw new ProductException(
ProductErrorCode.UNKNOWN_PRODUCT,
"요청에 존재하지 않는 상품이 포함되어 있습니다."
);
}
// 오늘 오늘 READY 주문 기준 shipmentId 결정
LocalDateTime startOfToday = LocalDate.now().atStartOfDay();
LocalDateTime endOfToday = LocalDate.now().atTime(23, 59, 59);
Long shipmentId = orderRepository
.findFirstByUserAndStatusAndOrderDateBetween(
user,
OrderStatus.READY,
startOfToday,
endOfToday
)
.map(Order::getShipmentId)
.orElseGet(() -> System.currentTimeMillis());
List<Order> newOrders = new ArrayList<>();
List<OrderResponse> result = new ArrayList<>();
for (Product product : products) {
int qty = quantityMap.get(product.getId());
Optional<Order> existingOrder =
orderRepository.findByUserAndProductAndShipmentIdAndStatus(
user,
product,
shipmentId,
OrderStatus.READY
);
if (existingOrder.isPresent()) {
Order order = existingOrder.get();
order.addQuantity(qty);
result.add(OrderResponse.from(order));
continue;
}
Order order = Order.builder()
.shipmentId(shipmentId)
.user(user)
.product(product)
.quantity(qty)
.totalPrice(product.getCost() * qty)
.status(OrderStatus.READY)
.build();
newOrders.add(order);
}
// 새로 만든 것만 저장
if (!newOrders.isEmpty()) {
List<Order> saved = orderRepository.saveAll(newOrders);
saved.forEach(o -> result.add(OrderResponse.from(o)));
}
return new CreateOrderResponse(shipmentId, result);
}
결과

에러버전
