From 05145ec2ba89de5d7571bcb72fb01cda91d46a40 Mon Sep 17 00:00:00 2001 From: pricelees Date: Wed, 1 Oct 2025 10:51:22 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=84=EC=9D=98=EC=9D=98=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tosspaymock/business/TosspayService.kt | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tosspay-mock/src/main/kotlin/com/sangdol/tosspaymock/business/TosspayService.kt 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}" } + } + } +}