@Service
@RequiredArgsConstructor
@Slf4j
public class PaymentService {
private final ScheduledExecutorService scheduler;
@Transactional
public KakaoApproveResponseDto kakaoPayApprove(String pgToken,Long userId,Long paymentId){
printInfo();
Payment payment = paymentRepository.findByPaymentId(paymentId).orElseThrow(()->new CatchStudyException(ErrorCode.PAYMENT_NOT_FOUND));
Booking booking = payment.getBooking();
Map<String,String> parameters = new HashMap<>();
parameters.put("cid",KakaoPayProperties.cid);
parameters.put("tid",payment.getTid());
parameters.put("partner_order_id", String.valueOf(paymentId));
parameters.put("partner_user_id", String.valueOf(userId));
parameters.put("pg_token", pgToken);
HttpEntity<Map<String,String>> requestEntity = new HttpEntity<>(parameters,this.getHeaders());
RestTemplate restTemplate = new RestTemplate();
KakaoApproveResponseDto kakaoApprove = restTemplate.postForObject(
KakaoPayProperties.approveUrl,
requestEntity,
KakaoApproveResponseDto.class
);
//좌석,room 사용중으로 변경, booking 테이블 변경 (상태,code), payment 테이블 변경 (amount,승인시간,status)
String code = makeCode();
booking.completeBooking(BookingStatus.beforeEnteringRoom,makeCode());
payment.approvePayment(kakaoApprove.getApproved_at(), PaymentStatus.approve,kakaoApprove.getAmount().getTotal());
if(booking.getBookedRoomInfo() == null){
booking.getSeat().updateSeatStatus(false);
}
scheduleStatusCheck(booking.getBookingId(),payment); //30 분 후 상태 확인 작업 스케줄링
return kakaoApprove;
}
@Transactional
public void checkAndCancelBooking(Long bookingId) { //예약된 좌석이 결제 30분 후 아직 '입실 전' 상태 일 때 좌석 취소 시킴
System.out.println("checkAndCancelBooking");
printInfo();
Booking booking = bookingRepository.findByBookingId(bookingId);
if (booking != null && booking.getSeat() != null && booking.getStatus().equals(BookingStatus.beforeEnteringRoom)) {
booking.cancelBeforeEnteringSeat();
booking.getSeat().updateSeatStatus(true); // 좌석 사용 가능으로 변경
}
}
public void scheduleStatusCheck(Long bookingId, Payment payment) {
System.out.println("scheduleStatus Check");
printInfo();
LocalDateTime paymentTime = payment.getPaymentTime();
long delay = Duration.between(LocalDateTime.now(), paymentTime.plusMinutes(1)).toMillis();
if(delay>0){
scheduler.schedule(() -> checkAndCancelBooking(bookingId), delay, TimeUnit.MILLISECONDS);
}
}
}
if (booking != null && booking.getSeat() != null && booking.getStatus().equals(BookingStatus.beforeEnteringRoom)) {
booking.cancelBeforeEnteringSeat();
booking.getSeat().updateSeatStatus(true); // 좌석 사용 가능으로 변경
}
-> booking 테이블의 변경감지가 동작하지 않아 DB 에 업데이트 되지 않음
private void printInfo(){
boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
log.info("tx active={}",txActive );
}
→ 트랜잭션이 설정된 상태인지 확인해봄
→ scheduleStatusCheck() 메서드는 트랜잭션이 설정 되었지만 checkAndCancelBooking() 메서드는 트랜잭션이 설정되지 않음