Compare commits
2 Commits
123b21cab2
...
fbaa1aa14c
Author | SHA1 | Date |
---|---|---|
|
fbaa1aa14c | |
|
fb66ea3347 |
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import kr.co.bootpay.Bootpay
|
import kr.co.bootpay.Bootpay
|
||||||
import kr.co.vividnext.sodalive.can.CanRepository
|
import kr.co.vividnext.sodalive.can.CanRepository
|
||||||
import kr.co.vividnext.sodalive.can.charge.event.ChargeSpringEvent
|
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.Payment
|
||||||
import kr.co.vividnext.sodalive.can.payment.PaymentGateway
|
import kr.co.vividnext.sodalive.can.payment.PaymentGateway
|
||||||
import kr.co.vividnext.sodalive.can.payment.PaymentStatus
|
import kr.co.vividnext.sodalive.can.payment.PaymentStatus
|
||||||
|
@ -29,6 +30,8 @@ class ChargeService(
|
||||||
private val chargeRepository: ChargeRepository,
|
private val chargeRepository: ChargeRepository,
|
||||||
private val canRepository: CanRepository,
|
private val canRepository: CanRepository,
|
||||||
private val memberRepository: MemberRepository,
|
private val memberRepository: MemberRepository,
|
||||||
|
private val couponNumberRepository: CanCouponNumberRepository,
|
||||||
|
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val okHttpClient: OkHttpClient,
|
private val okHttpClient: OkHttpClient,
|
||||||
private val applicationEventPublisher: ApplicationEventPublisher,
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
|
@ -43,6 +46,31 @@ class ChargeService(
|
||||||
private val appleInAppVerifyUrl: String
|
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
|
@Transactional
|
||||||
fun charge(member: Member, request: ChargeRequest): ChargeResponse {
|
fun charge(member: Member, request: ChargeRequest): ChargeResponse {
|
||||||
val can = canRepository.findByIdOrNull(request.canId)
|
val can = canRepository.findByIdOrNull(request.canId)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package kr.co.vividnext.sodalive.can.charge
|
package kr.co.vividnext.sodalive.can.charge
|
||||||
|
|
||||||
enum class ChargeStatus {
|
enum class ChargeStatus {
|
||||||
CHARGE, REFUND_CHARGE, EVENT, CANCEL,
|
CHARGE, REFUND_CHARGE, EVENT, COUPON, CANCEL,
|
||||||
|
|
||||||
// 관리자 지급
|
// 관리자 지급
|
||||||
ADMIN,
|
ADMIN,
|
||||||
|
|
|
@ -89,4 +89,19 @@ class CanCouponController(private val service: CanCouponService) {
|
||||||
)
|
)
|
||||||
.body(InputStreamResource(response))
|
.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!!
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -8,6 +8,16 @@ interface CanCouponNumberRepository : JpaRepository<CanCouponNumber, Long>, CanC
|
||||||
|
|
||||||
interface CanCouponNumberQueryRepository {
|
interface CanCouponNumberQueryRepository {
|
||||||
fun getUseCouponCount(id: Long): Int
|
fun getUseCouponCount(id: Long): Int
|
||||||
|
|
||||||
|
fun getCouponNumberTotalCount(couponId: Long): Int
|
||||||
|
|
||||||
|
fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List<GetCouponNumberListItemResponse>
|
||||||
|
|
||||||
|
fun getAllCouponNumberList(couponId: Long): List<GetCouponNumberListItemResponse>
|
||||||
|
|
||||||
|
fun findByCouponNumber(couponNumber: String): CanCouponNumber?
|
||||||
|
|
||||||
|
fun findByMemberId(memberId: Long): List<Long>
|
||||||
}
|
}
|
||||||
|
|
||||||
class CanCouponNumberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponNumberQueryRepository {
|
class CanCouponNumberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponNumberQueryRepository {
|
||||||
|
@ -19,4 +29,60 @@ class CanCouponNumberQueryRepositoryImpl(private val queryFactory: JPAQueryFacto
|
||||||
.fetch()
|
.fetch()
|
||||||
.size
|
.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getCouponNumberTotalCount(couponId: Long): Int {
|
||||||
|
return queryFactory
|
||||||
|
.select(canCouponNumber.id)
|
||||||
|
.from(canCouponNumber)
|
||||||
|
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
||||||
|
.fetch()
|
||||||
|
.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List<GetCouponNumberListItemResponse> {
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QGetCouponNumberListItemResponse(
|
||||||
|
canCouponNumber.id,
|
||||||
|
canCouponNumber.couponNumber,
|
||||||
|
canCouponNumber.member.isNotNull
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(canCouponNumber)
|
||||||
|
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
||||||
|
.orderBy(canCouponNumber.id.asc())
|
||||||
|
.offset(offset)
|
||||||
|
.limit(limit)
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAllCouponNumberList(couponId: Long): List<GetCouponNumberListItemResponse> {
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QGetCouponNumberListItemResponse(
|
||||||
|
canCouponNumber.id,
|
||||||
|
canCouponNumber.couponNumber,
|
||||||
|
canCouponNumber.member.isNotNull
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(canCouponNumber)
|
||||||
|
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
||||||
|
.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<Long> {
|
||||||
|
return queryFactory
|
||||||
|
.select(canCouponNumber.id)
|
||||||
|
.from(canCouponNumber)
|
||||||
|
.where(canCouponNumber.member.id.eq(memberId))
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.can.coupon
|
||||||
|
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
import kr.co.vividnext.sodalive.can.coupon.QCanCoupon.canCoupon
|
import kr.co.vividnext.sodalive.can.coupon.QCanCoupon.canCoupon
|
||||||
import kr.co.vividnext.sodalive.can.coupon.QCanCouponNumber.canCouponNumber
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
interface CanCouponRepository : JpaRepository<CanCoupon, Long>, CanCouponQueryRepository
|
interface CanCouponRepository : JpaRepository<CanCoupon, Long>, CanCouponQueryRepository
|
||||||
|
@ -10,10 +9,6 @@ interface CanCouponRepository : JpaRepository<CanCoupon, Long>, CanCouponQueryRe
|
||||||
interface CanCouponQueryRepository {
|
interface CanCouponQueryRepository {
|
||||||
fun getCouponTotalCount(): Int
|
fun getCouponTotalCount(): Int
|
||||||
fun getCouponList(offset: Long, limit: Long): List<CanCoupon>
|
fun getCouponList(offset: Long, limit: Long): List<CanCoupon>
|
||||||
fun getCouponNumberTotalCount(couponId: Long): Int
|
|
||||||
fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List<GetCouponNumberListItemResponse>
|
|
||||||
|
|
||||||
fun getAllCouponNumberList(couponId: Long): List<GetCouponNumberListItemResponse>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CanCouponQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponQueryRepository {
|
class CanCouponQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanCouponQueryRepository {
|
||||||
|
@ -33,45 +28,4 @@ class CanCouponQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) :
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCouponNumberTotalCount(couponId: Long): Int {
|
|
||||||
return queryFactory
|
|
||||||
.select(canCouponNumber.id)
|
|
||||||
.from(canCouponNumber)
|
|
||||||
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
|
||||||
.fetch()
|
|
||||||
.size
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): List<GetCouponNumberListItemResponse> {
|
|
||||||
return queryFactory
|
|
||||||
.select(
|
|
||||||
QGetCouponNumberListItemResponse(
|
|
||||||
canCouponNumber.id,
|
|
||||||
canCouponNumber.couponNumber,
|
|
||||||
canCouponNumber.member.isNotNull
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.from(canCouponNumber)
|
|
||||||
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
|
||||||
.orderBy(canCouponNumber.id.asc())
|
|
||||||
.offset(offset)
|
|
||||||
.limit(limit)
|
|
||||||
.fetch()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAllCouponNumberList(couponId: Long): List<GetCouponNumberListItemResponse> {
|
|
||||||
return queryFactory
|
|
||||||
.select(
|
|
||||||
QGetCouponNumberListItemResponse(
|
|
||||||
canCouponNumber.id,
|
|
||||||
canCouponNumber.couponNumber,
|
|
||||||
canCouponNumber.member.isNotNull
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.from(canCouponNumber)
|
|
||||||
.where(canCouponNumber.canCoupon.id.eq(couponId))
|
|
||||||
.orderBy(canCouponNumber.id.asc())
|
|
||||||
.fetch()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,12 @@ package kr.co.vividnext.sodalive.can.coupon
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import kr.co.vividnext.sodalive.aws.sqs.SqsEvent
|
import kr.co.vividnext.sodalive.aws.sqs.SqsEvent
|
||||||
import kr.co.vividnext.sodalive.aws.sqs.SqsEventType
|
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.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
||||||
import org.springframework.context.ApplicationEventPublisher
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
@ -14,9 +17,14 @@ import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class CanCouponService(
|
class CanCouponService(
|
||||||
|
private val issueService: CanCouponIssueService,
|
||||||
|
private val chargeService: ChargeService,
|
||||||
|
|
||||||
private val repository: CanCouponRepository,
|
private val repository: CanCouponRepository,
|
||||||
private val couponNumberRepository: CanCouponNumberRepository,
|
private val couponNumberRepository: CanCouponNumberRepository,
|
||||||
|
|
||||||
|
private val memberRepository: MemberRepository,
|
||||||
|
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val applicationEventPublisher: ApplicationEventPublisher
|
private val applicationEventPublisher: ApplicationEventPublisher
|
||||||
) {
|
) {
|
||||||
|
@ -49,15 +57,15 @@ class CanCouponService(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): GetCouponNumberListResponse {
|
fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): GetCouponNumberListResponse {
|
||||||
val totalCount = repository.getCouponNumberTotalCount(couponId = couponId)
|
val totalCount = couponNumberRepository.getCouponNumberTotalCount(couponId = couponId)
|
||||||
val items = repository.getCouponNumberList(couponId = couponId, offset = offset, limit = limit)
|
val items = couponNumberRepository.getCouponNumberList(couponId = couponId, offset = offset, limit = limit)
|
||||||
return GetCouponNumberListResponse(totalCount, items)
|
return GetCouponNumberListResponse(totalCount, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadCouponNumberList(couponId: Long): ByteArrayInputStream {
|
fun downloadCouponNumberList(couponId: Long): ByteArrayInputStream {
|
||||||
val header = listOf("순번", "쿠폰번호", "사용여부")
|
val header = listOf("순번", "쿠폰번호", "사용여부")
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
val couponNumberList = repository.getAllCouponNumberList(couponId)
|
val couponNumberList = couponNumberRepository.getAllCouponNumberList(couponId)
|
||||||
|
|
||||||
val workbook = XSSFWorkbook()
|
val workbook = XSSFWorkbook()
|
||||||
try {
|
try {
|
||||||
|
@ -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 {
|
private fun insertHyphens(input: String): String {
|
||||||
return input.chunked(4).joinToString("-")
|
return input.chunked(4).joinToString("-")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package kr.co.vividnext.sodalive.can.coupon
|
||||||
|
|
||||||
|
data class UseCanCouponRequest(val couponNumber: String)
|
Loading…
Reference in New Issue