Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,9 @@ public void cancel(String reason) {
this.cancelReason = reason;
}

// 체크인 체크아웃 시간 고정 설정
public void setDefaultCheckTime(LocalDateTime checkin, LocalDateTime checkout) {
this.checkin = checkin.withHour(15).truncatedTo(ChronoUnit.HOURS);
this.checkout = checkout.withHour(11).truncatedTo(ChronoUnit.HOURS);
}


// json 반환 시 파싱해서 반환
public String[] parseDateTime(LocalDateTime checkin, LocalDateTime checkout) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
return new String[] {
checkin.format(formatter),
checkout.format(formatter)
};
// 상태 변경
public void changeStatus(ReservationStatus status) {
this.status = status;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public enum ReservationStatus {

RESERVED("예약완료"),
CANCELED("예약취소"),
COMPLETED("체크인완료"); // 체크인 이후로 (자동) 변경
COMPLETED("체크인완료"), // 체크인 이후로 (자동) 변경

NOTCANCELABLE("취소불가");

private final String status;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.springframework.stereotype.Repository;
import site.campingon.campingon.reservation.entity.Reservation;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Repository
Expand All @@ -31,5 +33,5 @@ public interface ReservationRepository extends JpaRepository<Reservation, Long>
@Query("SELECT r FROM Reservation r WHERE r.user.id = :userId AND r.status = 'RESERVED' ORDER BY r.checkin ASC LIMIT 1")
Reservation findUpcomingReservationByUserId(@Param("userId")Long userId);


List<Reservation> findByCheckin(LocalDateTime targetTime);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package site.campingon.campingon.reservation.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import site.campingon.campingon.reservation.entity.Reservation;
import site.campingon.campingon.reservation.entity.ReservationStatus;
import site.campingon.campingon.reservation.repository.ReservationRepository;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class ReservationStatusUpdate {

private final ReservationRepository reservationRepository;

// 매일 자정에 예약불가 실행
@Scheduled(cron = "0 59 23 * * ?")
public void updateStatusToNotCancelable() {
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Seoul"));
LocalDate targetDate = LocalDate.from(now.plusDays(1));

LocalDateTime targetTime = targetDate.atTime(15, 0);

List<Reservation> reservations = reservationRepository.findByCheckin(targetTime);

reservations.stream()
.filter(reservation -> reservation.getStatus() != ReservationStatus.NOTCANCELABLE)
.forEach(reservation -> reservation.changeStatus(ReservationStatus.NOTCANCELABLE));

reservationRepository.saveAll(reservations);

log.debug("예약불가 업데이트 스케줄러가 실행되었습니다.");
}

// 매일 3시에 체크인완료 실행
@Scheduled(cron = "0 0 15 * * ?")
public void updateStatusToCompleted() {
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Seoul"));
LocalDateTime targetDate = now.toLocalDate().atTime(15, 0);

List<Reservation> reservations = reservationRepository.findByCheckin(targetDate);
for (Reservation reservation : reservations) {
if (reservation.getStatus() != ReservationStatus.COMPLETED) {
reservation.changeStatus(ReservationStatus.COMPLETED);
}
}
reservationRepository.saveAll(reservations);

log.debug("체크인완료 업데이트 스케줄러가 실행되었습니다.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import site.campingon.campingon.camp.repository.CampSiteRepository;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -89,7 +90,10 @@ void getAvailableCampSitesSuccess() {
LocalDate checkout = LocalDate.of(2023, 10, 5);
List<CampSite> availableCampSites = Arrays.asList(mockCampSite);

when(campSiteRepository.findAvailableCampSites(campId, checkin, checkout)).thenReturn(availableCampSites);
LocalDateTime newCheckin = LocalDateTime.of(2023, 10, 1,0,0);
LocalDateTime newCheckout = LocalDateTime.of(2023, 10, 5,0,0);

when(campSiteRepository.findAvailableCampSites(campId, newCheckin, newCheckout)).thenReturn(availableCampSites);
when(campSiteMapper.toCampSiteListResponseDto(any(CampSite.class))).thenReturn(mockCampSiteListDto);

// when
Expand All @@ -100,7 +104,7 @@ void getAvailableCampSitesSuccess() {
assertEquals(1, result.size());
assertEquals(mockCampSiteListDto, result.get(0));

verify(campSiteRepository).findAvailableCampSites(campId, checkin, checkout);
verify(campSiteRepository).findAvailableCampSites(campId, newCheckin, newCheckout);
verify(campSiteMapper).toCampSiteListResponseDto(any(CampSite.class));

}
Expand All @@ -115,7 +119,10 @@ void getAvailableCampSitesReturnsEmptyList() {
LocalDate checkout = LocalDate.of(2023, 10, 5);
List<CampSite> emptyCampSites = Collections.emptyList();

when(campSiteRepository.findAvailableCampSites(campId, checkin, checkout)).thenReturn(emptyCampSites);
LocalDateTime newCheckin = LocalDateTime.of(2023, 10, 1,0,0);
LocalDateTime newCheckout = LocalDateTime.of(2023, 10, 5,0,0);

when(campSiteRepository.findAvailableCampSites(campId, newCheckin, newCheckout)).thenReturn(emptyCampSites);

// when
List<CampSiteListResponseDto> result = campSiteReserveService.getAvailableCampSites(campId, checkin, checkout);
Expand All @@ -124,7 +131,7 @@ void getAvailableCampSitesReturnsEmptyList() {
assertNotNull(result);
assertTrue(result.isEmpty());

verify(campSiteRepository).findAvailableCampSites(campId, checkin, checkout);
verify(campSiteRepository).findAvailableCampSites(campId, newCheckin, newCheckout);
verify(campSiteMapper, never()).toCampSiteListResponseDto(any(CampSite.class));
}

Expand Down Expand Up @@ -174,7 +181,6 @@ void testCreateCampSiteWithSingleInduty() {
.price(campSite.getPrice())
.maximumPeople(campSite.getMaximumPeople())
.indoorFacility(campSite.getIndoorFacility())
.isAvailable(campSite.isAvailable())
.build());

// When
Expand Down Expand Up @@ -232,7 +238,6 @@ void testUpdateCampSite() {
.price(updatedCampSite.getPrice())
.maximumPeople(updatedCampSite.getMaximumPeople())
.indoorFacility(updatedCampSite.getIndoorFacility())
.isAvailable(updatedCampSite.isAvailable())
.build());

// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import site.campingon.campingon.reservation.utils.ReservationValidate;
import site.campingon.campingon.user.entity.User;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

Expand Down Expand Up @@ -138,8 +139,8 @@ void createReservationSuccess() {
ReservationCreateRequestDto requestDto = new ReservationCreateRequestDto(
mockCamp.getId(),
mockCampSite.getId(),
LocalDateTime.now(),
LocalDateTime.now().plusDays(1),
LocalDate.now(),
LocalDate.now().plusDays(1),
2,
50000
);
Expand Down Expand Up @@ -189,8 +190,8 @@ void createReservationUserNotFound() {
ReservationCreateRequestDto requestDto = new ReservationCreateRequestDto(
mockCamp.getId(),
mockCampSite.getId(),
LocalDateTime.now(),
LocalDateTime.now().plusDays(1),
LocalDate.now(),
LocalDate.now().plusDays(1),
2,
50000
);
Expand All @@ -212,8 +213,8 @@ void createReservationCampSiteNotFound() {
ReservationCreateRequestDto requestDto = new ReservationCreateRequestDto(
mockCamp.getId(),
mockCampSite.getId(),
LocalDateTime.now(),
LocalDateTime.now().plusDays(1),
LocalDate.now(),
LocalDate.now().plusDays(1),
2,
50000
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package site.campingon.campingon.reservation.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import site.campingon.campingon.camp.entity.Camp;
import site.campingon.campingon.camp.entity.CampSite;
import site.campingon.campingon.camp.entity.Induty;
import site.campingon.campingon.reservation.entity.Reservation;
import site.campingon.campingon.reservation.entity.ReservationStatus;
import site.campingon.campingon.reservation.repository.ReservationRepository;
import site.campingon.campingon.user.entity.User;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ReservationStatusUpdateTest {

@Mock
private ReservationRepository reservationRepository;

@InjectMocks
private ReservationStatusUpdate reservationStatusUpdate;

@Mock
private Reservation reservation1;
@Mock
private Reservation reservation2;

@BeforeEach
void setUp() {
when(reservation1.getStatus()).thenReturn(ReservationStatus.RESERVED);
when(reservation2.getStatus()).thenReturn(ReservationStatus.NOTCANCELABLE);
}

@Test
@DisplayName("갱신성공 - 예약불가상태로 갱신")
void testUpdateStatusToNotCancelable() {

// Given - 밀리초 제거 필요
LocalDateTime targetTime = LocalDateTime.now().plusDays(1).withHour(15).withMinute(0).withSecond(0).withNano(0);
List<Reservation> reservations = Arrays.asList(reservation1, reservation2);

when(reservationRepository.findByCheckin(targetTime)).thenReturn(reservations);

// 밀리초를 제거한 targetTime으로 설정
when(reservationRepository.findByCheckin(targetTime)).thenReturn(reservations);

// When
reservationStatusUpdate.updateStatusToNotCancelable();

// Then
ArgumentCaptor<List<Reservation>> captor = ArgumentCaptor.forClass(List.class);
verify(reservationRepository, times(1)).saveAll(captor.capture());

List<Reservation> savedReservations = captor.getValue();
assertEquals(2, savedReservations.size());
verify(reservation1).changeStatus(ReservationStatus.NOTCANCELABLE);
verify(reservation2, never()).changeStatus(ReservationStatus.NOTCANCELABLE);
}

@Test
@DisplayName("갱신성공 - 체크인완료상태로 갱신")
void testUpdateStatusToCompleted() {

// Given - 밀리초 제거 필요
LocalDateTime targetTime = LocalDateTime.now().withHour(15).withMinute(0).withSecond(0).withNano(0);

// 상태를 변경할 수 있도록 설정
when(reservation1.getStatus()).thenReturn(ReservationStatus.RESERVED);
when(reservation2.getStatus()).thenReturn(ReservationStatus.COMPLETED);

List<Reservation> reservations = Arrays.asList(reservation1, reservation2);

// 밀리초를 제거한 targetTime으로 설정
when(reservationRepository.findByCheckin(targetTime)).thenReturn(reservations);

// When
reservationStatusUpdate.updateStatusToCompleted();

// Then
ArgumentCaptor<List<Reservation>> captor = ArgumentCaptor.forClass(List.class);
verify(reservationRepository, times(1)).saveAll(captor.capture());

List<Reservation> savedReservations = captor.getValue();
assertEquals(2, savedReservations.size());
verify(reservation1).changeStatus(ReservationStatus.COMPLETED);
verify(reservation2, never()).changeStatus(ReservationStatus.COMPLETED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ void setUp() {
.campSite(CampSite.builder()
.siteType(CAR_SITE)
.price(CAR_SITE.getPrice())
.maximumPeople(CAR_SITE.getMaximum_people())
.maximumPeople(CAR_SITE.getMaximumPeople())
.build())
.user(User.builder()
.id(123L)
.name("Mock User")
.email("[email protected]")
.build())
.checkIn(LocalDateTime.of(2024, 12, 1, 14, 0))
.checkOut(LocalDateTime.of(2024, 12, 3, 11, 0))
.checkin(LocalDateTime.of(2024, 12, 1, 14, 0))
.checkout(LocalDateTime.of(2024, 12, 3, 11, 0))
.guestCnt(2)
.status(ReservationStatus.COMPLETED)
.totalPrice(160000)
Expand Down
Loading