diff --git a/tosspay-mock/src/main/kotlin/com/sangdol/tosspaymock/business/TosspayService.kt b/tosspay-mock/src/main/kotlin/com/sangdol/tosspaymock/business/TosspayService.kt new file mode 100644 index 00000000..4aa64069 --- /dev/null +++ b/tosspay-mock/src/main/kotlin/com/sangdol/tosspaymock/business/TosspayService.kt @@ -0,0 +1,111 @@ +package com.sangdol.tosspaymock.business + +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.tosspaymock.business.domain.Payment +import com.sangdol.tosspaymock.business.domain.cancel.Cancellation +import com.sangdol.tosspaymock.exception.TosspayException +import com.sangdol.tosspaymock.exception.code.TosspayCancelErrorCode +import com.sangdol.tosspaymock.infrastructure.persistence.OrderAmountEntity +import com.sangdol.tosspaymock.infrastructure.persistence.OrderAmountRepository +import com.sangdol.tosspaymock.web.dto.PaymentCancelRequest +import com.sangdol.tosspaymock.web.dto.PaymentConfirmRequest +import com.sangdol.tosspaymock.web.dto.PaymentResponse +import io.github.oshai.kotlinlogging.KLogger +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.stereotype.Service + +private val log: KLogger = KotlinLogging.logger {} + +@Service +class TosspayService( + private val idGenerator: IDGenerator, + private val orderAmountRepository: OrderAmountRepository, +) { + + fun confirm(request: PaymentConfirmRequest): PaymentResponse { + log.info { "[TosspayService.confirm] 결제 확정 시작: paymentKey=${request.paymentKey}, amount=${request.amount}" } + + val payment = choosePayment(request).also { saveAmount(request.paymentKey, it) } + + return payment.toResponse() + .also { + log.info { "[TosspayService.confirm] 결제 확정 완료: paymentKey=${request.paymentKey}, amount=${request.amount}" } + } + } + + fun cancel(paymentKey: String, request: PaymentCancelRequest): PaymentResponse { + log.info { "[TosspayService.cancel] 결제 취소 시작: paymentKey=${paymentKey}" } + + val orderAmount = orderAmountRepository.findByPaymentKey(paymentKey) + ?: throw TosspayException(TosspayCancelErrorCode.NOT_FOUND_PAYMENT) + + val cancellation = Cancellation.random( + cancelReason = request.cancelReason, + cancelAmount = request.cancelAmount ?: orderAmount.totalAmount(), + easyPayDiscountAmount = orderAmount.easypayDiscountAmount, + cardDiscountAmount = orderAmount.cardDiscountAmount, + transferDiscountAmount = orderAmount.transferDiscountAmount + ) + + return Payment.randomForCancellation(paymentKey, cancellation) + .toResponse() + .also { + log.info { "[TosspayService.cancel] 결제 취소 완료: paymentKey=${paymentKey}" } + } + } + + private fun choosePayment(request: PaymentConfirmRequest): Payment { + log.info { "[TosspayService.choosePayment] 랜덤 결제 정보 생성 시작: paymentKey=${request.paymentKey}, amount=${request.amount}" } + val randomValue = Math.random() + + // 70%는 간편결제에 배정 + return if (randomValue < 0.7) { + // 70%의 간편결제 중 70%는 카드 + if (randomValue < 0.49) { + Payment.randomWithEasypayCard( + request.paymentKey, request.orderId, request.amount, request.requestedAt + ).also { + log.info { "[Tosspayment.choosePayment] 간편결제 + 카드 결제 객체 생성 완료" } + } + } else { // 30%는 간편결제 선불 충전액 + Payment.randomWithEasypayPrepaid( + request.paymentKey, request.orderId, request.amount, request.requestedAt + ).also { + log.info { "[Tosspayment.choosePayment] 간편결제 + 충전식 결제 객체 생성 완료" } + } + } + } else if (randomValue < 0.95) { // 남은 30% 중 25%는 일반 카드 + Payment.randomWithCard( + request.paymentKey, request.orderId, request.amount, request.requestedAt + ).also { + log.info { "[Tosspayment.choosePayment] 카드 결제 객체 생성 완료" } + } + } else { // 나머지는 계좌이체 + Payment.randomWithBankTransfer( + request.paymentKey, request.orderId, request.amount, request.requestedAt + ).also { + log.info { "[Tosspayment.choosePayment] 계좌이체 결제 객체 생성 완료" } + } + } + } + + private fun saveAmount(paymentKey: String, payment: Payment) { + log.info { "[Tosspayment.saveAmount] 결제 금액 정보 저장 시작: paymentKey=${paymentKey}" } + val easypayDiscountAmount = payment.easyPay?.discountAmount ?: 0 + val cardDiscountAmount = 0 + val transferDiscountAmount = 0 + + val orderAmount = OrderAmountEntity( + idGenerator.create(), + paymentKey, + (payment.totalAmount - easypayDiscountAmount), + easypayDiscountAmount, + cardDiscountAmount, + transferDiscountAmount + ) + + orderAmountRepository.save(orderAmount).also { + log.info { "[Tosspayment.saveAmount] 결제 금액 정보 저장 완료: id=${it.id}, paymentKey=${paymentKey}, amount=${orderAmount.approvedAmount}, easypayDiscount=${orderAmount.easypayDiscountAmount}" } + } + } +}