parent
81b11976a7
commit
72d10f9443
|
@ -0,0 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.can.charge
|
||||
|
||||
data class ChargeCompleteResponse(
|
||||
val price: Double,
|
||||
val currencyCode: String,
|
||||
val isFirstCharged: Boolean
|
||||
)
|
|
@ -3,17 +3,22 @@ package kr.co.vividnext.sodalive.can.charge
|
|||
import kr.co.vividnext.sodalive.can.payment.PaymentGateway
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.marketing.AdTrackingHistoryType
|
||||
import kr.co.vividnext.sodalive.marketing.AdTrackingService
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/charge")
|
||||
class ChargeController(private val service: ChargeService) {
|
||||
class ChargeController(
|
||||
private val service: ChargeService,
|
||||
private val trackingService: AdTrackingService
|
||||
) {
|
||||
|
||||
@PostMapping
|
||||
fun charge(
|
||||
|
@ -30,14 +35,30 @@ class ChargeController(private val service: ChargeService) {
|
|||
@PostMapping("/verify")
|
||||
fun verify(
|
||||
@RequestBody verifyRequest: VerifyRequest,
|
||||
@AuthenticationPrincipal user: User
|
||||
) = ApiResponse.ok(service.verify(user, verifyRequest))
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
) = run {
|
||||
if (member == null) {
|
||||
throw SodaException("로그인 정보를 확인해주세요.")
|
||||
}
|
||||
|
||||
val response = service.verify(memberId = member.id!!, verifyRequest)
|
||||
trackingCharge(member, response)
|
||||
ApiResponse.ok(Unit)
|
||||
}
|
||||
|
||||
@PostMapping("/verify/hecto")
|
||||
fun verifyHecto(
|
||||
@RequestBody verifyRequest: VerifyRequest,
|
||||
@AuthenticationPrincipal user: User
|
||||
) = ApiResponse.ok(service.verifyHecto(user, verifyRequest))
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
) = run {
|
||||
if (member == null) {
|
||||
throw SodaException("로그인 정보를 확인해주세요.")
|
||||
}
|
||||
|
||||
val response = service.verifyHecto(memberId = member.id!!, verifyRequest)
|
||||
trackingCharge(member, response)
|
||||
ApiResponse.ok(Unit)
|
||||
}
|
||||
|
||||
@PostMapping("/apple")
|
||||
fun appleCharge(
|
||||
|
@ -54,8 +75,16 @@ class ChargeController(private val service: ChargeService) {
|
|||
@PostMapping("/apple/verify")
|
||||
fun appleVerify(
|
||||
@RequestBody verifyRequest: AppleVerifyRequest,
|
||||
@AuthenticationPrincipal user: User
|
||||
) = ApiResponse.ok(service.appleVerify(user, verifyRequest))
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
) = run {
|
||||
if (member == null) {
|
||||
throw SodaException("로그인 정보를 확인해주세요.")
|
||||
}
|
||||
|
||||
val response = service.appleVerify(memberId = member.id!!, verifyRequest)
|
||||
trackingCharge(member, response)
|
||||
ApiResponse.ok(Unit)
|
||||
}
|
||||
|
||||
@PostMapping("/google")
|
||||
fun googleCharge(
|
||||
|
@ -78,17 +107,40 @@ class ChargeController(private val service: ChargeService) {
|
|||
paymentGateway = request.paymentGateway
|
||||
)
|
||||
|
||||
ApiResponse.ok(
|
||||
service.processGoogleIap(
|
||||
val response = service.processGoogleIap(
|
||||
memberId = member.id!!,
|
||||
chargeId = chargeId,
|
||||
productId = request.productId,
|
||||
purchaseToken = request.purchaseToken,
|
||||
paymentGateway = request.paymentGateway
|
||||
)
|
||||
)
|
||||
|
||||
trackingCharge(member, response)
|
||||
ApiResponse.ok(Unit)
|
||||
} else {
|
||||
throw SodaException("결제정보에 오류가 있습니다.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun trackingCharge(
|
||||
member: Member,
|
||||
response: ChargeCompleteResponse
|
||||
) {
|
||||
if (
|
||||
!member.activePid.isNullOrBlank() &&
|
||||
member.partnerExpirationDatetime?.isAfter(LocalDateTime.now()) == true
|
||||
) {
|
||||
trackingService.saveTrackingHistory(
|
||||
pid = member.activePid!!,
|
||||
type = if (response.isFirstCharged) {
|
||||
AdTrackingHistoryType.FIRST_PAYMENT
|
||||
} else {
|
||||
AdTrackingHistoryType.REPEAT_PAYMENT
|
||||
},
|
||||
memberId = member.id!!,
|
||||
price = response.price,
|
||||
locale = response.currencyCode
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ interface ChargeQueryRepository {
|
|||
fun getOldestChargeWhereRewardCanGreaterThan0(chargeId: Long, memberId: Long, container: String): Charge?
|
||||
fun getOldestChargeWhereChargeCanGreaterThan0(chargeId: Long, memberId: Long, container: String): Charge?
|
||||
fun getChargeCountAfterDate(memberId: Long, date: LocalDateTime): Int
|
||||
fun isFirstCharged(memberId: Long): Boolean
|
||||
}
|
||||
|
||||
class ChargeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : ChargeQueryRepository {
|
||||
|
@ -76,6 +77,21 @@ class ChargeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Cha
|
|||
.size
|
||||
}
|
||||
|
||||
override fun isFirstCharged(memberId: Long): Boolean {
|
||||
return queryFactory
|
||||
.select(charge.id)
|
||||
.from(charge)
|
||||
.innerJoin(charge.member, member)
|
||||
.innerJoin(charge.payment, payment)
|
||||
.where(
|
||||
member.id.eq(memberId),
|
||||
charge.status.eq(ChargeStatus.CHARGE),
|
||||
payment.status.eq(PaymentStatus.COMPLETE)
|
||||
)
|
||||
.fetch()
|
||||
.size <= 1
|
||||
}
|
||||
|
||||
private fun getPaymentGatewayCondition(container: String): BooleanExpression? {
|
||||
val paymentGatewayCondition = when (container) {
|
||||
"aos" -> {
|
||||
|
|
|
@ -23,9 +23,10 @@ import org.springframework.data.repository.findByIdOrNull
|
|||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.retry.annotation.Backoff
|
||||
import org.springframework.retry.annotation.Retryable
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
@Service
|
||||
@Transactional(readOnly = true)
|
||||
|
@ -102,10 +103,10 @@ class ChargeService(
|
|||
}
|
||||
|
||||
@Transactional
|
||||
fun verify(user: User, verifyRequest: VerifyRequest) {
|
||||
fun verify(memberId: Long, verifyRequest: VerifyRequest): ChargeCompleteResponse {
|
||||
val charge = chargeRepository.findByIdOrNull(verifyRequest.orderId.toLong())
|
||||
?: throw SodaException("결제정보에 오류가 있습니다.")
|
||||
val member = memberRepository.findByEmail(user.username)
|
||||
val member = memberRepository.findByIdOrNull(memberId)
|
||||
?: throw SodaException("로그인 정보를 확인해주세요.")
|
||||
|
||||
if (charge.payment!!.paymentGateway == PaymentGateway.PG) {
|
||||
|
@ -130,6 +131,12 @@ class ChargeService(
|
|||
memberId = member.id!!
|
||||
)
|
||||
)
|
||||
|
||||
return ChargeCompleteResponse(
|
||||
price = BigDecimal(charge.payment!!.price).setScale(2, RoundingMode.HALF_UP).toDouble(),
|
||||
currencyCode = charge.payment!!.locale?.takeLast(3) ?: "KRW",
|
||||
isFirstCharged = chargeRepository.isFirstCharged(memberId)
|
||||
)
|
||||
} else {
|
||||
throw SodaException("결제정보에 오류가 있습니다.")
|
||||
}
|
||||
|
@ -142,10 +149,10 @@ class ChargeService(
|
|||
}
|
||||
|
||||
@Transactional
|
||||
fun verifyHecto(user: User, verifyRequest: VerifyRequest) {
|
||||
fun verifyHecto(memberId: Long, verifyRequest: VerifyRequest): ChargeCompleteResponse {
|
||||
val charge = chargeRepository.findByIdOrNull(verifyRequest.orderId.toLong())
|
||||
?: throw SodaException("결제정보에 오류가 있습니다.")
|
||||
val member = memberRepository.findByEmail(user.username)
|
||||
val member = memberRepository.findByIdOrNull(memberId)
|
||||
?: throw SodaException("로그인 정보를 확인해주세요.")
|
||||
|
||||
if (charge.payment!!.paymentGateway == PaymentGateway.PG) {
|
||||
|
@ -174,6 +181,12 @@ class ChargeService(
|
|||
memberId = member.id!!
|
||||
)
|
||||
)
|
||||
|
||||
return ChargeCompleteResponse(
|
||||
price = BigDecimal(charge.payment!!.price).setScale(2, RoundingMode.HALF_UP).toDouble(),
|
||||
currencyCode = charge.payment!!.locale?.takeLast(3) ?: "KRW",
|
||||
isFirstCharged = chargeRepository.isFirstCharged(memberId)
|
||||
)
|
||||
} else {
|
||||
throw SodaException("결제정보에 오류가 있습니다.")
|
||||
}
|
||||
|
@ -208,10 +221,10 @@ class ChargeService(
|
|||
}
|
||||
|
||||
@Transactional
|
||||
fun appleVerify(user: User, verifyRequest: AppleVerifyRequest) {
|
||||
fun appleVerify(memberId: Long, verifyRequest: AppleVerifyRequest): ChargeCompleteResponse {
|
||||
val charge = chargeRepository.findByIdOrNull(verifyRequest.chargeId)
|
||||
?: throw SodaException("결제정보에 오류가 있습니다.")
|
||||
val member = memberRepository.findByEmail(user.username)
|
||||
val member = memberRepository.findByIdOrNull(memberId)
|
||||
?: throw SodaException("로그인 정보를 확인해주세요.")
|
||||
|
||||
if (charge.payment!!.paymentGateway == PaymentGateway.APPLE_IAP) {
|
||||
|
@ -228,6 +241,12 @@ class ChargeService(
|
|||
memberId = member.id!!
|
||||
)
|
||||
)
|
||||
|
||||
return ChargeCompleteResponse(
|
||||
price = BigDecimal(charge.payment!!.price).setScale(2, RoundingMode.HALF_UP).toDouble(),
|
||||
currencyCode = charge.payment!!.locale?.takeLast(3) ?: "KRW",
|
||||
isFirstCharged = chargeRepository.isFirstCharged(memberId)
|
||||
)
|
||||
} else {
|
||||
throw SodaException("결제정보에 오류가 있습니다.")
|
||||
}
|
||||
|
@ -271,7 +290,7 @@ class ChargeService(
|
|||
productId: String,
|
||||
purchaseToken: String,
|
||||
paymentGateway: PaymentGateway
|
||||
) {
|
||||
): ChargeCompleteResponse {
|
||||
val charge = chargeRepository.findByIdOrNull(id = chargeId)
|
||||
?: throw SodaException("결제정보에 오류가 있습니다.")
|
||||
val member = memberRepository.findByIdOrNull(id = memberId)
|
||||
|
@ -290,6 +309,12 @@ class ChargeService(
|
|||
memberId = member.id!!
|
||||
)
|
||||
)
|
||||
|
||||
return ChargeCompleteResponse(
|
||||
price = BigDecimal(charge.payment!!.price).setScale(2, RoundingMode.HALF_UP).toDouble(),
|
||||
currencyCode = charge.payment!!.locale?.takeLast(3) ?: "KRW",
|
||||
isFirstCharged = chargeRepository.isFirstCharged(memberId)
|
||||
)
|
||||
} else {
|
||||
throw SodaException("구매를 하지 못했습니다.\n고객센터로 문의해 주세요")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue