diff --git a/src/main/java/poomasi/domain/admin/statistics/controller/StatisticsController.java b/src/main/java/poomasi/domain/admin/statistics/controller/StatisticsController.java index e221f69c..c5679770 100644 --- a/src/main/java/poomasi/domain/admin/statistics/controller/StatisticsController.java +++ b/src/main/java/poomasi/domain/admin/statistics/controller/StatisticsController.java @@ -3,12 +3,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import poomasi.domain.admin.statistics.dto.response.CategoryMonthlySalesResponse; import poomasi.domain.admin.statistics.dto.response.StoreMonthlySalesResponse; import poomasi.domain.admin.statistics.service.StatisticsService; -import poomasi.domain.order.service.OrderService; + +import java.time.LocalDate; @RestController @RequiredArgsConstructor @@ -16,14 +18,13 @@ public class StatisticsController { private final StatisticsService statisticsService; - private final OrderService orderService; @GetMapping("/stores/{storeId}/monthly-sales") public ResponseEntity> getMonthlyStoreSales( @PathVariable Long storeId, @RequestParam String startMonth, @RequestParam String endMonth, - Pageable pageable) { + @PageableDefault(size = 10) Pageable pageable) { Page salesResponses = statisticsService.getMonthlyStoreSales(storeId, startMonth, endMonth, pageable); return ResponseEntity.ok(salesResponses); @@ -31,12 +32,11 @@ public ResponseEntity> getMonthlyStoreSales( @GetMapping("/categories/monthly-sales") public ResponseEntity> getCategoryMonthlySales( - @RequestParam Long categoryId, @RequestParam String startMonth, - @RequestParam String endMonth, - Pageable pageable - ) { - Page sales = statisticsService.getCategoryMonthlySales(categoryId, startMonth, endMonth, pageable); - return ResponseEntity.ok(sales); + @PageableDefault(size = 10) Pageable pageable) { + + LocalDate startDate = LocalDate.parse(startMonth + "-01"); + Page salesResponses = statisticsService.getCategoryMonthlySales(startDate, pageable); + return ResponseEntity.ok(salesResponses); } } diff --git a/src/main/java/poomasi/domain/admin/statistics/dto/response/CategoryMonthlySalesResponse.java b/src/main/java/poomasi/domain/admin/statistics/dto/response/CategoryMonthlySalesResponse.java index 3a2649b5..778719a1 100644 --- a/src/main/java/poomasi/domain/admin/statistics/dto/response/CategoryMonthlySalesResponse.java +++ b/src/main/java/poomasi/domain/admin/statistics/dto/response/CategoryMonthlySalesResponse.java @@ -1,9 +1,20 @@ package poomasi.domain.admin.statistics.dto.response; +import lombok.Getter; +import lombok.Setter; + import java.math.BigDecimal; -public record CategoryMonthlySalesResponse( - String categoryName, - int count, - BigDecimal totalSales -) { } +@Getter +@Setter +public class CategoryMonthlySalesResponse { + private String categoryName; + private int count; + private BigDecimal totalSales; + + public CategoryMonthlySalesResponse(String categoryName, int count, BigDecimal totalSales) { + this.categoryName = categoryName; + this.count = count; + this.totalSales = totalSales; + } +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/admin/statistics/service/StatisticsService.java b/src/main/java/poomasi/domain/admin/statistics/service/StatisticsService.java index f63767c6..dfb5d9f8 100644 --- a/src/main/java/poomasi/domain/admin/statistics/service/StatisticsService.java +++ b/src/main/java/poomasi/domain/admin/statistics/service/StatisticsService.java @@ -8,15 +8,21 @@ import org.springframework.transaction.annotation.Transactional; import poomasi.domain.admin.statistics.dto.response.StoreMonthlySalesResponse; import poomasi.domain.order.entity.Order; +import poomasi.domain.order.entity.OrderedProductStatus; import poomasi.domain.order.service.OrderService; import poomasi.domain.admin.statistics.dto.response.CategoryMonthlySalesResponse; +import poomasi.domain.product._category.entity.Category; +import poomasi.domain.product._category.service.CategoryService; +import poomasi.domain.product.entity.Product; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @RequiredArgsConstructor @@ -24,8 +30,8 @@ @Service public class StatisticsService { private final OrderService orderService; + private final CategoryService categoryService; - @Transactional(readOnly = true) public Page getMonthlyStoreSales(Long storeId, String startMonth, String endMonth, Pageable pageable) { LocalDate start = LocalDate.parse(startMonth + "-01"); LocalDate end = LocalDate.parse(endMonth + "-01"); @@ -36,25 +42,51 @@ public Page getMonthlyStoreSales(Long storeId, String List orders = orderService.getOrdersByUpdateAtBetween(startDate, endDate); - // 주문 목록에서 각 OrderedProduct를 순회하여 storeId와 일치하는 주문 품목의 매출을 계산 List salesResponses = orders.stream() .flatMap(order -> order.getOrderedProducts().stream()) - .filter(orderedProduct -> orderedProduct.getProduct().getStore().getId().equals(storeId)) + .filter(orderedProduct -> orderedProduct.getStoreId() + .equals(storeId) && orderedProduct.getOrderedProductStatus() == OrderedProductStatus.DELIVERED) .map(orderedProduct -> { BigDecimal totalSales = orderedProduct.getPrice().multiply(BigDecimal.valueOf(orderedProduct.getCount())); - return new StoreMonthlySalesResponse(orderedProduct.getProduct().getStore(), totalSales); + return new StoreMonthlySalesResponse(orderedProduct.getStore(), totalSales); }) .collect(Collectors.toList()); return new PageImpl<>(salesResponses, pageable, salesResponses.size()); } - public Page getCategoryMonthlySales(Long categoryId, String startMonth, String endMonth, Pageable pageable) { - LocalDate start = LocalDate.parse(startMonth + "-01"); - LocalDate end = LocalDate.parse(endMonth + "-01"); - end = end.withDayOfMonth(end.lengthOfMonth()); + public Page getCategoryMonthlySales(LocalDate startDate, Pageable pageable) { + + LocalDate endDate = startDate.plusMonths(5); + + List orders = orderService.getOrdersByUpdateAtBetween(startDate.atStartOfDay(), endDate.atTime(23, 59, 59)); + + Map salesMap = new HashMap<>(); + + orders.stream() + .flatMap(order -> order.getOrderedProducts().stream()) + .filter(orderedProduct -> orderedProduct.getOrderedProductStatus() == OrderedProductStatus.DELIVERED) + .forEach(orderedProduct -> { + Product product = orderedProduct.getProduct(); + Long categoryId = product.getCategoryId(); + Category category = categoryService.getCategory(categoryId); + + CategoryMonthlySalesResponse salesResponse = salesMap.computeIfAbsent(category, k -> + new CategoryMonthlySalesResponse(category.getName(), 0, BigDecimal.ZERO) + ); + + salesResponse.setCount(salesResponse.getCount() + 1); + BigDecimal productTotal = product.getPrice().multiply(BigDecimal.valueOf(orderedProduct.getCount())); + salesResponse.setTotalSales(salesResponse.getTotalSales().add(productTotal)); + }); + + List responseList = new ArrayList<>(salesMap.values()); + + int start = (int) pageable.getOffset(); + int end = Math.min((start + pageable.getPageSize()), responseList.size()); + Page page = new PageImpl<>(responseList.subList(start, end), pageable, responseList.size()); - return orderService.getCategoryMonthlySales(categoryId, start.atStartOfDay(), end.atTime(LocalTime.MAX), pageable); + return page; } } diff --git a/src/main/java/poomasi/domain/order/entity/OrderedProduct.java b/src/main/java/poomasi/domain/order/entity/OrderedProduct.java index a3e456c5..c4052446 100644 --- a/src/main/java/poomasi/domain/order/entity/OrderedProduct.java +++ b/src/main/java/poomasi/domain/order/entity/OrderedProduct.java @@ -11,14 +11,10 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import java.math.BigDecimal; -import java.util.List; -import java.util.Objects; -import jakarta.persistence.*; import jdk.jfr.Description; import lombok.Builder; import lombok.Getter; @@ -28,10 +24,9 @@ import poomasi.domain.member.entity.Member; import poomasi.domain.product.entity.Product; import poomasi.domain.review.entity.Review; +import poomasi.domain.store.entity.Store; import poomasi.payment.entity.Payment; -import java.math.BigDecimal; - import static poomasi.domain.order.entity.OrderedProductStatus.PENDING_SELLER_APPROVAL; @Entity @@ -159,5 +154,13 @@ public BigDecimal calculateRefundAmount(){ BigDecimal count = new BigDecimal(this.count); return this.price.multiply(count); } + + public Store getStore() { + return getProduct().getStore(); + } + + public Long getStoreId(){ + return getStore().getId(); + } } diff --git a/src/main/java/poomasi/domain/order/repository/OrderRepository.java b/src/main/java/poomasi/domain/order/repository/OrderRepository.java index 7791e210..1abbdd00 100644 --- a/src/main/java/poomasi/domain/order/repository/OrderRepository.java +++ b/src/main/java/poomasi/domain/order/repository/OrderRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import poomasi.domain.admin.statistics.dto.response.CategoryMonthlySalesResponse; import poomasi.domain.order.entity.Order; import java.time.LocalDateTime; @@ -23,24 +22,4 @@ public interface OrderRepository extends JpaRepository { @Query("SELECT o FROM Order o WHERE o.updateAt BETWEEN :startDate AND :endDate") List findAllByUpdateAtBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate); - - @Query(""" - SELECT new poomasi.domain.admin.statistics.dto.response.CategoryMonthlySalesResponse( - p.category, - COUNT(op.id), - SUM(op.price * op.quantity) - ) - FROM Order o - JOIN o.orderedProducts op - JOIN op.product p - WHERE p.category.id = :categoryId - AND o.createdAt BETWEEN :startDate AND :endDate - GROUP BY p.category - """) - Page findCategoryMonthlySales( - @Param("categoryId") Long categoryId, - @Param("startDate") LocalDateTime startDate, - @Param("endDate") LocalDateTime endDate, - Pageable pageable - ); } diff --git a/src/main/java/poomasi/domain/order/service/OrderService.java b/src/main/java/poomasi/domain/order/service/OrderService.java index 956b0f2e..93ce7d53 100644 --- a/src/main/java/poomasi/domain/order/service/OrderService.java +++ b/src/main/java/poomasi/domain/order/service/OrderService.java @@ -218,10 +218,6 @@ public List getOrdersByUpdateAtBetween(LocalDateTime startDate, LocalDate return orderRepository.findAllByUpdateAtBetween(startDate, endDate); } - public Page getCategoryMonthlySales(Long categoryId, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable){ - return orderRepository.findCategoryMonthlySales(categoryId, startDate, endDate, pageable); - } - }