mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2025-12-06 07:06:24 +00:00
Merge branch 'main' of https://github.com/won-ktds/smarketing-backend
This commit is contained in:
commit
8679eba53e
@ -1,5 +1,9 @@
|
|||||||
package com.won.smarketing.store.config;
|
package com.won.smarketing.store.config;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
|
|
||||||
@ -10,7 +14,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableJpaAuditing
|
@EnableJpaAuditing
|
||||||
public class JpaConfig {
|
public class JpaConfig {
|
||||||
}리는 50자 이하여야 합니다")
|
|
||||||
private String category;
|
private String category;
|
||||||
|
|
||||||
@Schema(description = "가격", example = "4500", required = true)
|
@Schema(description = "가격", example = "4500", required = true)
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매장 관리를 위한 REST API 컨트롤러
|
* 매장 관리를 위한 REST API 컨트롤러
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import javax.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
import javax.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 메뉴 수정 요청 DTO
|
* 메뉴 수정 요청 DTO
|
||||||
|
|||||||
@ -7,6 +7,8 @@ import org.springframework.data.repository.query.Param;
|
|||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매출 정보 데이터 접근을 위한 Repository
|
* 매출 정보 데이터 접근을 위한 Repository
|
||||||
@ -14,31 +16,52 @@ import java.math.BigDecimal;
|
|||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public interface SalesRepository extends JpaRepository<Sales, Long> {
|
public interface SalesRepository extends JpaRepository<Sales, Long> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매장의 오늘 매출 조회
|
* 매장의 특정 날짜 매출 조회
|
||||||
*
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @param salesDate 매출 날짜
|
||||||
|
* @return 해당 날짜 매출 목록
|
||||||
|
*/
|
||||||
|
List<Sales> findByStoreIdAndSalesDate(Long storeId, LocalDate salesDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 매장의 특정 기간 매출 조회
|
||||||
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @param startDate 시작 날짜
|
||||||
|
* @param endDate 종료 날짜
|
||||||
|
* @return 해당 기간 매출 목록
|
||||||
|
*/
|
||||||
|
List<Sales> findByStoreIdAndSalesDateBetween(Long storeId, LocalDate startDate, LocalDate endDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 매장의 오늘 매출 조회 (네이티브 쿼리)
|
||||||
|
*
|
||||||
* @param storeId 매장 ID
|
* @param storeId 매장 ID
|
||||||
* @return 오늘 매출
|
* @return 오늘 매출
|
||||||
*/
|
*/
|
||||||
@Query("SELECT COALESCE(SUM(s.salesAmount), 0) FROM Sales s WHERE s.storeId = :storeId AND s.salesDate = CURRENT_DATE")
|
@Query(value = "SELECT COALESCE(SUM(sales_amount), 0) FROM sales WHERE store_id = :storeId AND sales_date = CURRENT_DATE", nativeQuery = true)
|
||||||
BigDecimal findTodaySalesByStoreId(@Param("storeId") Long storeId);
|
BigDecimal findTodaySalesByStoreIdNative(@Param("storeId") Long storeId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매장의 이번 달 매출 조회
|
* 매장의 어제 매출 조회 (네이티브 쿼리)
|
||||||
*
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @return 어제 매출
|
||||||
|
*/
|
||||||
|
@Query(value = "SELECT COALESCE(SUM(sales_amount), 0) FROM sales WHERE store_id = :storeId AND sales_date = CURRENT_DATE - INTERVAL '1 day'", nativeQuery = true)
|
||||||
|
BigDecimal findYesterdaySalesByStoreIdNative(@Param("storeId") Long storeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 매장의 이번 달 매출 조회 (네이티브 쿼리)
|
||||||
|
*
|
||||||
* @param storeId 매장 ID
|
* @param storeId 매장 ID
|
||||||
* @return 이번 달 매출
|
* @return 이번 달 매출
|
||||||
*/
|
*/
|
||||||
@Query("SELECT COALESCE(SUM(s.salesAmount), 0) FROM Sales s WHERE s.storeId = :storeId AND YEAR(s.salesDate) = YEAR(CURRENT_DATE) AND MONTH(s.salesDate) = MONTH(CURRENT_DATE)")
|
@Query(value = "SELECT COALESCE(SUM(sales_amount), 0) FROM sales WHERE store_id = :storeId " +
|
||||||
BigDecimal findMonthSalesByStoreId(@Param("storeId") Long storeId);
|
"AND EXTRACT(YEAR FROM sales_date) = EXTRACT(YEAR FROM CURRENT_DATE) " +
|
||||||
|
"AND EXTRACT(MONTH FROM sales_date) = EXTRACT(MONTH FROM CURRENT_DATE)", nativeQuery = true)
|
||||||
/**
|
BigDecimal findMonthSalesByStoreIdNative(@Param("storeId") Long storeId);
|
||||||
* 매장의 전일 대비 매출 변화량 조회
|
}
|
||||||
*
|
|
||||||
* @param storeId 매장 ID
|
|
||||||
* @return 전일 대비 매출 변화량
|
|
||||||
*/
|
|
||||||
@Query("SELECT COALESCE((SELECT SUM(s1.salesAmount) FROM Sales s1 WHERE s1.storeId = :storeId AND s1.salesDate = CURRENT_DATE) - (SELECT SUM(s2.salesAmount) FROM Sales s2 WHERE s2.storeId = :storeId AND s2.salesDate = CURRENT_DATE - 1), 0)")
|
|
||||||
BigDecimal findPreviousDayComparisonByStoreId(@Param("storeId") Long storeId);
|
|
||||||
}
|
|
||||||
@ -83,7 +83,7 @@ public class MenuServiceImpl implements MenuService {
|
|||||||
.orElseThrow(() -> new BusinessException(ErrorCode.MENU_NOT_FOUND));
|
.orElseThrow(() -> new BusinessException(ErrorCode.MENU_NOT_FOUND));
|
||||||
|
|
||||||
// 메뉴 정보 업데이트
|
// 메뉴 정보 업데이트
|
||||||
menu.updateMenuInfo(
|
menu.updateMenu(
|
||||||
request.getMenuName(),
|
request.getMenuName(),
|
||||||
request.getCategory(),
|
request.getCategory(),
|
||||||
request.getPrice(),
|
request.getPrice(),
|
||||||
|
|||||||
@ -1,60 +1,84 @@
|
|||||||
package com.won.smarketing.store.service;
|
package com.won.smarketing.store.service;
|
||||||
|
|
||||||
import com.won.smarketing.store.dto.SalesResponse;
|
import com.won.smarketing.store.dto.SalesResponse;
|
||||||
|
import com.won.smarketing.store.entity.Sales;
|
||||||
|
import com.won.smarketing.store.repository.SalesRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매출 서비스 구현체
|
* 매출 관리 서비스 구현체
|
||||||
* 매출 조회 기능 구현 (현재는 Mock 데이터)
|
* 매출 조회 기능 구현
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public class SalesServiceImpl implements SalesService {
|
public class SalesServiceImpl implements SalesService {
|
||||||
|
|
||||||
|
private final SalesRepository salesRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 매출 정보 조회
|
* 매출 정보 조회
|
||||||
* 현재는 Mock 데이터를 반환 (실제로는 매출 데이터 조회 로직 필요)
|
*
|
||||||
*
|
* @return 매출 정보 (오늘, 월간, 전일 대비)
|
||||||
* @return 매출 정보
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SalesResponse getSales() {
|
public SalesResponse getSales() {
|
||||||
log.info("매출 정보 조회");
|
// TODO: 현재는 더미 데이터 반환, 실제로는 현재 로그인한 사용자의 매장 ID를 사용해야 함
|
||||||
|
Long storeId = 1L; // 임시로 설정
|
||||||
// Mock 데이터 (실제로는 데이터베이스에서 조회)
|
|
||||||
BigDecimal todaySales = new BigDecimal("150000");
|
// 오늘 매출 계산
|
||||||
BigDecimal monthSales = new BigDecimal("4500000");
|
BigDecimal todaySales = calculateSalesByDate(storeId, LocalDate.now());
|
||||||
BigDecimal yesterdaySales = new BigDecimal("125000");
|
|
||||||
BigDecimal targetSales = new BigDecimal("176000");
|
// 이번 달 매출 계산
|
||||||
|
BigDecimal monthSales = calculateMonthSales(storeId);
|
||||||
// 전일 대비 변화 계산
|
|
||||||
|
// 어제 매출 계산
|
||||||
|
BigDecimal yesterdaySales = calculateSalesByDate(storeId, LocalDate.now().minusDays(1));
|
||||||
|
|
||||||
|
// 전일 대비 매출 변화량 계산
|
||||||
BigDecimal previousDayComparison = todaySales.subtract(yesterdaySales);
|
BigDecimal previousDayComparison = todaySales.subtract(yesterdaySales);
|
||||||
BigDecimal previousDayChangeRate = yesterdaySales.compareTo(BigDecimal.ZERO) > 0
|
|
||||||
? previousDayComparison.divide(yesterdaySales, 4, RoundingMode.HALF_UP)
|
|
||||||
.multiply(new BigDecimal("100"))
|
|
||||||
: BigDecimal.ZERO;
|
|
||||||
|
|
||||||
// 목표 대비 달성률 계산
|
|
||||||
BigDecimal goalAchievementRate = targetSales.compareTo(BigDecimal.ZERO) > 0
|
|
||||||
? todaySales.divide(targetSales, 4, RoundingMode.HALF_UP)
|
|
||||||
.multiply(new BigDecimal("100"))
|
|
||||||
: BigDecimal.ZERO;
|
|
||||||
|
|
||||||
return SalesResponse.builder()
|
return SalesResponse.builder()
|
||||||
.todaySales(todaySales)
|
.todaySales(todaySales)
|
||||||
.monthSales(monthSales)
|
.monthSales(monthSales)
|
||||||
.previousDayComparison(previousDayComparison)
|
.previousDayComparison(previousDayComparison)
|
||||||
.previousDayChangeRate(previousDayChangeRate)
|
|
||||||
.goalAchievementRate(goalAchievementRate)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 날짜의 매출 계산
|
||||||
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @param date 날짜
|
||||||
|
* @return 해당 날짜 매출
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateSalesByDate(Long storeId, LocalDate date) {
|
||||||
|
List<Sales> salesList = salesRepository.findByStoreIdAndSalesDate(storeId, date);
|
||||||
|
return salesList.stream()
|
||||||
|
.map(Sales::getSalesAmount)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 이번 달 매출 계산
|
||||||
|
*
|
||||||
|
* @param storeId 매장 ID
|
||||||
|
* @return 이번 달 매출
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateMonthSales(Long storeId) {
|
||||||
|
LocalDate now = LocalDate.now();
|
||||||
|
LocalDate startOfMonth = now.withDayOfMonth(1);
|
||||||
|
LocalDate endOfMonth = now.withDayOfMonth(now.lengthOfMonth());
|
||||||
|
|
||||||
|
List<Sales> salesList = salesRepository.findByStoreIdAndSalesDateBetween(storeId, startOfMonth, endOfMonth);
|
||||||
|
return salesList.stream()
|
||||||
|
.map(Sales::getSalesAmount)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,31 +1,33 @@
|
|||||||
server:
|
server:
|
||||||
port: ${SERVER_PORT:8082}
|
port: ${SERVER_PORT:8082}
|
||||||
servlet:
|
|
||||||
context-path: /
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: store-service
|
name: store-service
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:storedb}
|
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:StoreDB}
|
||||||
username: ${POSTGRES_USER:postgres}
|
username: ${POSTGRES_USER:postgres}
|
||||||
password: ${POSTGRES_PASSWORD:postgres}
|
password: ${POSTGRES_PASSWORD:postgres}
|
||||||
|
driver-class-name: org.postgresql.Driver
|
||||||
jpa:
|
jpa:
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: ${JPA_DDL_AUTO:update}
|
ddl-auto: ${DDL_AUTO:update}
|
||||||
show-sql: ${JPA_SHOW_SQL:true}
|
show-sql: ${SHOW_SQL:true}
|
||||||
properties:
|
properties:
|
||||||
hibernate:
|
hibernate:
|
||||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||||
format_sql: true
|
format_sql: true
|
||||||
|
data:
|
||||||
springdoc:
|
redis:
|
||||||
swagger-ui:
|
host: ${REDIS_HOST:localhost}
|
||||||
path: /swagger-ui.html
|
port: ${REDIS_PORT:6379}
|
||||||
operations-sorter: method
|
password: ${REDIS_PASSWORD:}
|
||||||
api-docs:
|
|
||||||
path: /api-docs
|
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
com.won.smarketing.store: ${LOG_LEVEL:DEBUG}
|
com.won.smarketing.store: ${LOG_LEVEL:DEBUG}
|
||||||
|
|
||||||
|
jwt:
|
||||||
|
secret: ${JWT_SECRET:mySecretKeyForJWTTokenGenerationAndValidation123456789}
|
||||||
|
access-token-validity: ${JWT_ACCESS_VALIDITY:3600000}
|
||||||
|
refresh-token-validity: ${JWT_REFRESH_VALIDITY:604800000}
|
||||||
Loading…
x
Reference in New Issue
Block a user