Skip to content

Commit

Permalink
fix: 예약 관련 로직을 수정한다. (#287)
Browse files Browse the repository at this point in the history
* feat: 예약 시간 변경

* feat: 비관적 락 적용

* feat: 예약 삭제 로직 수정
hyunw9 authored Mar 5, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent a31611b commit 488eebc
Showing 6 changed files with 110 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -39,4 +39,5 @@ out/

/src/main/resources/application-dev.yml
/src/main/resources/application-local.yml
/src/main/resources/application-prod.yml
/src/main/resources/application-prod.yml
shallwe-master.pem
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package com.shallwe.domain.reservation.application;

import static com.shallwe.domain.reservation.domain.ReservationStatus.*;

import static com.shallwe.domain.reservation.domain.ReservationStatus.WAITING;

import com.shallwe.domain.common.Status;
import com.shallwe.domain.experiencegift.domain.ExperienceGift;
import com.shallwe.domain.experiencegift.domain.repository.ExperienceGiftRepository;
import com.shallwe.domain.experiencegift.exception.ExperienceGiftNotFoundException;
import com.shallwe.domain.reservation.domain.Reservation;
import com.shallwe.domain.reservation.domain.ReservationStatus;
import com.shallwe.domain.reservation.domain.repository.ReservationRepository;
import com.shallwe.domain.reservation.dto.request.OwnerReservationCreate;
import com.shallwe.domain.reservation.dto.response.ReservationResponse;
import com.shallwe.domain.reservation.dto.request.UserReservationCreate;
import com.shallwe.domain.reservation.dto.request.UpdateReservationReq;
import com.shallwe.domain.reservation.exception.InvalidReservationException;
import com.shallwe.domain.reservation.exception.InvalidReservationUpdateException;
import com.shallwe.domain.reservation.exception.InvalidSenderException;
import com.shallwe.domain.reservation.exception.InvalidReceiverException;
import com.shallwe.domain.reservation.exception.*;

import com.shallwe.domain.user.domain.User;
import com.shallwe.domain.user.domain.repository.UserRepository;
import com.shallwe.domain.user.exception.InvalidUserException;
@@ -33,63 +38,91 @@
@Transactional(readOnly = true)
public class ReservationManipulationServiceImpl implements ReservationManipulationService {

private final ReservationRepository reservationRepository;
private final ExperienceGiftRepository experienceGiftRepository;
private final UserRepository userRepository;
private final NaverSmsClient naverSmsClient;

@Override
@Transactional
public List<ReservationResponse> addOwnerReservation(OwnerReservationCreate ownerReservationCreate, UserPrincipal userPrincipal) {
ExperienceGift experienceGift = experienceGiftRepository.findById(ownerReservationCreate.getExperienceGiftId())
.orElseThrow(ExperienceGiftNotFoundException::new);

List<Reservation> reservations = OwnerReservationCreate.toEntityForOwner(ownerReservationCreate, experienceGift);
return reservations.stream()
.map(reservationRepository::save)
.map(ReservationResponse::toDtoOwner)
.collect(Collectors.toList());
}

@Override
@Transactional
public ReservationResponse addUserReservation(UserReservationCreate reservationRequest, UserPrincipal userPrincipal) throws Exception {
User sender = userRepository.findById(userPrincipal.getId())
.orElseThrow(InvalidSenderException::new);

User receiver = userRepository.findByPhoneNumberAndStatus(reservationRequest.getPhoneNumber(), Status.ACTIVE)
.orElseThrow(InvalidReceiverException::new);

ExperienceGift experienceGift = experienceGiftRepository.findExperienceGiftById(reservationRequest.getExperienceGiftId())
.orElseThrow(ExperienceGiftNotFoundException::new);

Reservation reservation = reservationRepository.findByDateAndTimeAndExperienceGift(
reservationRequest.getDate(), reservationRequest.getTime(), experienceGift)
.orElseThrow(InvalidReservationException::new);

if (reservation.getReservationStatus().equals(WAITING)) {
reservation.updateStatus(BOOKED);
reservation.updateUserReservationRequest(reservationRequest, sender, receiver);
naverSmsClient.sendApply(receiver, experienceGift, reservation);
experienceGift.addReservationCount();
} else {
throw new InvalidReservationException();
}
return ReservationResponse.toDtoUser(reservation);
}

@Override
@Transactional
public ReservationResponse updateReservation(UpdateReservationReq updateReq, UserPrincipal userPrincipal) {
Reservation updateReservation = reservationRepository.findById(
updateReq.getReservationId()).map(
reservation -> {
reservation.updateReservation(updateReq);
return reservationRepository.save(reservation);
}
).orElseThrow(InvalidReservationException::new);
return ReservationResponse.toDtoUser(updateReservation);
private final ReservationRepository reservationRepository;
private final ExperienceGiftRepository experienceGiftRepository;
private final UserRepository userRepository;
private final NaverSmsClient naverSmsClient;

@Transactional
public List<ReservationResponse> addOwnerReservation(
OwnerReservationCreate ownerReservationCreate, UserPrincipal userPrincipal) {
ExperienceGift experienceGift = experienceGiftRepository.findById(
ownerReservationCreate.getExperienceGiftId())
.orElseThrow(ExperienceGiftNotFoundException::new);

List<Reservation> reservations = OwnerReservationCreate.toEntityForOwner(ownerReservationCreate,
experienceGift);
return reservations.stream()
.map(reservationRepository::save)
.map(ReservationResponse::toDtoOwner)
.collect(Collectors.toList());
}

@Transactional
public ReservationResponse addUserReservation(UserReservationCreate reservationRequest,
UserPrincipal userPrincipal) throws Exception {
User sender = userRepository.findById(userPrincipal.getId())
.orElseThrow(InvalidSenderException::new);

User receiver = userRepository.findByPhoneNumberAndStatus(reservationRequest.getPhoneNumber(),
Status.ACTIVE)
.orElseThrow(InvalidReceiverException::new);

ExperienceGift experienceGift = experienceGiftRepository.findExperienceGiftById(
reservationRequest.getExperienceGiftId())
.orElseThrow(ExperienceGiftNotFoundException::new);

Reservation reservation = reservationRepository.findByDateAndTimeAndExperienceGiftWithPessimisticLock(
reservationRequest.getDate(), reservationRequest.getTime(), experienceGift)
.orElseThrow(InvalidReservationException::new);

if (reservation.getReservationStatus().equals(WAITING)) {
reservation.updateStatus(BOOKED);
reservation.updateUserReservationRequest(reservationRequest, sender, receiver);
naverSmsClient.sendApply(receiver, experienceGift, reservation);
experienceGift.addReservationCount();
} else {
throw new InvalidReservationException();
}
return ReservationResponse.toDtoUser(reservation);
}

@Transactional
public ReservationResponse updateReservation(UpdateReservationReq updateReq,
UserPrincipal userPrincipal) {

//현재 예약 검색
Reservation currentReservation = reservationRepository.findById(updateReq.getReservationId())
.orElseThrow(InvalidReservationException::new);

//변경 가능한 예약 검색
Reservation newReservation = reservationRepository.findByDateAndTimeAndExperienceGift(
updateReq.getDate(), updateReq.getTime(),
currentReservation.getExperienceGift()
).orElseThrow(InvalidReservationUpdateException::new);

//DTO 생성
UserReservationCreate reservationCreateDto = UserReservationCreate.builder()
.persons(currentReservation.getPersons())
.experienceGiftId(currentReservation.getExperienceGift().getId())
.invitationComment(currentReservation.getInvitationComment())
.phoneNumber(currentReservation.getPhoneNumber())
.imageUrl(currentReservation.getInvitationImg())
.build();

//기존 예약 정보를 현재 예약 정보로 이동
newReservation.updateUserReservationRequest(reservationCreateDto,
currentReservation.getSender(), currentReservation.getReceiver());
newReservation.updateStatus(BOOKED);
Reservation updated = reservationRepository.save(newReservation);

//기존 예약 정보 상태 초기화
currentReservation.clearReservation();
currentReservation.updateStatus(WAITING);
Reservation curr = reservationRepository.save(currentReservation);

return ReservationResponse.toDtoUser(updated);
}

@Override
@Transactional
Original file line number Diff line number Diff line change
@@ -101,6 +101,7 @@ public void updateStatus(ReservationStatus status) {
this.reservationStatus = status;
}


public void clearReservation() {
this.sender = null;
this.receiver = null;
Original file line number Diff line number Diff line change
@@ -7,10 +7,12 @@
import com.shallwe.domain.reservation.domain.ReservationStatus;
import com.shallwe.domain.shopowner.domain.ShopOwner;
import com.shallwe.domain.user.domain.User;
import jakarta.persistence.LockModeType;
import java.time.LocalDate;
import java.time.LocalTime;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@@ -35,7 +37,13 @@ public interface ReservationRepository extends JpaRepository<Reservation, Long>,

Optional<List<Reservation>> findAllByExperienceGiftAndDate(ExperienceGift experienceGift, LocalDate date);


@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select r from Reservation r where r.date = :date and r.time = :time and r.experienceGift=:experienceGift")
Optional<Reservation> findByDateAndTimeAndExperienceGiftWithPessimisticLock(LocalDate date, LocalTime time, ExperienceGift experienceGift);

@EntityGraph(attributePaths = {"experienceGift", "experienceGift.shopOwner", "sender", "receiver"})
Optional<Reservation> findReservationById(Long reservationId);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.shallwe.domain.reservation.exception;

public class InvalidReservationUpdateException extends RuntimeException{

public InvalidReservationUpdateException() {
super("변경이 불가능한 예약 시간입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -132,7 +132,7 @@ public ResponseCustom<ReservationResponse> createUserReservation(
reservationManipulationService.addUserReservation(reservationRequest, userPrincipal));
}

@Operation(summary = "예약 수정하기", description = "예약을 수정합니다")
@Operation(summary = "예약 수정하기", description = "예약 ID로 해당 예약의 시간을 수정합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "예약 수정 성공", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = ReservationResponse.class))}),

0 comments on commit 488eebc

Please sign in to comment.