데브코스 : 1차프로젝트 (5일차)

슬키·2026년 1월 28일

5일차

할일목록

  • 발표자료 만들기
  • creatOrder 기능 추가
  • 피드백 반영

1. 피드백 반영

  • 기존 주문 삭제 스케쥴러에 유저부분은 삭제하고 기능을 개선한다.
    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);
  • 조회없이 기능 바로 삭제

CreateOrder 기능 추가

  • 팀장님이 장바구니기능을 따로 안만드는 대신에 한번의 주문을 진행할때 여러 상품을 담을 수 있도록 기능을 만들어달라고했다.

기존코드

@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);

    }

결과

에러버전

profile
풀스택 개발자 성장일기

0개의 댓글