add year sales

This commit is contained in:
박서은 2025-06-13 15:16:23 +09:00
parent cc871cddab
commit 69964d970c
9 changed files with 75 additions and 15 deletions

View File

@ -1,5 +1,6 @@
package com.won.smarketing.store.dto; package com.won.smarketing.store.dto;
import com.won.smarketing.store.entity.Sales;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
@ -7,6 +8,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
/** /**
* 매출 응답 DTO * 매출 응답 DTO
@ -33,4 +35,7 @@ public class SalesResponse {
@Schema(description = "목표 매출 대비 달성율 (%)", example = "85.2") @Schema(description = "목표 매출 대비 달성율 (%)", example = "85.2")
private BigDecimal goalAchievementRate; private BigDecimal goalAchievementRate;
@Schema(description = "일년 동안의 매출액")
private List<Sales> yearSales;
} }

View File

@ -48,7 +48,11 @@ public class StoreCreateRequest {
@Schema(description = "SNS 계정 정보", example = "인스타그램: @mystore") @Schema(description = "SNS 계정 정보", example = "인스타그램: @mystore")
@Size(max = 500, message = "SNS 계정 정보는 500자 이하여야 합니다") @Size(max = 500, message = "SNS 계정 정보는 500자 이하여야 합니다")
private String snsAccounts; private String instaAccounts;
@Size(max = 500, message = "SNS 계정 정보는 500자 이하여야 합니다")
@Schema(description = "블로그 계정 정보", example = "블로그: mystore")
private String blogAccounts;
@Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.") @Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.")
@Size(max = 1000, message = "매장 설명은 1000자 이하여야 합니다") @Size(max = 1000, message = "매장 설명은 1000자 이하여야 합니다")

View File

@ -47,8 +47,11 @@ public class StoreResponse {
@Schema(description = "좌석 수", example = "20") @Schema(description = "좌석 수", example = "20")
private Integer seatCount; private Integer seatCount;
@Schema(description = "SNS 계정 정보", example = "인스타그램: @mystore") @Schema(description = "블로그 계정 정보", example = "블로그: mystore")
private String snsAccounts; private String blogAccounts;
@Schema(description = "인스타 계정 정보", example = "인스타그램: @mystore")
private String instaAccounts;
@Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.") @Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.")
private String description; private String description;

View File

@ -43,9 +43,13 @@ public class StoreUpdateRequest {
@Schema(description = "좌석 수", example = "20") @Schema(description = "좌석 수", example = "20")
private Integer seatCount; private Integer seatCount;
@Schema(description = "SNS 계정 정보", example = "인스타그램: @mystore") @Schema(description = "인스타 계정 정보", example = "인스타그램: @mystore")
@Size(max = 500, message = "인스타 계정 정보는 500자 이하여야 합니다")
private String instaAccounts;
@Schema(description = "블로그 계정 정보", example = "블로그: mystore")
@Size(max = 500, message = "SNS 계정 정보는 500자 이하여야 합니다") @Size(max = 500, message = "SNS 계정 정보는 500자 이하여야 합니다")
private String snsAccounts; private String blogAccounts;
@Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.") @Schema(description = "매장 설명", example = "따뜻한 분위기의 동네 카페입니다.")
@Size(max = 1000, message = "매장 설명은 1000자 이하여야 합니다") @Size(max = 1000, message = "매장 설명은 1000자 이하여야 합니다")

View File

@ -54,8 +54,11 @@ public class Store {
@Column(name = "seat_count") @Column(name = "seat_count")
private Integer seatCount; private Integer seatCount;
@Column(name = "sns_accounts", length = 500) @Column(name = "insta_accounts", length = 500)
private String snsAccounts; private String instaAccounts;
@Column(name = "blog_accounts", length = 500)
private String blogAccounts;
@Column(name = "description", length = 1000) @Column(name = "description", length = 1000)
private String description; private String description;
@ -81,12 +84,13 @@ public class Store {
* @param businessHours 영업시간 * @param businessHours 영업시간
* @param closedDays 휴무일 * @param closedDays 휴무일
* @param seatCount 좌석 * @param seatCount 좌석
* @param snsAccounts SNS 계정 정보 * @param instaAccounts SNS 계정 정보
* @param blogAccounts SNS 계정 정보
* @param description 설명 * @param description 설명
*/ */
public void updateStore(String storeName, String businessType, String address, public void updateStore(String storeName, String businessType, String address,
String phoneNumber, String businessHours, String closedDays, String phoneNumber, String businessHours, String closedDays,
Integer seatCount, String snsAccounts, String description) { Integer seatCount, String instaAccounts, String blogAccounts, String description) {
if (storeName != null && !storeName.trim().isEmpty()) { if (storeName != null && !storeName.trim().isEmpty()) {
this.storeName = storeName; this.storeName = storeName;
} }
@ -100,7 +104,8 @@ public class Store {
this.businessHours = businessHours; this.businessHours = businessHours;
this.closedDays = closedDays; this.closedDays = closedDays;
this.seatCount = seatCount; this.seatCount = seatCount;
this.snsAccounts = snsAccounts; this.instaAccounts = instaAccounts;
this.blogAccounts = blogAccounts;
this.description = description; this.description = description;
} }

View File

@ -8,7 +8,9 @@ import org.springframework.stereotype.Repository;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 매출 정보 데이터 접근을 위한 Repository * 매출 정보 데이터 접근을 위한 Repository
@ -64,4 +66,20 @@ public interface SalesRepository extends JpaRepository<Sales, Long> {
"AND EXTRACT(YEAR FROM sales_date) = EXTRACT(YEAR FROM CURRENT_DATE) " + "AND EXTRACT(YEAR FROM sales_date) = EXTRACT(YEAR FROM CURRENT_DATE) " +
"AND EXTRACT(MONTH FROM sales_date) = EXTRACT(MONTH FROM CURRENT_DATE)", nativeQuery = true) "AND EXTRACT(MONTH FROM sales_date) = EXTRACT(MONTH FROM CURRENT_DATE)", nativeQuery = true)
BigDecimal findMonthSalesByStoreIdNative(@Param("storeId") Long storeId); BigDecimal findMonthSalesByStoreIdNative(@Param("storeId") Long storeId);
/**
* 매장의 최근 365일 매출 데이터 조회 (날짜와 함께)
*
* @param storeId 매장 ID
* @return 최근 365일 매출 데이터 (날짜 오름차순)
*/
@Query("SELECT s FROM Sales s " +
"WHERE s.storeId = :storeId " +
"AND s.salesDate >= :startDate " +
"AND s.salesDate <= :endDate " +
"ORDER BY s.salesDate ASC")
List<Sales> findSalesDataLast365Days(
@Param("storeId") Long storeId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
} }

