From fbaa1aa14ce22a3d66ef6797cdb635d86fce8082 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 3 Jan 2024 04:11:32 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BF=A0=ED=8F=B0=20=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/can/charge/ChargeService.kt | 28 +++++++++++++++++ .../sodalive/can/charge/ChargeStatus.kt | 2 +- .../can/coupon/CanCouponController.kt | 15 +++++++++ .../can/coupon/CanCouponIssueService.kt | 31 +++++++++++++++++++ .../can/coupon/CanCouponNumberRepository.kt | 19 ++++++++++++ .../sodalive/can/coupon/CanCouponService.kt | 19 ++++++++++++ .../can/coupon/UseCanCouponRequest.kt | 3 ++ 7 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponIssueService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/UseCanCouponRequest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt index a8756b5..25cb5ca 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import kr.co.bootpay.Bootpay import kr.co.vividnext.sodalive.can.CanRepository import kr.co.vividnext.sodalive.can.charge.event.ChargeSpringEvent +import kr.co.vividnext.sodalive.can.coupon.CanCouponNumberRepository import kr.co.vividnext.sodalive.can.payment.Payment import kr.co.vividnext.sodalive.can.payment.PaymentGateway import kr.co.vividnext.sodalive.can.payment.PaymentStatus @@ -29,6 +30,8 @@ class ChargeService( private val chargeRepository: ChargeRepository, private val canRepository: CanRepository, private val memberRepository: MemberRepository, + private val couponNumberRepository: CanCouponNumberRepository, + private val objectMapper: ObjectMapper, private val okHttpClient: OkHttpClient, private val applicationEventPublisher: ApplicationEventPublisher, @@ -43,6 +46,31 @@ class ChargeService( private val appleInAppVerifyUrl: String ) { + @Transactional + fun chargeByCoupon(couponNumber: String, member: Member) { + val canCouponNumber = couponNumberRepository.findByCouponNumber(couponNumber = couponNumber) + ?: throw SodaException("잘못된 쿠폰번호입니다.\n고객센터로 문의해 주시기 바랍니다.") + + if (canCouponNumber.member != null) { + throw SodaException("이미 사용한 쿠폰번호 입니다.") + } + + val coupon = canCouponNumber.canCoupon!! + val couponCharge = Charge(0, coupon.can, status = ChargeStatus.COUPON) + couponCharge.title = "${coupon.can} 캔" + couponCharge.member = member + + val payment = Payment( + status = PaymentStatus.COMPLETE, + paymentGateway = PaymentGateway.PG + ) + payment.method = coupon.couponName + couponCharge.payment = payment + chargeRepository.save(couponCharge) + + member.charge(0, coupon.can, "pg") + } + @Transactional fun charge(member: Member, request: ChargeRequest): ChargeResponse { val can = canRepository.findByIdOrNull(request.canId) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeStatus.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeStatus.kt index 1585dcd..c31a16d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeStatus.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeStatus.kt @@ -1,7 +1,7 @@ package kr.co.vividnext.sodalive.can.charge enum class ChargeStatus { - CHARGE, REFUND_CHARGE, EVENT, CANCEL, + CHARGE, REFUND_CHARGE, EVENT, COUPON, CANCEL, // 관리자 지급 ADMIN, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt index c67c4f7..5962f3a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponController.kt @@ -89,4 +89,19 @@ class CanCouponController(private val service: CanCouponService) { ) .body(InputStreamResource(response)) } + + @PostMapping("/use") + fun useCanCoupon( + @RequestBody request: UseCanCouponRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.useCanCoupon( + couponNumber = request.couponNumber, + memberId = member.id!! + ) + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponIssueService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponIssueService.kt new file mode 100644 index 0000000..547e7fa --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponIssueService.kt @@ -0,0 +1,31 @@ +package kr.co.vividnext.sodalive.can.coupon + +import kr.co.vividnext.sodalive.common.SodaException +import org.springframework.stereotype.Service + +@Service +class CanCouponIssueService(private val couponNumberRepository: CanCouponNumberRepository) { + fun validateAvailableUseCoupon(couponNumber: String, memberId: Long) { + val canCouponNumber = checkCanCouponNumber(couponNumber) + + if (!isMultipleUse(canCouponNumber)) { + val canCouponNumberList = couponNumberRepository.findByMemberId(memberId = memberId) + if (canCouponNumberList.isNotEmpty()) { + throw SodaException("해당 쿠폰은 1회만 충전이 가능합니다.") + } + } + } + + private fun checkCanCouponNumber(couponNumber: String): CanCouponNumber { + val canCouponNumber = couponNumberRepository.findByCouponNumber(couponNumber = couponNumber) + ?: throw SodaException("잘못된 쿠폰번호입니다.\n고객센터로 문의해 주시기 바랍니다.") + + if (canCouponNumber.member != null) { + throw SodaException("이미 사용한 쿠폰번호 입니다.") + } + + return canCouponNumber + } + + private fun isMultipleUse(canCouponNumber: CanCouponNumber) = canCouponNumber.canCoupon!!.isMultipleUse +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponNumberRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponNumberRepository.kt index c51c98c..0e4ccd1 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponNumberRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponNumberRepository.kt @@ -14,6 +14,10 @@ interface CanCouponNumberQueryRepository { fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List fun getAllCouponNumberList(couponId: Long): List + + fun findByCouponNumber(couponNumber: String): CanCouponNumber? + + fun findByMemberId(memberId: Long): List } class CanCouponNumberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponNumberQueryRepository { @@ -66,4 +70,19 @@ class CanCouponNumberQueryRepositoryImpl(private val queryFactory: JPAQueryFacto .orderBy(canCouponNumber.id.asc()) .fetch() } + + override fun findByCouponNumber(couponNumber: String): CanCouponNumber? { + return queryFactory + .selectFrom(canCouponNumber) + .where(canCouponNumber.couponNumber.eq(couponNumber)) + .fetchFirst() + } + + override fun findByMemberId(memberId: Long): List { + return queryFactory + .select(canCouponNumber.id) + .from(canCouponNumber) + .where(canCouponNumber.member.id.eq(memberId)) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt index e5b95bc..f0474b8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/CanCouponService.kt @@ -3,9 +3,12 @@ package kr.co.vividnext.sodalive.can.coupon import com.fasterxml.jackson.databind.ObjectMapper import kr.co.vividnext.sodalive.aws.sqs.SqsEvent import kr.co.vividnext.sodalive.aws.sqs.SqsEventType +import kr.co.vividnext.sodalive.can.charge.ChargeService import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.MemberRepository import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.springframework.context.ApplicationEventPublisher +import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream @@ -14,9 +17,14 @@ import java.time.format.DateTimeFormatter @Service class CanCouponService( + private val issueService: CanCouponIssueService, + private val chargeService: ChargeService, + private val repository: CanCouponRepository, private val couponNumberRepository: CanCouponNumberRepository, + private val memberRepository: MemberRepository, + private val objectMapper: ObjectMapper, private val applicationEventPublisher: ApplicationEventPublisher ) { @@ -91,6 +99,17 @@ class CanCouponService( } } + fun useCanCoupon(couponNumber: String, memberId: Long) { + val member = memberRepository.findByIdOrNull(id = memberId) + ?: throw SodaException("로그인 정보를 확인해주세요.") + + if (member.auth == null) throw SodaException("쿠폰은 본인인증을 하셔야 사용이 가능합니다.") + + issueService.validateAvailableUseCoupon(couponNumber, memberId) + + chargeService.chargeByCoupon(couponNumber, member) + } + private fun insertHyphens(input: String): String { return input.chunked(4).joinToString("-") } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/UseCanCouponRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/UseCanCouponRequest.kt new file mode 100644 index 0000000..b0083ea --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/coupon/UseCanCouponRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.can.coupon + +data class UseCanCouponRequest(val couponNumber: String)