package roomescape.payment.business import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import roomescape.payment.exception.PaymentErrorCode import roomescape.payment.exception.PaymentException import roomescape.payment.infrastructure.client.PaymentApproveResponse 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.PaymentCancelRequest import roomescape.payment.web.PaymentCancelResponse import roomescape.payment.web.PaymentCreateResponse import roomescape.payment.web.toCreateResponse import roomescape.reservation.infrastructure.persistence.ReservationEntity import java.time.OffsetDateTime @Service class PaymentService( private val paymentRepository: PaymentRepository, private val canceledPaymentRepository: CanceledPaymentRepository ) { @Transactional fun createPayment( approveResponse: PaymentApproveResponse, reservation: ReservationEntity ): PaymentCreateResponse { val payment = PaymentEntity( orderId = approveResponse.orderId, paymentKey = approveResponse.paymentKey, totalAmount = approveResponse.totalAmount, reservation = reservation, approvedAt = approveResponse.approvedAt ) return paymentRepository.save(payment).toCreateResponse() } @Transactional(readOnly = true) fun isReservationPaid(reservationId: Long): Boolean = paymentRepository.existsByReservationId(reservationId) @Transactional fun createCanceledPayment( cancelInfo: PaymentCancelResponse, approvedAt: OffsetDateTime, paymentKey: String ): CanceledPaymentEntity { val canceledPayment = CanceledPaymentEntity( paymentKey = paymentKey, cancelReason = cancelInfo.cancelReason, cancelAmount = cancelInfo.cancelAmount, approvedAt = approvedAt, canceledAt = cancelInfo.canceledAt ) return canceledPaymentRepository.save(canceledPayment) } @Transactional fun createCanceledPaymentByReservationId(reservationId: Long): PaymentCancelRequest { val paymentKey: String = paymentRepository.findPaymentKeyByReservationId(reservationId) ?: throw PaymentException(PaymentErrorCode.PAYMENT_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 payment: PaymentEntity = paymentRepository.findByPaymentKey(paymentKey) ?.also { paymentRepository.delete(it) } ?: throw PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) val canceledPayment = CanceledPaymentEntity( paymentKey = paymentKey, cancelReason = cancelReason, cancelAmount = payment.totalAmount, approvedAt = payment.approvedAt, canceledAt = canceledAt ) return canceledPaymentRepository.save(canceledPayment) } @Transactional fun updateCanceledTime( paymentKey: String, canceledAt: OffsetDateTime ) { canceledPaymentRepository.findByPaymentKey(paymentKey) ?.apply { this.canceledAt = canceledAt } ?: throw PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) } }