구현한 기능
- 사용자가 본인의 예약을 취소할 수 있는 API
- 파트너(점장)가 매장의 예약을 취소할 수 있는 API
- 예약 취소 시 상태를 CANCELLED로 변경하는 로직
- 적절한 권한 체크(본인 예약 또는 파트너 소유 매장의 예약만 취소 가능)
- 이미 취소되었거나 방문 확인/완료된 예약은 취소할 수 없도록 제한
코드 스냅샷
ReservationService.java
@Transactional
public ReservationDto.ReservationInfoResponse cancelReservation(Long reservationId, Long actorId, boolean isPartner) {
Reservation reservation = reservationRepository.findById(reservationId)
.orElseThrow(() -> new CustomException(ErrorCode.RESERVATION_NOT_FOUND));
validateCancellationPermission(reservation, actorId, isPartner);
if (reservation.getStatus() == ReservationStatus.CANCELLED) {
throw new CustomException(ErrorCode.INVALID_REQUEST, "이미 취소된 예약입니다.");
}
if (reservation.getStatus() == ReservationStatus.ARRIVED ||
reservation.getStatus() == ReservationStatus.COMPLETED) {
throw new CustomException(ErrorCode.RESERVATION_NOT_ALLOWED, "이미 방문 확인되었거나 완료된 예약은 취소할 수 없습니다.");
}
reservation.setStatus(ReservationStatus.CANCELLED);
Reservation cancelledReservation = reservationRepository.save(reservation);
return converToReservationInfoResponse(cancelledReservation);
}
ReservationController.java
@PatchMapping("/{reservationId}/cancel")
public ResponseEntity<ApiResponse<ReservationDto.ReservationInfoResponse>> cancelReservation(
@PathVariable Long reservationId
) {
String currentUserEmail = authenticationUtil.getCurrentUserEmail();
Long currentUserId = authenticationUtil.getCurrentUserId();
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext()
.getAuthentication().getAuthorities();
boolean isPartner = authorities.stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_PARTNER"));
ReservationDto.ReservationInfoResponse response =
reservationService.cancelReservation(reservationId, currentUserId, isPartner);
return ResponseEntity.ok(ApiResponse.success("예약이 성공적으로 취소되었습니다.", response));
}
Postman 테스트

구현 예정
- 도착 확인 API(키오스크 연동)
- 도착 상태 업데이트 API(예약 상태 변경)