mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-06-13 04:49:10 +00:00
add : init project
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
package com.won.smarketing.store;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
/**
|
||||
* 매장 서비스 메인 애플리케이션 클래스
|
||||
* Spring Boot 애플리케이션의 진입점
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {"com.won.smarketing.store", "com.won.smarketing.common"})
|
||||
@EntityScan(basePackages = {"com.won.smarketing.store.entity"})
|
||||
@EnableJpaRepositories(basePackages = {"com.won.smarketing.store.repository"})
|
||||
public class StoreServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StoreServiceApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.won.smarketing.store.controller;
|
||||
|
||||
import com.won.smarketing.common.dto.ApiResponse;
|
||||
import com.won.smarketing.store.dto.MenuCreateRequest;
|
||||
import com.won.smarketing.store.dto.MenuResponse;
|
||||
import com.won.smarketing.store.dto.MenuUpdateRequest;
|
||||
import com.won.smarketing.store.service.MenuService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 메뉴 관리를 위한 REST API 컨트롤러
|
||||
* 메뉴 등록, 조회, 수정, 삭제 기능 제공
|
||||
*/
|
||||
@Tag(name = "메뉴 관리", description = "메뉴 정보 관리 API")
|
||||
@RestController
|
||||
@RequestMapping("/api/menu")
|
||||
@RequiredArgsConstructor
|
||||
public class MenuController {
|
||||
|
||||
private final MenuService menuService;
|
||||
|
||||
/**
|
||||
* 메뉴 정보 등록
|
||||
*
|
||||
* @param request 메뉴 등록 요청 정보
|
||||
* @return 등록된 메뉴 정보
|
||||
*/
|
||||
@Operation(summary = "메뉴 등록", description = "새로운 메뉴를 등록합니다.")
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<ApiResponse<MenuResponse>> register(@Valid @RequestBody MenuCreateRequest request) {
|
||||
MenuResponse response = menuService.register(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "메뉴가 성공적으로 등록되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 목록 조회
|
||||
*
|
||||
* @param category 메뉴 카테고리 (선택사항)
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
@Operation(summary = "메뉴 목록 조회", description = "메뉴 목록을 조회합니다. 카테고리별 필터링 가능합니다.")
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<MenuResponse>>> getMenus(
|
||||
@Parameter(description = "메뉴 카테고리")
|
||||
@RequestParam(required = false) String category) {
|
||||
List<MenuResponse> response = menuService.getMenus(category);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 정보 수정
|
||||
*
|
||||
* @param menuId 수정할 메뉴 ID
|
||||
* @param request 메뉴 수정 요청 정보
|
||||
* @return 수정된 메뉴 정보
|
||||
*/
|
||||
@Operation(summary = "메뉴 수정", description = "메뉴 정보를 수정합니다.")
|
||||
@PutMapping("/{menuId}")
|
||||
public ResponseEntity<ApiResponse<MenuResponse>> updateMenu(
|
||||
@Parameter(description = "메뉴 ID", required = true)
|
||||
@PathVariable Long menuId,
|
||||
@Valid @RequestBody MenuUpdateRequest request) {
|
||||
MenuResponse response = menuService.updateMenu(menuId, request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "메뉴가 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 삭제
|
||||
*
|
||||
* @param menuId 삭제할 메뉴 ID
|
||||
* @return 삭제 성공 응답
|
||||
*/
|
||||
@Operation(summary = "메뉴 삭제", description = "메뉴를 삭제합니다.")
|
||||
@DeleteMapping("/{menuId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMenu(
|
||||
@Parameter(description = "메뉴 ID", required = true)
|
||||
@PathVariable Long menuId) {
|
||||
menuService.deleteMenu(menuId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "메뉴가 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.won.smarketing.store.controller;
|
||||
|
||||
import com.won.smarketing.common.dto.ApiResponse;
|
||||
import com.won.smarketing.store.dto.SalesResponse;
|
||||
import com.won.smarketing.store.service.SalesService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 매출 정보를 위한 REST API 컨트롤러
|
||||
* 매출 조회 기능 제공
|
||||
*/
|
||||
@Tag(name = "매출 관리", description = "매출 정보 조회 API")
|
||||
@RestController
|
||||
@RequestMapping("/api/sales")
|
||||
@RequiredArgsConstructor
|
||||
public class SalesController {
|
||||
|
||||
private final SalesService salesService;
|
||||
|
||||
/**
|
||||
* 매출 정보 조회
|
||||
*
|
||||
* @return 매출 정보 (오늘, 월간, 전일 대비)
|
||||
*/
|
||||
@Operation(summary = "매출 조회", description = "오늘 매출, 월간 매출, 전일 대비 매출 정보를 조회합니다.")
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<SalesResponse>> getSales() {
|
||||
SalesResponse response = salesService.getSales();
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.won.smarketing.store.controller;
|
||||
|
||||
import com.won.smarketing.common.dto.ApiResponse;
|
||||
import com.won.smarketing.store.dto.StoreCreateRequest;
|
||||
import com.won.smarketing.store.dto.StoreResponse;
|
||||
import com.won.smarketing.store.dto.StoreUpdateRequest;
|
||||
import com.won.smarketing.store.service.StoreService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 매장 관리를 위한 REST API 컨트롤러
|
||||
* 매장 등록, 조회, 수정 기능 제공
|
||||
*/
|
||||
@Tag(name = "매장 관리", description = "매장 정보 관리 API")
|
||||
@RestController
|
||||
@RequestMapping("/api/store")
|
||||
@RequiredArgsConstructor
|
||||
public class StoreController {
|
||||
|
||||
private final StoreService storeService;
|
||||
|
||||
/**
|
||||
* 매장 정보 등록
|
||||
*
|
||||
* @param request 매장 등록 요청 정보
|
||||
* @return 등록된 매장 정보
|
||||
*/
|
||||
@Operation(summary = "매장 등록", description = "새로운 매장 정보를 등록합니다.")
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<ApiResponse<StoreResponse>> register(@Valid @RequestBody StoreCreateRequest request) {
|
||||
StoreResponse response = storeService.register(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "매장이 성공적으로 등록되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 매장 정보 조회
|
||||
*
|
||||
* @param storeId 조회할 매장 ID
|
||||
* @return 매장 정보
|
||||
*/
|
||||
@Operation(summary = "매장 조회", description = "매장 ID로 매장 정보를 조회합니다.")
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<StoreResponse>> getStore(
|
||||
@Parameter(description = "매장 ID", required = true)
|
||||
@RequestParam String storeId) {
|
||||
StoreResponse response = storeService.getStore(storeId);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* 매장 정보 수정
|
||||
*
|
||||
* @param storeId 수정할 매장 ID
|
||||
* @param request 매장 수정 요청 정보
|
||||
* @return 수정된 매장 정보
|
||||
*/
|
||||
@Operation(summary = "매장 수정", description = "매장 정보를 수정합니다.")
|
||||
@PutMapping("/{storeId}")
|
||||
public ResponseEntity<ApiResponse<StoreResponse>> updateStore(
|
||||
@Parameter(description = "매장 ID", required = true)
|
||||
@PathVariable Long storeId,
|
||||
@Valid @RequestBody StoreUpdateRequest request) {
|
||||
StoreResponse response = storeService.updateStore(storeId, request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "매장 정보가 성공적으로 수정되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 메뉴 등록 요청 DTO
|
||||
* 메뉴 등록 시 필요한 정보를 담는 데이터 전송 객체
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "메뉴 등록 요청 정보")
|
||||
public class MenuCreateRequest {
|
||||
|
||||
@Schema(description = "매장 ID", example = "1", required = true)
|
||||
@NotNull(message = "매장 ID는 필수입니다.")
|
||||
private Long storeId;
|
||||
|
||||
@Schema(description = "메뉴명", example = "아메리카노", required = true)
|
||||
@NotBlank(message = "메뉴명은 필수입니다.")
|
||||
@Size(max = 200, message = "메뉴명은 200자 이하여야 합니다.")
|
||||
private String menuName;
|
||||
|
||||
@Schema(description = "메뉴 카테고리", example = "커피", required = true)
|
||||
@NotBlank(message = "카테고리는 필수입니다.")
|
||||
@Size(max = 100, message = "카테고리는 100자 이하여야 합니다.")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "가격", example = "4500", required = true)
|
||||
@NotNull(message = "가격은 필수입니다.")
|
||||
@Min(value = 0, message = "가격은 0 이상이어야 합니다.")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "메뉴 설명", example = "진한 원두의 깊은 맛")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "메뉴 이미지 URL", example = "https://example.com/americano.jpg")
|
||||
private String image;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 메뉴 정보 응답 DTO
|
||||
* 메뉴 정보 조회/등록/수정 시 반환되는 데이터
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "메뉴 정보 응답")
|
||||
public class MenuResponse {
|
||||
|
||||
@Schema(description = "메뉴 ID", example = "1")
|
||||
private Long menuId;
|
||||
|
||||
@Schema(description = "메뉴명", example = "아메리카노")
|
||||
private String menuName;
|
||||
|
||||
@Schema(description = "메뉴 카테고리", example = "커피")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "가격", example = "4500")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "메뉴 설명", example = "진한 원두의 깊은 맛")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "메뉴 이미지 URL", example = "https://example.com/americano.jpg")
|
||||
private String image;
|
||||
|
||||
@Schema(description = "등록 시각")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Schema(description = "수정 시각")
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 메뉴 수정 요청 DTO
|
||||
* 메뉴 정보 수정 시 필요한 정보를 담는 데이터 전송 객체
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "메뉴 수정 요청 정보")
|
||||
public class MenuUpdateRequest {
|
||||
|
||||
@Schema(description = "메뉴명", example = "아메리카노")
|
||||
@Size(max = 200, message = "메뉴명은 200자 이하여야 합니다.")
|
||||
private String menuName;
|
||||
|
||||
@Schema(description = "메뉴 카테고리", example = "커피")
|
||||
@Size(max = 100, message = "카테고리는 100자 이하여야 합니다.")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "가격", example = "4500")
|
||||
@Min(value = 0, message = "가격은 0 이상이어야 합니다.")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "메뉴 설명", example = "진한 원두의 깊은 맛")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "메뉴 이미지 URL", example = "https://example.com/americano.jpg")
|
||||
private String image;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 매출 정보 응답 DTO
|
||||
* 오늘 매출, 월간 매출, 전일 대비 매출 정보
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "매출 정보 응답")
|
||||
public class SalesResponse {
|
||||
|
||||
@Schema(description = "오늘 매출", example = "150000")
|
||||
private BigDecimal todaySales;
|
||||
|
||||
@Schema(description = "이번 달 매출", example = "3200000")
|
||||
private BigDecimal monthSales;
|
||||
|
||||
@Schema(description = "전일 대비 매출 변화량", example = "25000")
|
||||
private BigDecimal previousDayComparison;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 매장 등록 요청 DTO
|
||||
* 매장 등록 시 필요한 정보를 담는 데이터 전송 객체
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "매장 등록 요청 정보")
|
||||
public class StoreCreateRequest {
|
||||
|
||||
@Schema(description = "매장 소유자 사용자 ID", example = "testuser", required = true)
|
||||
@NotBlank(message = "사용자 ID는 필수입니다.")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "매장명", example = "맛있는 카페", required = true)
|
||||
@NotBlank(message = "매장명은 필수입니다.")
|
||||
@Size(max = 200, message = "매장명은 200자 이하여야 합니다.")
|
||||
private String storeName;
|
||||
|
||||
@Schema(description = "매장 이미지 URL", example = "https://example.com/store.jpg")
|
||||
private String storeImage;
|
||||
|
||||
@Schema(description = "업종", example = "카페", required = true)
|
||||
@NotBlank(message = "업종은 필수입니다.")
|
||||
@Size(max = 100, message = "업종은 100자 이하여야 합니다.")
|
||||
private String businessType;
|
||||
|
||||
@Schema(description = "매장 주소", example = "서울시 강남구 테헤란로 123", required = true)
|
||||
@NotBlank(message = "주소는 필수입니다.")
|
||||
@Size(max = 500, message = "주소는 500자 이하여야 합니다.")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "매장 전화번호", example = "02-1234-5678", required = true)
|
||||
@NotBlank(message = "전화번호는 필수입니다.")
|
||||
@Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "올바른 전화번호 형식이 아닙니다.")
|
||||
private String phoneNumber;
|
||||
|
||||
@Schema(description = "사업자 번호", example = "123-45-67890", required = true)
|
||||
@NotBlank(message = "사업자 번호는 필수입니다.")
|
||||
@Pattern(regexp = "^\\d{3}-\\d{2}-\\d{5}$", message = "사업자 번호 형식이 올바르지 않습니다.")
|
||||
private String businessNumber;
|
||||
|
||||
@Schema(description = "인스타그램 계정", example = "@mycafe")
|
||||
@Size(max = 100, message = "인스타그램 계정은 100자 이하여야 합니다.")
|
||||
private String instaAccount;
|
||||
|
||||
@Schema(description = "네이버 블로그 계정", example = "mycafe_blog")
|
||||
@Size(max = 100, message = "네이버 블로그 계정은 100자 이하여야 합니다.")
|
||||
private String naverBlogAccount;
|
||||
|
||||
@Schema(description = "오픈 시간", example = "09:00")
|
||||
@Pattern(regexp = "^\\d{2}:\\d{2}$", message = "올바른 시간 형식이 아닙니다. (HH:MM)")
|
||||
private String openTime;
|
||||
|
||||
@Schema(description = "마감 시간", example = "22:00")
|
||||
@Pattern(regexp = "^\\d{2}:\\d{2}$", message = "올바른 시간 형식이 아닙니다. (HH:MM)")
|
||||
private String closeTime;
|
||||
|
||||
@Schema(description = "휴무일", example = "매주 월요일")
|
||||
@Size(max = 100, message = "휴무일은 100자 이하여야 합니다.")
|
||||
private String closedDays;
|
||||
|
||||
@Schema(description = "좌석 수", example = "20")
|
||||
private Integer seatCount;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 매장 정보 응답 DTO
|
||||
* 매장 정보 조회/등록/수정 시 반환되는 데이터
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "매장 정보 응답")
|
||||
public class StoreResponse {
|
||||
|
||||
@Schema(description = "매장 ID", example = "1")
|
||||
private Long storeId;
|
||||
|
||||
@Schema(description = "매장명", example = "맛있는 카페")
|
||||
private String storeName;
|
||||
|
||||
@Schema(description = "매장 이미지 URL", example = "https://example.com/store.jpg")
|
||||
private String storeImage;
|
||||
|
||||
@Schema(description = "업종", example = "카페")
|
||||
private String businessType;
|
||||
|
||||
@Schema(description = "매장 주소", example = "서울시 강남구 테헤란로 123")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "매장 전화번호", example = "02-1234-5678")
|
||||
private String phoneNumber;
|
||||
|
||||
@Schema(description = "사업자 번호", example = "123-45-67890")
|
||||
private String businessNumber;
|
||||
|
||||
@Schema(description = "인스타그램 계정", example = "@mycafe")
|
||||
private String instaAccount;
|
||||
|
||||
@Schema(description = "네이버 블로그 계정", example = "mycafe_blog")
|
||||
private String naverBlogAccount;
|
||||
|
||||
@Schema(description = "오픈 시간", example = "09:00")
|
||||
private String openTime;
|
||||
|
||||
@Schema(description = "마감 시간", example = "22:00")
|
||||
private String closeTime;
|
||||
|
||||
@Schema(description = "휴무일", example = "매주 월요일")
|
||||
private String closedDays;
|
||||
|
||||
@Schema(description = "좌석 수", example = "20")
|
||||
private Integer seatCount;
|
||||
|
||||
@Schema(description = "등록 시각")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Schema(description = "수정 시각")
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.won.smarketing.store.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 매장 수정 요청 DTO
|
||||
* 매장 정보 수정 시 필요한 정보를 담는 데이터 전송 객체
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "매장 수정 요청 정보")
|
||||
public class StoreUpdateRequest {
|
||||
|
||||
@Schema(description = "매장명", example = "맛있는 카페")
|
||||
@Size(max = 200, message = "매장명은 200자 이하여야 합니다.")
|
||||
private String storeName;
|
||||
|
||||
@Schema(description = "매장 이미지 URL", example = "https://example.com/store.jpg")
|
||||
private String storeImage;
|
||||
|
||||
@Schema(description = "매장 주소", example = "서울시 강남구 테헤란로 123")
|
||||
@Size(max = 500, message = "주소는 500자 이하여야 합니다.")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "매장 전화번호", example = "02-1234-5678")
|
||||
@Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "올바른 전화번호 형식이 아닙니다.")
|
||||
private String phoneNumber;
|
||||
|
||||
@Schema(description = "인스타그램 계정", example = "@mycafe")
|
||||
@Size(max = 100, message = "인스타그램 계정은 100자 이하여야 합니다.")
|
||||
private String instaAccount;
|
||||
|
||||
@Schema(description = "네이버 블로그 계정", example = "mycafe_blog")
|
||||
@Size(max = 100, message = "네이버 블로그 계정은 100자 이하여야 합니다.")
|
||||
private String naverBlogAccount;
|
||||
|
||||
@Schema(description = "오픈 시간", example = "09:00")
|
||||
@Pattern(regexp = "^\\d{2}:\\d{2}$", message = "올바른 시간 형식이 아닙니다. (HH:MM)")
|
||||
private String openTime;
|
||||
|
||||
@Schema(description = "마감 시간", example = "22:00")
|
||||
@Pattern(regexp = "^\\d{2}:\\d{2}$", message = "올바른 시간 형식이 아닙니다. (HH:MM)")
|
||||
private String closeTime;
|
||||
|
||||
@Schema(description = "휴무일", example = "매주 월요일")
|
||||
@Size(max = 100, message = "휴무일은 100자 이하여야 합니다.")
|
||||
private String closedDays;
|
||||
|
||||
@Schema(description = "좌석 수", example = "20")
|
||||
private Integer seatCount;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.won.smarketing.store.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 메뉴 정보를 나타내는 엔티티
|
||||
* 메뉴명, 카테고리, 가격, 설명, 이미지 정보 저장
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "menus")
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class Menu {
|
||||
|
||||
/**
|
||||
* 메뉴 고유 식별자
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 매장 ID
|
||||
*/
|
||||
@Column(name = "store_id", nullable = false)
|
||||
private Long storeId;
|
||||
|
||||
/**
|
||||
* 메뉴명
|
||||
*/
|
||||
@Column(name = "menu_name", nullable = false, length = 200)
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 메뉴 카테고리
|
||||
*/
|
||||
@Column(name = "category", nullable = false, length = 100)
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 가격
|
||||
*/
|
||||
@Column(name = "price", nullable = false)
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 메뉴 설명
|
||||
*/
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 메뉴 이미지 URL
|
||||
*/
|
||||
@Column(name = "image", length = 500)
|
||||
private String image;
|
||||
|
||||
/**
|
||||
* 메뉴 등록 시각
|
||||
*/
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 메뉴 정보 수정 시각
|
||||
*/
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 엔티티 저장 전 실행되는 메서드
|
||||
* 생성 시각과 수정 시각을 현재 시각으로 설정
|
||||
*/
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 업데이트 전 실행되는 메서드
|
||||
* 수정 시각을 현재 시각으로 갱신
|
||||
*/
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 정보 업데이트 메서드
|
||||
*
|
||||
* @param menuName 메뉴명
|
||||
* @param category 카테고리
|
||||
* @param price 가격
|
||||
* @param description 설명
|
||||
* @param image 이미지 URL
|
||||
*/
|
||||
public void updateMenuInfo(String menuName, String category, Integer price, String description, String image) {
|
||||
this.menuName = menuName;
|
||||
this.category = category;
|
||||
this.price = price;
|
||||
this.description = description;
|
||||
this.image = image;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.won.smarketing.store.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 매출 정보를 나타내는 엔티티
|
||||
* 일별 매출 데이터 저장
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "sales")
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class Sales {
|
||||
|
||||
/**
|
||||
* 매출 고유 식별자
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 매장 ID
|
||||
*/
|
||||
@Column(name = "store_id", nullable = false)
|
||||
private Long storeId;
|
||||
|
||||
/**
|
||||
* 매출 날짜
|
||||
*/
|
||||
@Column(name = "sales_date", nullable = false)
|
||||
private LocalDate salesDate;
|
||||
|
||||
/**
|
||||
* 매출 금액
|
||||
*/
|
||||
@Column(name = "sales_amount", nullable = false, precision = 15, scale = 2)
|
||||
private BigDecimal salesAmount;
|
||||
|
||||
/**
|
||||
* 매출 등록 시각
|
||||
*/
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 엔티티 저장 전 실행되는 메서드
|
||||
* 생성 시각을 현재 시각으로 설정
|
||||
*/
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.won.smarketing.store.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 매장 정보를 나타내는 엔티티
|
||||
* 매장의 기본 정보, 운영 정보, SNS 계정 정보 저장
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "stores")
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class Store {
|
||||
|
||||
/**
|
||||
* 매장 고유 식별자
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 매장 소유자 사용자 ID
|
||||
*/
|
||||
@Column(name = "user_id", unique = true, nullable = false, length = 50)
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 매장명
|
||||
*/
|
||||
@Column(name = "store_name", nullable = false, length = 200)
|
||||
private String storeName;
|
||||
|
||||
/**
|
||||
* 매장 이미지 URL
|
||||
*/
|
||||
@Column(name = "store_image", length = 500)
|
||||
private String storeImage;
|
||||
|
||||
/**
|
||||
* 업종
|
||||
*/
|
||||
@Column(name = "business_type", nullable = false, length = 100)
|
||||
private String businessType;
|
||||
|
||||
/**
|
||||
* 매장 주소
|
||||
*/
|
||||
@Column(name = "address", nullable = false, length = 500)
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 매장 전화번호
|
||||
*/
|
||||
@Column(name = "phone_number", nullable = false, length = 20)
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 사업자 번호
|
||||
*/
|
||||
@Column(name = "business_number", nullable = false, length = 20)
|
||||
private String businessNumber;
|
||||
|
||||
/**
|
||||
* 인스타그램 계정
|
||||
*/
|
||||
@Column(name = "insta_account", length = 100)
|
||||
private String instaAccount;
|
||||
|
||||
/**
|
||||
* 네이버 블로그 계정
|
||||
*/
|
||||
@Column(name = "naver_blog_account", length = 100)
|
||||
private String naverBlogAccount;
|
||||
|
||||
/**
|
||||
* 오픈 시간
|
||||
*/
|
||||
@Column(name = "open_time", length = 10)
|
||||
private String openTime;
|
||||
|
||||
/**
|
||||
* 마감 시간
|
||||
*/
|
||||
@Column(name = "close_time", length = 10)
|
||||
private String closeTime;
|
||||
|
||||
/**
|
||||
* 휴무일
|
||||
*/
|
||||
@Column(name = "closed_days", length = 100)
|
||||
private String closedDays;
|
||||
|
||||
/**
|
||||
* 좌석 수
|
||||
*/
|
||||
@Column(name = "seat_count")
|
||||
private Integer seatCount;
|
||||
|
||||
/**
|
||||
* 매장 등록 시각
|
||||
*/
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 매장 정보 수정 시각
|
||||
*/
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 엔티티 저장 전 실행되는 메서드
|
||||
* 생성 시각과 수정 시각을 현재 시각으로 설정
|
||||
*/
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 업데이트 전 실행되는 메서드
|
||||
* 수정 시각을 현재 시각으로 갱신
|
||||
*/
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 매장 정보 업데이트 메서드
|
||||
*
|
||||
* @param storeName 매장명
|
||||
* @param storeImage 매장 이미지
|
||||
* @param address 주소
|
||||
* @param phoneNumber 전화번호
|
||||
* @param instaAccount 인스타그램 계정
|
||||
* @param naverBlogAccount 네이버 블로그 계정
|
||||
* @param openTime 오픈 시간
|
||||
* @param closeTime 마감 시간
|
||||
* @param closedDays 휴무일
|
||||
* @param seatCount 좌석 수
|
||||
*/
|
||||
public void updateStoreInfo(String storeName, String storeImage, String address, String phoneNumber,
|
||||
String instaAccount, String naverBlogAccount, String openTime, String closeTime,
|
||||
String closedDays, Integer seatCount) {
|
||||
this.storeName = storeName;
|
||||
this.storeImage = storeImage;
|
||||
this.address = address;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.instaAccount = instaAccount;
|
||||
this.naverBlogAccount = naverBlogAccount;
|
||||
this.openTime = openTime;
|
||||
this.closeTime = closeTime;
|
||||
this.closedDays = closedDays;
|
||||
this.seatCount = seatCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.won.smarketing.store.repository;
|
||||
|
||||
import com.won.smarketing.store.entity.Menu;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 메뉴 정보 데이터 접근을 위한 Repository
|
||||
* JPA를 사용한 메뉴 CRUD 작업 처리
|
||||
*/
|
||||
@Repository
|
||||
public interface MenuRepository extends JpaRepository<Menu, Long> {
|
||||
|
||||
/**
|
||||
* 카테고리별 메뉴 조회 (메뉴명 오름차순)
|
||||
*
|
||||
* @param category 메뉴 카테고리
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
List<Menu> findByCategoryOrderByMenuNameAsc(String category);
|
||||
|
||||
/**
|
||||
* 전체 메뉴 조회 (메뉴명 오름차순)
|
||||
*
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
List<Menu> findAllByOrderByMenuNameAsc();
|
||||
|
||||
/**
|
||||
* 매장별 메뉴 조회
|
||||
*
|
||||
* @param storeId 매장 ID
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
List<Menu> findByStoreId(Long storeId);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.won.smarketing.store.repository;
|
||||
|
||||
import com.won.smarketing.store.entity.Sales;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 매출 정보 데이터 접근을 위한 Repository
|
||||
* JPA를 사용한 매출 조회 작업 처리
|
||||
*/
|
||||
@Repository
|
||||
public interface SalesRepository extends JpaRepository<Sales, Long> {
|
||||
|
||||
/**
|
||||
* 매장의 오늘 매출 조회
|
||||
*
|
||||
* @param storeId 매장 ID
|
||||
* @return 오늘 매출
|
||||
*/
|
||||
@Query("SELECT COALESCE(SUM(s.salesAmount), 0) FROM Sales s WHERE s.storeId = :storeId AND s.salesDate = CURRENT_DATE")
|
||||
BigDecimal findTodaySalesByStoreId(@Param("storeId") Long storeId);
|
||||
|
||||
/**
|
||||
* 매장의 이번 달 매출 조회
|
||||
*
|
||||
* @param storeId 매장 ID
|
||||
* @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)")
|
||||
BigDecimal findMonthSalesByStoreId(@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);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.won.smarketing.store.repository;
|
||||
|
||||
import com.won.smarketing.store.entity.Store;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 매장 정보 데이터 접근을 위한 Repository
|
||||
* JPA를 사용한 매장 CRUD 작업 처리
|
||||
*/
|
||||
@Repository
|
||||
public interface StoreRepository extends JpaRepository<Store, Long> {
|
||||
|
||||
/**
|
||||
* 사용자 ID로 매장 조회
|
||||
*
|
||||
* @param userId 사용자 ID
|
||||
* @return 매장 정보
|
||||
*/
|
||||
Optional<Store> findByUserId(String userId);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.store.dto.MenuCreateRequest;
|
||||
import com.won.smarketing.store.dto.MenuResponse;
|
||||
import com.won.smarketing.store.dto.MenuUpdateRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 메뉴 관리 서비스 인터페이스
|
||||
* 메뉴 등록, 조회, 수정, 삭제 기능 정의
|
||||
*/
|
||||
public interface MenuService {
|
||||
|
||||
/**
|
||||
* 메뉴 정보 등록
|
||||
*
|
||||
* @param request 메뉴 등록 요청 정보
|
||||
* @return 등록된 메뉴 정보
|
||||
*/
|
||||
MenuResponse register(MenuCreateRequest request);
|
||||
|
||||
/**
|
||||
* 메뉴 목록 조회
|
||||
*
|
||||
* @param category 메뉴 카테고리 (선택사항)
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
List<MenuResponse> getMenus(String category);
|
||||
|
||||
/**
|
||||
* 메뉴 정보 수정
|
||||
*
|
||||
* @param menuId 수정할 메뉴 ID
|
||||
* @param request 메뉴 수정 요청 정보
|
||||
* @return 수정된 메뉴 정보
|
||||
*/
|
||||
MenuResponse updateMenu(Long menuId, MenuUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 메뉴 삭제
|
||||
*
|
||||
* @param menuId 삭제할 메뉴 ID
|
||||
*/
|
||||
void deleteMenu(Long menuId);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.common.exception.BusinessException;
|
||||
import com.won.smarketing.common.exception.ErrorCode;
|
||||
import com.won.smarketing.store.dto.MenuCreateRequest;
|
||||
import com.won.smarketing.store.dto.MenuResponse;
|
||||
import com.won.smarketing.store.dto.MenuUpdateRequest;
|
||||
import com.won.smarketing.store.entity.Menu;
|
||||
import com.won.smarketing.store.repository.MenuRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 메뉴 관리 서비스 구현체
|
||||
* 메뉴 등록, 조회, 수정, 삭제 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class MenuServiceImpl implements MenuService {
|
||||
|
||||
private final MenuRepository menuRepository;
|
||||
|
||||
/**
|
||||
* 메뉴 정보 등록
|
||||
*
|
||||
* @param request 메뉴 등록 요청 정보
|
||||
* @return 등록된 메뉴 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public MenuResponse register(MenuCreateRequest request) {
|
||||
// 메뉴 엔티티 생성 및 저장
|
||||
Menu menu = Menu.builder()
|
||||
.storeId(request.getStoreId())
|
||||
.menuName(request.getMenuName())
|
||||
.category(request.getCategory())
|
||||
.price(request.getPrice())
|
||||
.description(request.getDescription())
|
||||
.image(request.getImage())
|
||||
.build();
|
||||
|
||||
Menu savedMenu = menuRepository.save(menu);
|
||||
return toMenuResponse(savedMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 목록 조회
|
||||
*
|
||||
* @param category 메뉴 카테고리 (선택사항)
|
||||
* @return 메뉴 목록
|
||||
*/
|
||||
@Override
|
||||
public List<MenuResponse> getMenus(String category) {
|
||||
List<Menu> menus;
|
||||
|
||||
if (category != null && !category.trim().isEmpty()) {
|
||||
menus = menuRepository.findByCategoryOrderByMenuNameAsc(category);
|
||||
} else {
|
||||
menus = menuRepository.findAllByOrderByMenuNameAsc();
|
||||
}
|
||||
|
||||
return menus.stream()
|
||||
.map(this::toMenuResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 정보 수정
|
||||
*
|
||||
* @param menuId 수정할 메뉴 ID
|
||||
* @param request 메뉴 수정 요청 정보
|
||||
* @return 수정된 메뉴 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public MenuResponse updateMenu(Long menuId, MenuUpdateRequest request) {
|
||||
Menu menu = menuRepository.findById(menuId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.MENU_NOT_FOUND));
|
||||
|
||||
// 메뉴 정보 업데이트
|
||||
menu.updateMenuInfo(
|
||||
request.getMenuName(),
|
||||
request.getCategory(),
|
||||
request.getPrice(),
|
||||
request.getDescription(),
|
||||
request.getImage()
|
||||
);
|
||||
|
||||
Menu updatedMenu = menuRepository.save(menu);
|
||||
return toMenuResponse(updatedMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 삭제
|
||||
*
|
||||
* @param menuId 삭제할 메뉴 ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteMenu(Long menuId) {
|
||||
Menu menu = menuRepository.findById(menuId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.MENU_NOT_FOUND));
|
||||
|
||||
menuRepository.delete(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu 엔티티를 MenuResponse DTO로 변환
|
||||
*
|
||||
* @param menu Menu 엔티티
|
||||
* @return MenuResponse DTO
|
||||
*/
|
||||
private MenuResponse toMenuResponse(Menu menu) {
|
||||
return MenuResponse.builder()
|
||||
.menuId(menu.getId())
|
||||
.menuName(menu.getMenuName())
|
||||
.category(menu.getCategory())
|
||||
.price(menu.getPrice())
|
||||
.description(menu.getDescription())
|
||||
.image(menu.getImage())
|
||||
.createdAt(menu.getCreatedAt())
|
||||
.updatedAt(menu.getUpdatedAt())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.store.dto.SalesResponse;
|
||||
|
||||
/**
|
||||
* 매출 관리 서비스 인터페이스
|
||||
* 매출 조회 기능 정의
|
||||
*/
|
||||
public interface SalesService {
|
||||
|
||||
/**
|
||||
* 매출 정보 조회
|
||||
*
|
||||
* @return 매출 정보 (오늘, 월간, 전일 대비)
|
||||
*/
|
||||
SalesResponse getSales();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.store.dto.SalesResponse;
|
||||
import com.won.smarketing.store.repository.SalesRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 매출 관리 서비스 구현체
|
||||
* 매출 조회 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class SalesServiceImpl implements SalesService {
|
||||
|
||||
private final SalesRepository salesRepository;
|
||||
|
||||
/**
|
||||
* 매출 정보 조회
|
||||
*
|
||||
* @return 매출 정보 (오늘, 월간, 전일 대비)
|
||||
*/
|
||||
@Override
|
||||
public SalesResponse getSales() {
|
||||
// TODO: 현재는 더미 데이터 반환, 실제로는 현재 로그인한 사용자의 매장 ID를 사용해야 함
|
||||
Long storeId = 1L; // 임시로 설정
|
||||
|
||||
BigDecimal todaySales = salesRepository.findTodaySalesByStoreId(storeId);
|
||||
BigDecimal monthSales = salesRepository.findMonthSalesByStoreId(storeId);
|
||||
BigDecimal previousDayComparison = salesRepository.findPreviousDayComparisonByStoreId(storeId);
|
||||
|
||||
return SalesResponse.builder()
|
||||
.todaySales(todaySales != null ? todaySales : BigDecimal.ZERO)
|
||||
.monthSales(monthSales != null ? monthSales : BigDecimal.ZERO)
|
||||
.previousDayComparison(previousDayComparison != null ? previousDayComparison : BigDecimal.ZERO)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.store.dto.StoreCreateRequest;
|
||||
import com.won.smarketing.store.dto.StoreResponse;
|
||||
import com.won.smarketing.store.dto.StoreUpdateRequest;
|
||||
|
||||
/**
|
||||
* 매장 관리 서비스 인터페이스
|
||||
* 매장 등록, 조회, 수정 기능 정의
|
||||
*/
|
||||
public interface StoreService {
|
||||
|
||||
/**
|
||||
* 매장 정보 등록
|
||||
*
|
||||
* @param request 매장 등록 요청 정보
|
||||
* @return 등록된 매장 정보
|
||||
*/
|
||||
StoreResponse register(StoreCreateRequest request);
|
||||
|
||||
/**
|
||||
* 매장 정보 조회
|
||||
*
|
||||
* @param storeId 조회할 매장 ID
|
||||
* @return 매장 정보
|
||||
*/
|
||||
StoreResponse getStore(String storeId);
|
||||
|
||||
/**
|
||||
* 매장 정보 수정
|
||||
*
|
||||
* @param storeId 수정할 매장 ID
|
||||
* @param request 매장 수정 요청 정보
|
||||
* @return 수정된 매장 정보
|
||||
*/
|
||||
StoreResponse updateStore(Long storeId, StoreUpdateRequest request);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.won.smarketing.store.service;
|
||||
|
||||
import com.won.smarketing.common.exception.BusinessException;
|
||||
import com.won.smarketing.common.exception.ErrorCode;
|
||||
import com.won.smarketing.store.dto.StoreCreateRequest;
|
||||
import com.won.smarketing.store.dto.StoreResponse;
|
||||
import com.won.smarketing.store.dto.StoreUpdateRequest;
|
||||
import com.won.smarketing.store.entity.Store;
|
||||
import com.won.smarketing.store.repository.StoreRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 매장 관리 서비스 구현체
|
||||
* 매장 등록, 조회, 수정 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class StoreServiceImpl implements StoreService {
|
||||
|
||||
private final StoreRepository storeRepository;
|
||||
|
||||
/**
|
||||
* 매장 정보 등록
|
||||
*
|
||||
* @param request 매장 등록 요청 정보
|
||||
* @return 등록된 매장 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StoreResponse register(StoreCreateRequest request) {
|
||||
// 사용자별 매장 중복 등록 확인
|
||||
if (storeRepository.findByUserId(request.getUserId()).isPresent()) {
|
||||
throw new BusinessException(ErrorCode.STORE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
// 매장 엔티티 생성 및 저장
|
||||
Store store = Store.builder()
|
||||
.userId(request.getUserId())
|
||||
.storeName(request.getStoreName())
|
||||
.storeImage(request.getStoreImage())
|
||||
.businessType(request.getBusinessType())
|
||||
.address(request.getAddress())
|
||||
.phoneNumber(request.getPhoneNumber())
|
||||
.businessNumber(request.getBusinessNumber())
|
||||
.instaAccount(request.getInstaAccount())
|
||||
.naverBlogAccount(request.getNaverBlogAccount())
|
||||
.openTime(request.getOpenTime())
|
||||
.closeTime(request.getCloseTime())
|
||||
.closedDays(request.getClosedDays())
|
||||
.seatCount(request.getSeatCount())
|
||||
.build();
|
||||
|
||||
Store savedStore = storeRepository.save(store);
|
||||
return toStoreResponse(savedStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 매장 정보 조회
|
||||
*
|
||||
* @param storeId 조회할 매장 ID
|
||||
* @return 매장 정보
|
||||
*/
|
||||
@Override
|
||||
public StoreResponse getStore(String storeId) {
|
||||
Store store = storeRepository.findByUserId(storeId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.STORE_NOT_FOUND));
|
||||
|
||||
return toStoreResponse(store);
|
||||
}
|
||||
|
||||
/**
|
||||
* 매장 정보 수정
|
||||
*
|
||||
* @param storeId 수정할 매장 ID
|
||||
* @param request 매장 수정 요청 정보
|
||||
* @return 수정된 매장 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public StoreResponse updateStore(Long storeId, StoreUpdateRequest request) {
|
||||
Store store = storeRepository.findById(storeId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.STORE_NOT_FOUND));
|
||||
|
||||
// 매장 정보 업데이트
|
||||
store.updateStoreInfo(
|
||||
request.getStoreName(),
|
||||
request.getStoreImage(),
|
||||
request.getAddress(),
|
||||
request.getPhoneNumber(),
|
||||
request.getInstaAccount(),
|
||||
request.getNaverBlogAccount(),
|
||||
request.getOpenTime(),
|
||||
request.getCloseTime(),
|
||||
request.getClosedDays(),
|
||||
request.getSeatCount()
|
||||
);
|
||||
|
||||
Store updatedStore = storeRepository.save(store);
|
||||
return toStoreResponse(updatedStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store 엔티티를 StoreResponse DTO로 변환
|
||||
*
|
||||
* @param store Store 엔티티
|
||||
* @return StoreResponse DTO
|
||||
*/
|
||||
private StoreResponse toStoreResponse(Store store) {
|
||||
return StoreResponse.builder()
|
||||
.storeId(store.getId())
|
||||
.storeName(store.getStoreName())
|
||||
.storeImage(store.getStoreImage())
|
||||
.businessType(store.getBusinessType())
|
||||
.address(store.getAddress())
|
||||
.phoneNumber(store.getPhoneNumber())
|
||||
.businessNumber(store.getBusinessNumber())
|
||||
.instaAccount(store.getInstaAccount())
|
||||
.naverBlogAccount(store.getNaverBlogAccount())
|
||||
.openTime(store.getOpenTime())
|
||||
.closeTime(store.getCloseTime())
|
||||
.closedDays(store.getClosedDays())
|
||||
.seatCount(store.getSeatCount())
|
||||
.createdAt(store.getCreatedAt())
|
||||
.updatedAt(store.getUpdatedAt())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
server:
|
||||
port: ${SERVER_PORT:8082}
|
||||
servlet:
|
||||
context-path: /
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: store-service
|
||||
datasource:
|
||||
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:storedb}
|
||||
username: ${POSTGRES_USER:postgres}
|
||||
password: ${POSTGRES_PASSWORD:postgres}
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: ${JPA_DDL_AUTO:update}
|
||||
show-sql: ${JPA_SHOW_SQL:true}
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
format_sql: true
|
||||
|
||||
springdoc:
|
||||
swagger-ui:
|
||||
path: /swagger-ui.html
|
||||
operations-sorter: method
|
||||
api-docs:
|
||||
path: /api-docs
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.won.smarketing.store: ${LOG_LEVEL:DEBUG}
|
||||
Reference in New Issue
Block a user