View File

@ -176,7 +176,8 @@ public class BlobStorageServiceImpl implements BlobStorageService {
.businessHours(store.getBusinessHours()) .businessHours(store.getBusinessHours())
.closedDays(store.getClosedDays()) .closedDays(store.getClosedDays())
.seatCount(store.getSeatCount()) .seatCount(store.getSeatCount())
.snsAccounts(store.getSnsAccounts()) .blogAccounts(store.getBlogAccounts())
.instaAccounts(store.getInstaAccounts())
.storeImage(fileUrl) .storeImage(fileUrl)
.description(store.getDescription()) .description(store.getDescription())
.createdAt(store.getCreatedAt()) .createdAt(store.getCreatedAt())

View File

@ -11,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 매출 관리 서비스 구현체 * 매출 관리 서비스 구현체
@ -22,7 +23,6 @@ import java.util.List;
public class SalesServiceImpl implements SalesService { public class SalesServiceImpl implements SalesService {
private final SalesRepository salesRepository; private final SalesRepository salesRepository;
private final StoreRepository storeRepository;
/** /**
* 매출 정보 조회 * 매출 정보 조회
@ -43,9 +43,12 @@ public class SalesServiceImpl implements SalesService {
// 전일 대비 매출 변화량 계산 // 전일 대비 매출 변화량 계산
BigDecimal previousDayComparison = todaySales.subtract(yesterdaySales); BigDecimal previousDayComparison = todaySales.subtract(yesterdaySales);
//오늘로부터 1년 전까지의 매출 리스트
return SalesResponse.builder() return SalesResponse.builder()
.todaySales(todaySales) .todaySales(todaySales)
.monthSales(monthSales) .monthSales(monthSales)
.yearSales(getSalesAmountListLast365Days(storeId))
.previousDayComparison(previousDayComparison) .previousDayComparison(previousDayComparison)
.build(); .build();
} }
@ -80,4 +83,18 @@ public class SalesServiceImpl implements SalesService {
.map(Sales::getSalesAmount) .map(Sales::getSalesAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add); .reduce(BigDecimal.ZERO, BigDecimal::add);
} }
/**
* 최근 365일 매출 금액 리스트 조회
*
* @param storeId 매장 ID
* @return 최근 365일 매출 금액 리스트
*/
private List<Sales> getSalesAmountListLast365Days(Long storeId) {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(365);
// Sales 엔티티 전체를 조회하는 메서드 사용
return salesRepository.findSalesDataLast365Days(storeId, startDate, endDate);
}
} }

View File

@ -57,7 +57,8 @@ public class StoreServiceImpl implements StoreService {
.businessHours(request.getBusinessHours()) .businessHours(request.getBusinessHours())
.closedDays(request.getClosedDays()) .closedDays(request.getClosedDays())
.seatCount(request.getSeatCount()) .seatCount(request.getSeatCount())
.snsAccounts(request.getSnsAccounts()) .blogAccounts(request.getBlogAccounts())
.instaAccounts(request.getInstaAccounts())
.description(request.getDescription()) .description(request.getDescription())
.build(); .build();
@ -126,7 +127,8 @@ public class StoreServiceImpl implements StoreService {
request.getBusinessHours(), request.getBusinessHours(),
request.getClosedDays(), request.getClosedDays(),
request.getSeatCount(), request.getSeatCount(),
request.getSnsAccounts(), request.getInstaAccounts(),
request.getBlogAccounts(),
request.getDescription() request.getDescription()
); );
@ -152,7 +154,8 @@ public class StoreServiceImpl implements StoreService {
.businessHours(store.getBusinessHours()) .businessHours(store.getBusinessHours())
.closedDays(store.getClosedDays()) .closedDays(store.getClosedDays())
.seatCount(store.getSeatCount()) .seatCount(store.getSeatCount())
.snsAccounts(store.getSnsAccounts()) .blogAccounts(store.getBlogAccounts())
.instaAccounts(store.getInstaAccounts())
.description(store.getDescription()) .description(store.getDescription())
.createdAt(store.getCreatedAt()) .createdAt(store.getCreatedAt())
.updatedAt(store.getUpdatedAt()) .updatedAt(store.getUpdatedAt())