Compare commits

..

No commits in common. "fbaa1aa14ce22a3d66ef6797cdb635d86fce8082" and "123b21cab2f35c75d17d2396a234f40cb5364501" have entirely different histories.

8 changed files with 50 additions and 166 deletions

View File

@ -4,7 +4,6 @@ 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
@ -30,8 +29,6 @@ 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,
@ -46,31 +43,6 @@ 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)

View File

@ -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, COUPON, CANCEL, CHARGE, REFUND_CHARGE, EVENT, CANCEL,
// 관리자 지급 // 관리자 지급
ADMIN, ADMIN,

View File

@ -89,19 +89,4 @@ 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!!
)
)
}
} }

View File

@ -1,31 +0,0 @@
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
}

View File

@ -8,16 +8,6 @@ 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 {
@ -29,60 +19,4 @@ 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()
}
} }

View File

@ -2,6 +2,7 @@ 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
@ -9,6 +10,10 @@ 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 {
@ -28,4 +33,45 @@ 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()
}
} }

View File

@ -3,12 +3,9 @@ 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
@ -17,14 +14,9 @@ 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
) { ) {
@ -57,15 +49,15 @@ class CanCouponService(
} }
fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): GetCouponNumberListResponse { fun getCouponNumberList(couponId: Long, offset: Long, limit: Long): GetCouponNumberListResponse {
val totalCount = couponNumberRepository.getCouponNumberTotalCount(couponId = couponId) val totalCount = repository.getCouponNumberTotalCount(couponId = couponId)
val items = couponNumberRepository.getCouponNumberList(couponId = couponId, offset = offset, limit = limit) val items = repository.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 = couponNumberRepository.getAllCouponNumberList(couponId) val couponNumberList = repository.getAllCouponNumberList(couponId)
val workbook = XSSFWorkbook() val workbook = XSSFWorkbook()
try { try {
@ -99,17 +91,6 @@ 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("-")
} }

View File

@ -1,3 +0,0 @@
package kr.co.vividnext.sodalive.can.coupon
data class UseCanCouponRequest(val couponNumber: String)