Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
33e1838
refactor: 커스텀 예외 추가
Jjiggu Sep 12, 2025
2abd8d3
refactor: 커스텀 예외 추가
Jjiggu Sep 12, 2025
24ce659
chore: 사용하지 않는 예외 삭제
Jjiggu Sep 19, 2025
4642383
refactor: 에러메시지 일부 수정
Jjiggu Sep 19, 2025
0249ef2
feat: 누락된 예외 처리 케이스 추가
Jjiggu Sep 19, 2025
6c078a3
feat: 주문 취소 및 상태 변경 유효성 에러코드 추가
Jjiggu Sep 19, 2025
ccbf258
refactor: 에러코드명 일관성 있게 변경
Jjiggu Sep 19, 2025
86f66eb
feat: 주문 상태 변경 유효성 검사 예외 추가
Jjiggu Sep 19, 2025
09f161f
feat: 주문 취소 유효성 검사 추가
Jjiggu Sep 19, 2025
f82e07c
refactor: 코드 가독성 개선
Jjiggu Sep 19, 2025
8610b76
chore: 네이밍 일관성 유지
Jjiggu Sep 19, 2025
964c7cd
refactor: 예외처리 케이스 보강
Jjiggu Sep 19, 2025
f11504e
refactor: 사용자 권한 검증 메서드로 분리
Jjiggu Sep 19, 2025
537422f
refactor: 예약 관련 예외 처리 케이스 보강
Jjiggu Sep 19, 2025
09ee01d
refactor: 예약 관련 예외 처리 케이스 보강
Jjiggu Sep 19, 2025
0569690
refactor: RESERVATION_DATA_INCONSISTENCY redis로 분리
Jjiggu Sep 19, 2025
78afb19
feat: buildReservationUserKey 추가
Jjiggu Sep 19, 2025
342c8cc
feat: 예약번호 기반 상태 변경 로직 생성
Jjiggu Sep 19, 2025
352b561
feat: 예약번호 기반 상태 변경 로직 생성
Jjiggu Sep 19, 2025
d51e03a
feat: 예약번호 기반 상태 변경 로직 생성
Jjiggu Sep 19, 2025
230d2e5
refactor: redis 아래로 위치 변경
Jjiggu Sep 19, 2025
cc3f2f6
refactor: 유저 검증 메서드 분리
Jjiggu Sep 19, 2025
c40461d
refactor: 유저 검증 메서드 분리
Jjiggu Sep 19, 2025
41f64d9
feat: 메뉴 관련 예외처리 보강
Jjiggu Sep 19, 2025
814cbce
feat: 결제수단 관련 예외처리 보강
Jjiggu Sep 19, 2025
4378a71
feat: 예외처리 보강
Jjiggu Sep 19, 2025
b8c90a9
feat: NPE 예외처리 보강
Jjiggu Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@
import com.nowait.domaincorerdb.menu.entity.Menu;
import com.nowait.domaincorerdb.menu.entity.MenuImage;
import com.nowait.domaincorerdb.menu.exception.MenuCreationUnauthorizedException;
import com.nowait.domaincorerdb.menu.exception.MenuCrossStoreConflictException;
import com.nowait.domaincorerdb.menu.exception.MenuDeleteUnauthorizedException;
import com.nowait.domaincorerdb.menu.exception.MenuDuplicateIdException;
import com.nowait.domaincorerdb.menu.exception.MenuInvalidSortOrderException;
import com.nowait.domaincorerdb.menu.exception.MenuNotFoundException;
import com.nowait.domaincorerdb.menu.exception.MenuParamEmptyException;
import com.nowait.domaincorerdb.menu.exception.MenuUpdateUnauthorizedException;
import com.nowait.domaincorerdb.menu.exception.MenuViewUnauthorizedException;
import com.nowait.domaincorerdb.menu.repository.MenuImageRepository;
import com.nowait.domaincorerdb.menu.repository.MenuRepository;
import com.nowait.domaincorerdb.order.exception.OrderUpdateUnauthorizedException;
import com.nowait.domaincorerdb.order.exception.OrderViewUnauthorizedException;
import com.nowait.domaincorerdb.user.entity.MemberDetails;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
Expand All @@ -42,12 +47,10 @@ public class MenuService {
@Transactional
public MenuCreateResponse createMenu(MenuCreateRequest request, MemberDetails memberDetails) {
// 사용자 정보 가져오기
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);

User user = getUser(memberDetails);
// 사용자 역할이 SUPER_ADMIN이거나, storeId가 일치하는지 확인
if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(request.getStoreId())) {
throw new MenuCreationUnauthorizedException();
}
validateViewAuthorization(user, request.getStoreId());

