Skip to content

Commit

Permalink
feat: 예약 변경 알림톡 적용 (#289)
Browse files Browse the repository at this point in the history
* feat: 알림톡 기능 구현 / 예약등록 알림톡 적용

* feat: 예약 확정 알림톡 적용

* feat: 예약 확정 + 초대장 알림톡 적용

* feat: 예약 취소 알림톡 구현

* feat: 예약 취소 알림톡 구현

* fix: 예약 확정 로직 수정

* feat: 예약 변경 알림톡 적용
  • Loading branch information
sejineer authored Mar 5, 2024
1 parent 488eebc commit 8afe9df
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface ReservationManipulationService {

List<ReservationResponse> addOwnerReservation(OwnerReservationCreate ownerReservationCreate, UserPrincipal userPrincipal);
ReservationResponse addUserReservation(UserReservationCreate reservationRequest, UserPrincipal userPrincipal) throws Exception;
ReservationResponse updateReservation(UpdateReservationReq updateReq, UserPrincipal userPrincipal);
ReservationResponse updateReservation(UpdateReservationReq updateReq, UserPrincipal userPrincipal) throws Exception;
void cancelReservation(UserPrincipal userPrincipal, Long reservationId) throws Exception;

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,91 +38,98 @@
@Transactional(readOnly = true)
public class ReservationManipulationServiceImpl implements ReservationManipulationService {

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();
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.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);
}

@Override
@Transactional
public ReservationResponse updateReservation(UpdateReservationReq updateReq, UserPrincipal userPrincipal) throws Exception {
User user = userRepository.findById(userPrincipal.getId())
.orElseThrow(InvalidUserException::new);
//현재 예약 검색
Reservation currentReservation = reservationRepository.findReservationById(updateReq.getReservationId())
.orElseThrow(InvalidReservationException::new);

if(!currentReservation.getSender().getId().equals(user.getId()))
throw new UserReservationMismatchException();

//변경 가능한 예약 검색
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);
reservationRepository.save(currentReservation);

naverSmsClient.sendChange(newReservation);
return ReservationResponse.toDtoUser(updated);
}
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
Expand All @@ -136,11 +143,11 @@ public void cancelReservation(final UserPrincipal userPrincipal, final Long rese
if (!reservation.getSender().getId().equals(user.getId()))
throw new UserReservationMismatchException();

if(reservation.getReservationStatus().equals(BOOKED)) { // BOOKED 상태일 때 WAITING으로 변경
if (reservation.getReservationStatus().equals(BOOKED)) { // BOOKED 상태일 때 WAITING으로 변경
reservation.updateStatus(WAITING);
naverSmsClient.sendCancel(reservation);
reservation.clearReservation();
} else if(reservation.getReservationStatus().equals(CONFIRMED)) { // CONFIRMED 상태일 때 CANCELLED로 변경
} else if (reservation.getReservationStatus().equals(CONFIRMED)) { // CONFIRMED 상태일 때 CANCELLED로 변경
reservation.updateStatus(CANCELLED);
naverSmsClient.sendCancel(reservation);
} else { // 예약 상태가 BOOKED나 CONFIRMED가 아닐 경우
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@Data
public class UpdateReservationReq {

@Schema(type = "long", example = "2", description = "예약 날짜")
@Schema(type = "long", example = "2", description = "바꾸기 전 예약 ID")
private Long reservationId;

@Schema(type = "string", example = "2023-08-25", description = "예약 날짜")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public ResponseCustom<ReservationResponse> createUserReservation(
public ResponseCustom<ReservationResponse> updateReservation(
@Parameter(description = "수정 요청을 확인해주세요.", required = true) @RequestBody UpdateReservationReq updateReq,
@Parameter(description = "AccessToken 을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal
) {
) throws Exception {
return ResponseCustom.OK(
reservationManipulationService.updateReservation(updateReq, userPrincipal));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,57 @@ public void sendCancel(Reservation reservation) throws Exception {
.body(SmsResponseDto.class);
}

public void sendChange(final Reservation reservation) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis());
String url = "/alimtalk/v2/services/" + BIZTALK_SERVICE_ID + "/messages";
String signature = makeSignature(timestamp, url);

RestClient restClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.baseUrl("https://sens.apigw.ntruss.com/alimtalk/v2")
.defaultHeaders(header -> {
header.set("Content-Type", "application/json");
header.set("x-ncp-apigw-timestamp", timestamp);
header.set("x-ncp-iam-access-key", ACCESS_KEY);
header.set("x-ncp-apigw-signature-v2", signature);
})
.build();

String date = reservation.getDate().toString();
String time = reservation.getTime().toString();
String receiveUserName = reservation.getReceiver().getName();
String productName = reservation.getExperienceGift().getTitle();
String persons = reservation.getPersons().toString() + "명";

List<MessageMapping> messages = new ArrayList<>();
messages.add(MessageMapping.builder()
.to(reservation.getSender().getPhoneNumber())
.content("[셸위]\n" +
"예약이 변경되었습니다\n" +
"\n" +
"예약날짜: " + date + "\n" +
"예약시간: " + time + "\n" +
"수취인: " + receiveUserName + "\n" +
"상품명: " + productName + "\n" +
"옵션: " + persons)
.build());

AlimTalkReq alimTalkReq = AlimTalkReq.builder()
.plusFriendId("@shallwee")
.templateCode("reservationChanges")
.messages(messages)
.build();

ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(alimTalkReq);

restClient.post()
.uri("/services/" + BIZTALK_SERVICE_ID + "/messages")
.body(body)
.retrieve()
.body(SmsResponseDto.class);
}

@Transactional
public Message validVerificationCode(ValidVerificationCodeReq validVerificationCodeReq) {
LocalDateTime time = LocalDateTime.now();
Expand Down

0 comments on commit 8afe9df

Please sign in to comment.