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