package roomescape.payment.business import org.springframework.http.HttpStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository import roomescape.payment.infrastructure.persistence.PaymentEntity import roomescape.payment.infrastructure.persistence.PaymentRepository import roomescape.payment.web.* import roomescape.reservation.infrastructure.persistence.ReservationEntity import java.time.OffsetDateTime @Service class PaymentService( private val paymentRepository: PaymentRepository, private val canceledPaymentRepository: CanceledPaymentRepository ) { @Transactional fun createPayment( paymentResponse: PaymentApproveResponse, reservation: ReservationEntity ): ReservationPaymentResponse = PaymentEntity( orderId = paymentResponse.orderId, paymentKey = paymentResponse.paymentKey, totalAmount = paymentResponse.totalAmount, reservation = reservation, approvedAt = paymentResponse.approvedAt ).also { paymentRepository.save(it) }.toReservationPaymentResponse() @Transactional(readOnly = true) fun isReservationPaid( reservationId: Long ): Boolean = paymentRepository.existsByReservationId(reservationId) @Transactional fun createCanceledPayment( cancelInfo: PaymentCancelResponse, approvedAt: OffsetDateTime, paymentKey: String ): CanceledPaymentEntity = CanceledPaymentEntity( paymentKey = paymentKey, cancelReason = cancelInfo.cancelReason, cancelAmount = cancelInfo.cancelAmount, approvedAt = approvedAt, canceledAt = cancelInfo.canceledAt ).also { canceledPaymentRepository.save(it) } @Transactional fun createCanceledPaymentByReservationId(reservationId: Long): PaymentCancelRequest { val paymentKey: String = paymentRepository.findPaymentKeyByReservationId(reservationId) ?: throw RoomescapeException( ErrorType.PAYMENT_NOT_FOUND, "[reservationId: $reservationId]", HttpStatus.NOT_FOUND ) // 취소 시간은 현재 시간으로 일단 생성한 뒤, 결제 취소 완료 후 해당 시간으로 변경합니다. val canceled: CanceledPaymentEntity = cancelPayment(paymentKey) return PaymentCancelRequest(paymentKey, canceled.cancelAmount, canceled.cancelReason) } private fun cancelPayment( paymentKey: String, cancelReason: String = "고객 요청", canceledAt: OffsetDateTime = OffsetDateTime.now() ): CanceledPaymentEntity { val paymentEntity: PaymentEntity = paymentRepository.findByPaymentKey(paymentKey) ?.also { paymentRepository.delete(it) } ?: throw RoomescapeException( ErrorType.PAYMENT_NOT_FOUND, "[paymentKey: $paymentKey]", HttpStatus.NOT_FOUND ) return CanceledPaymentEntity( paymentKey = paymentKey, cancelReason = cancelReason, cancelAmount = paymentEntity.totalAmount, approvedAt = paymentEntity.approvedAt, canceledAt = canceledAt ).also { canceledPaymentRepository.save(it) } } @Transactional fun updateCanceledTime( paymentKey: String, canceledAt: OffsetDateTime ) { canceledPaymentRepository.findByPaymentKey(paymentKey)?.let { it.canceledAt = canceledAt } ?: throw RoomescapeException( ErrorType.PAYMENT_NOT_FOUND, "[paymentKey: $paymentKey]", HttpStatus.NOT_FOUND ) } }