// 메뉴 생성 로직
Menu toSave = request.toEntity();
Menu saved = menuRepository.save(toSave);
Expand All @@ -58,10 +61,10 @@ public MenuCreateResponse createMenu(MenuCreateRequest request, MemberDetails me
@Transactional(readOnly = true)
public MenuReadResponse getAllMenusByStoreId(Long storeId, MemberDetails memberDetails) {
// 사용자 정보 가져오기
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);

User user = getUser(memberDetails);
// 사용자 역할이 SUPER_ADMIN이거나, storeId가 일치하는지 확인
validateMenuViewAuthorization(user, storeId);
validateViewAuthorization(user, storeId);

List<Menu> menus = menuRepository.findAllByStoreIdAndDeletedFalseOrderBySortOrder(storeId);

List<MenuReadDto> menuReadResponse = menus.stream()
Expand All @@ -83,11 +86,10 @@ public MenuReadDto getMenuById(Long storeId, Long menuId, MemberDetails memberDe
throw new MenuParamEmptyException();
}
// 사용자 정보 가져오기
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
Menu menu = menuRepository.findByStoreIdAndIdAndDeletedFalse(storeId, menuId)
.orElseThrow(MenuNotFoundException::new);
User user = getUser(memberDetails);
Menu menu = getMenu(menuId);
// 사용자 역할이 SUPER_ADMIN이거나, storeId가 일치하는지 확인
validateMenuViewAuthorization(user, menu.getStoreId());
validateViewAuthorization(user, menu.getStoreId());

List<MenuImage> images = menuImageRepository.findByMenu(menu);
List<MenuImageUploadResponse> imageDto = images.stream()
Expand All @@ -100,13 +102,10 @@ public MenuReadDto getMenuById(Long storeId, Long menuId, MemberDetails memberDe

@Transactional
public MenuReadDto updateMenu(Long menuId, MenuUpdateRequest request, MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
Menu menu = menuRepository.findByIdAndDeletedFalse(menuId)
.orElseThrow(MenuNotFoundException::new);
User user = getUser(memberDetails);
Menu menu = getMenu(menuId);

if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(menu.getStoreId())) {
throw new MenuUpdateUnauthorizedException();
}
validateUpdateAuthorization(user, menu.getStoreId());

menu.updateInfo(
request.getAdminDisplayName(),
Expand Down Expand Up @@ -138,11 +137,11 @@ public String updateMenuSortOrder(List<MenuSortUpdateRequest> requests, MemberDe
}

if (requests.stream().map(MenuSortUpdateRequest::getMenuId).distinct().count() != requests.size()) {
throw new IllegalArgumentException("중복된 메뉴 ID가 포함되어 있습니다.");
throw new MenuDuplicateIdException();
}

if (requests.stream().anyMatch(r -> r.getSortOrder() == null || r.getSortOrder() < 0)) {
throw new IllegalArgumentException("잘못된 정렬 순서가 포함되어 있습니다. 정렬 순서는 0 이상의 정수여야 합니다.");
throw new MenuInvalidSortOrderException();
}

List<Long> ids = requests.stream().map(MenuSortUpdateRequest::getMenuId).toList();
Expand All @@ -153,7 +152,7 @@ public String updateMenuSortOrder(List<MenuSortUpdateRequest> requests, MemberDe

Long storeId = menus.get(0).getStoreId();
if (!menus.stream().allMatch(m -> storeId.equals(m.getStoreId()))) {
throw new IllegalArgumentException("다른 매장의 메뉴가 있습니다.");
throw new MenuCrossStoreConflictException();
}

Map<Long, Long> idToSort = requests.stream()
Expand All @@ -169,12 +168,10 @@ public String updateMenuSortOrder(List<MenuSortUpdateRequest> requests, MemberDe

@Transactional
public String deleteMenu(Long menuId, MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
Menu menu = menuRepository.findById(menuId).orElseThrow(MenuNotFoundException::new);
User user = getUser(memberDetails);
Menu menu = getMenu(menuId);

if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(menu.getStoreId())) {
throw new MenuDeleteUnauthorizedException();
}
validateDeleteAuthorization(user, menu.getStoreId());
menu.markAsDeleted();
menuRepository.save(menu);

Expand All @@ -191,10 +188,34 @@ public Boolean toggleSoldOut(Long menuId) {
return menu.getIsSoldOut();
}

private static void validateMenuViewAuthorization(User user, Long storeId) {
if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(storeId)) {

private void validateViewAuthorization(User user, Long storeId) {
if (!(Role.SUPER_ADMIN.equals(user.getRole())
|| (Role.MANAGER.equals(user.getRole()) && storeId.equals(user.getStoreId())))) {
throw new MenuViewUnauthorizedException();
}
}

private void validateUpdateAuthorization(User user, Long storeId) {
if (!(Role.SUPER_ADMIN.equals(user.getRole())
|| (Role.MANAGER.equals(user.getRole()) && storeId.equals(user.getStoreId())))) {
throw new MenuUpdateUnauthorizedException();
}
}

private void validateDeleteAuthorization(User user, Long storeId) {
if (!(Role.SUPER_ADMIN.equals(user.getRole())
|| (Role.MANAGER.equals(user.getRole()) && storeId.equals(user.getStoreId())))) {
throw new MenuDeleteUnauthorizedException();
}
}

private User getUser(MemberDetails memberDetails) {
return userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
}

private Menu getMenu(Long menuId) {
return menuRepository.findByIdAndDeletedFalse(menuId)
.orElseThrow(MenuNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@ public class OrderService {

@Transactional(readOnly = true)
public List<OrderResponseDto> findAllOrders(Long storeId, MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
User user = getUser(memberDetails);
storeRepository.findByStoreIdAndDeletedFalse(storeId).orElseThrow(StoreNotFoundException::new);
if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(storeId)) {
throw new OrderViewUnauthorizedException();
}

validateViewAuthorization(user, storeId);

LocalDate today = LocalDate.now(ZoneId.of("Asia/Seoul"));
LocalDateTime startDateTime = today.atStartOfDay();
Expand All @@ -64,11 +63,12 @@ public List<OrderResponseDto> findAllOrders(Long storeId, MemberDetails memberDe
@Transactional
public OrderStatusUpdateResponseDto updateOrderStatus(Long orderId, OrderStatus newStatus,
MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
User user = getUser(memberDetails);
UserOrder userOrder = orderRepository.findById(orderId).orElseThrow(OrderNotFoundException::new);
if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(userOrder.getStore().getStoreId())) {
throw new OrderUpdateUnauthorizedException();
}
Long storeId = userOrder.getStore().getStoreId();

validateUpdateAuthorization(user, storeId);

userOrder.updateStatus(newStatus);

if (OrderStatus.COOKED.equals(newStatus)) {
Expand All @@ -92,12 +92,10 @@ public OrderStatusUpdateResponseDto updateOrderStatus(Long orderId, OrderStatus

@Transactional
public OrderStatusUpdateResponseDto cancelOrder(Long orderId, CancelOrderRequest cancelOrderRequest, MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
User user = getUser(memberDetails);
UserOrder userOrder = orderRepository.findById(orderId).orElseThrow(OrderNotFoundException::new);

if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(userOrder.getStore().getStoreId())) {
throw new OrderUpdateUnauthorizedException();
}
validateUpdateAuthorization(user, userOrder.getStore().getStoreId());

userOrder.cancelOrder();

Expand All @@ -115,25 +113,43 @@ public OrderStatusUpdateResponseDto cancelOrder(Long orderId, CancelOrderRequest

@Transactional(readOnly = true)
public OrderSalesSumDetail getSaleSumByStoreId(MemberDetails memberDetails, LocalDate date) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
User user = getUser(memberDetails);
Long storeId = user.getStoreId();

if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(storeId)) {
throw new OrderViewUnauthorizedException();
}
validateViewAuthorization(user, storeId);

return statisticCustomRepository.findSalesSumByStoreId(storeId, date);
}

// 현재는 사용하지 않음. 향후 관리자 통계 페이지 확장 시 활용 가능
@Transactional(readOnly = true)
public List<TopSalesStoresDetail> getTop5StoresBySalesToday(MemberDetails memberDetails) {
User user = userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
User user = getUser(memberDetails);
Long storeId = user.getStoreId();

if (!Role.SUPER_ADMIN.equals(user.getRole()) && !user.getStoreId().equals(storeId)) {
validateUpdateAuthorization(user, storeId);

return statisticCustomRepository.getTop4PlusMine(storeId);
}

private void validateViewAuthorization(User user, Long storeId) {
if (!(Role.SUPER_ADMIN.equals(user.getRole())
|| (Role.MANAGER.equals(user.getRole()) && storeId.equals(user.getStoreId())))) {
throw new OrderViewUnauthorizedException();
}
}

return statisticCustomRepository.getTop4PlusMine(storeId);
private void validateUpdateAuthorization(User user, Long storeId) {
if (!(Role.SUPER_ADMIN.equals(user.getRole())
|| (Role.MANAGER.equals(user.getRole()) && storeId.equals(user.getStoreId())))) {
throw new OrderUpdateUnauthorizedException();
}
}

private User getUser(MemberDetails memberDetails) {
if (memberDetails == null) {
throw new OrderViewUnauthorizedException();
}
return userRepository.findById(memberDetails.getId()).orElseThrow(UserNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,22 @@ public ResponseEntity<?> updateEntry(
));
}

@PatchMapping("/admin/{storeId}/{reservationNumber}")
@Operation(summary = "예약팀 상태 업데이트 처리", description = "특정 예약에 대한 입장 완료 처리")
@ApiResponse(responseCode = "200", description = "예약팀 상태 변경 : CALLING -> CONFIRMED")
public ResponseEntity<?> updateEntryWithReservationNumber(
@PathVariable Long storeId,
@PathVariable String reservationNumber,
@RequestBody ReservationStatusRequest request,
@AuthenticationPrincipal MemberDetails memberDetails
) {
EntryStatusResponseDto response = reservationService.processEntryStatusByReservationNumber(storeId, reservationNumber, memberDetails, request.getStatus());
return ResponseEntity
.status(HttpStatus.OK)
.body(
ApiUtils.success(
response
));
}

}
Loading