Skip to content

Commit

Permalink
♻️refactor : 프론트 요청사항 반영 2차
Browse files Browse the repository at this point in the history
 - 판매점조회시 스크랩여부 필드추가
 - 당첨금액 순위별 당첨번호 및 당첨금정보 조회 API 작업
  • Loading branch information
ParkYunHo committed Sep 6, 2023
1 parent d8daff8 commit 205e3c6
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ class CommCode {

companion object {
val goodPlaceCnt: Int = 3

val taxLimitAmount: Long = 300000000 // 당첨금 세금부과 기준금액
val taxOverLimit: Float = 0.33F // 당첨금 3억 초과시 33% 세금 공제
val taxUnderLimit: Float = 0.22F // 당첨금 3억 이하시 22% 세금 공제
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,20 @@ class StaticsHandler(
)
.collectList()
.flatMap { BaseResponse().success(it) }

/**
* 당첨금액 순위별 당첨정보
*
* @param request [ServerRequest]
* @return [Mono]<[ServerResponse]>
* @author yoonho
* @since 2023.09.06
*/
fun findWinAmountDetail(request: ServerRequest): Mono<ServerResponse> =
staticsUseCase.findWinAmountDetail(
size = request.queryParam("size").orElseThrow { BadRequestException("필수 입력값 누락") }.trim(),
sortOption = request.queryParam("sortOption").orElseThrow { BadRequestException("필수 입력값 누락") }.trim()
)
.collectList()
.flatMap { BaseResponse().success(it) }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.john.lotto.statics.adapter.`in`.web

import com.john.lotto.statics.application.dto.StaticsAmountInfo
import com.john.lotto.statics.application.dto.StaticsInfo
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
Expand Down Expand Up @@ -204,13 +205,52 @@ class StaticsRouter(
security = [SecurityRequirement(name = "OpenID Connection Authentication")]
)
),
RouterOperation(
path = "/api/statics/rank/detail",
method = [RequestMethod.GET],
beanClass = StaticsHandler::class,
beanMethod = "findWinAmount",
operation = Operation(
tags = ["당첨번호 통계"],
summary = "당첨금액 순위별 당첨번호 정보",
operationId = "findWinAmountDetail",
parameters = [
Parameter(
name = "size",
description = "조회할 개수",
required = true,
examples = [
ExampleObject(name = "10", value = "10", description = "조회할 개수")
]
),
Parameter(
name = "sortOption",
description = "정렬옵션",
required = true,
examples = [
ExampleObject(name = "DESC", value = "DESC", description = "내림차순(desc)"),
ExampleObject(name = "ASC", value = "ASC", description = "오름차순(asc)"),
]
),
],
responses = [
ApiResponse(
description = "당첨번호 정보",
responseCode = "200",
content = [Content(schema = Schema(implementation = StaticsAmountInfo::class))]
)
],
security = [SecurityRequirement(name = "OpenID Connection Authentication")]
)
),
]
)
fun staticsRouterFunction(): RouterFunction<ServerResponse> = router {
accept(MediaType.APPLICATION_JSON).nest {
GET("/api/statics/period", staticsHandler::findPeriod)
GET("/api/statics/number", staticsHandler::findDrwtNo)
GET("/api/statics/rank", staticsHandler::findWinAmount)
GET("/api/statics/rank/detail", staticsHandler::findWinAmountDetail)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.john.lotto.statics.application

import com.john.lotto.amount.AmountRepository
import com.john.lotto.amount.dto.LottoWinAmountDto
import com.john.lotto.common.constants.CommCode
import com.john.lotto.common.exception.BadRequestException
import com.john.lotto.common.exception.InternalServerException
import com.john.lotto.statics.StaticsRepository
import com.john.lotto.statics.application.dto.StaticsAmountInfo
import com.john.lotto.statics.application.dto.StaticsInfo
import com.john.lotto.statics.application.port.`in`.StaticsUseCase
import org.slf4j.LoggerFactory
Expand All @@ -11,14 +15,16 @@ import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import kotlin.math.roundToLong

/**
* @author yoonho
* @since 2023.07.12
*/
@Service
class StaticsService(
private val staticsRepository: StaticsRepository
private val staticsRepository: StaticsRepository,
private val amountRepository: AmountRepository
): StaticsUseCase {
private val log = LoggerFactory.getLogger(this::class.java)

Expand Down Expand Up @@ -128,6 +134,58 @@ class StaticsService(
Flux.error(InternalServerException("당첨금액별 당첨번호 조회에 실패하였습니다."))
}

/**
* 당첨금액 순위별 당첨정보
*
* @param size [String]
* @param sortOption [String]
* @return [Flux]<[StaticsAmountInfo]>
* @author yoonho
* @since 2023.09.06
*/
@Cacheable(cacheNames = ["statics.common"], key = "#size + ':' + #sortOption", unless = "#result == null")
override fun findWinAmountDetail(size: String, sortOption: String): Flux<StaticsAmountInfo> =
try {
val checkDesc = when(sortOption) {
"DESC" -> true
"ASC" -> false
else -> false
}

val result = amountRepository.findLottoWinAmountSort(size = size.toLong(), isDesc = checkDesc)

val staticsDetailInfos: MutableList<StaticsAmountInfo> = mutableListOf()
for(item: LottoWinAmountDto in result) {
staticsDetailInfos.add(
StaticsAmountInfo(
drwtNo = item.drwtNo,
firstWinAmount = item.firstWinamnt,
firstWinAmountTax = this.calcTax(amount = item.firstWinamnt!!)
)
)
}

Flux.fromIterable(staticsDetailInfos)
}catch (e: Exception) {
log.error(" >>> [findWinAmountDetail] Exception occurs - message: ${e.message}")
Flux.error(InternalServerException("당첨금액 순위별 당첨정보 조회에 실패하였습니다."))
}

/**
* 당첨금액 세금계산
*
* @param amount [Long]
* @return [Long]
* @author yoonho
* @since 2023.09.06
*/
private fun calcTax(amount: Long): Long =
if(amount > CommCode.taxLimitAmount) {
amount * (1 - CommCode.taxOverLimit).roundToLong()
}else {
amount * (1 - CommCode.taxUnderLimit).roundToLong()
}

/**
* 통계 결과값 정렬
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.john.lotto.statics.application.dto

import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.annotation.JsonNaming
import io.swagger.v3.oas.annotations.media.Schema
import java.io.Serializable

/**
* @author yoonho
* @since 2023.09.06
*/
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
data class StaticsAmountInfo(
@Schema(description = "당첨회차", example = "0")
val drwtNo: Long? = -1L,
@Schema(description = "1등 1게임당 당첨금액", example = "0")
val firstWinAmount: Long? = -1L, // 1등 1게임당 당첨금액
@Schema(description = "1등 1게임당 당첨금액(세후)", example = "0")
val firstWinAmountTax: Long? = -1L, // 1등 1게임당 당첨금액(세후)
): Serializable
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.john.lotto.statics.application.port.`in`

import com.john.lotto.statics.application.dto.StaticsAmountInfo
import com.john.lotto.statics.application.dto.StaticsInfo
import com.john.lotto.statics.dto.StaticsDto
import reactor.core.publisher.Flux
Expand Down Expand Up @@ -49,4 +50,16 @@ interface StaticsUseCase {
* @since 2023.07.12
*/
fun findWinAmount(startRank: String, size: String, rankSortOption: String, sortType: String, sortOption: String): Flux<StaticsInfo>


/**
* 당첨금액 순위별 당첨정보
*
* @param size [String]
* @param sortOption [String]
* @return [Flux]<[StaticsAmountInfo]>
* @author yoonho
* @since 2023.09.06
*/
fun findWinAmountDetail(size: String, sortOption: String): Flux<StaticsAmountInfo>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.john.lotto.store.adapter.`in`.web
import com.john.lotto.common.constants.CommCode
import com.john.lotto.common.dto.BaseResponse
import com.john.lotto.common.exception.BadRequestException
import com.john.lotto.common.filter.userId
import com.john.lotto.store.application.port.`in`.FindLocationUseCase
import com.john.lotto.store.application.port.`in`.FindStoreUseCase
import org.springframework.stereotype.Component
Expand Down Expand Up @@ -31,6 +32,7 @@ class StoreHandler(
*/
fun findStore(request: ServerRequest): Mono<ServerResponse> =
findStoreUseCase.findStore(
userId = request.userId(),
location = request.queryParam("location").orElseThrow { BadRequestException("필수 입력값 누락") }.toString(),
subLocation = request.queryParam("subLocation").orElseThrow { BadRequestException("필수 입력값 누락") }.toString(),
sort = request.queryParam("sort").orElseGet { CommCode.Sort.NAME.code },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.john.lotto.store.application
import com.john.lotto.amount.AmountRepository
import com.john.lotto.common.constants.CommCode
import com.john.lotto.drwtstore.DrwtStoreRepository
import com.john.lotto.scrap.StoreScrapRepository
import com.john.lotto.store.StoreRepositoryImpl
import com.john.lotto.store.application.dto.LottoStoreTotalInfo
import com.john.lotto.store.application.port.`in`.FindLocationUseCase
Expand All @@ -22,13 +23,15 @@ import reactor.core.publisher.Flux
class StoreService(
private val storeRepositoryImpl: StoreRepositoryImpl,
private val drwtStoreRepository: DrwtStoreRepository,
private val amountRepository: AmountRepository
private val amountRepository: AmountRepository,
private val storeScrapRepository: StoreScrapRepository,
): FindStoreUseCase, FindLocationUseCase {
private val log = LoggerFactory.getLogger(this::class.java)

/**
* 로또 판매점 조회
*
* @param userId [String]
* @param location [String]
* @param subLocation [String]
* @param sort [String]
Expand All @@ -37,13 +40,15 @@ class StoreService(
* @author yoonho
* @since 2023.07.18
*/
@Cacheable(cacheNames = ["store.common"], key = "#location + ':' + #subLocation + ':' + #sort + ':' + #option", unless = "#result == null")
override fun findStore(location: String, subLocation: String, sort: String, option: String): Flux<LottoStoreTotalInfo> {
@Cacheable(cacheNames = ["store.common"], key = "#userId + ':' + #location + ':' + #subLocation + ':' + #sort + ':' + #option", unless = "#result == null")
override fun findStore(userId: String, location: String, subLocation: String, sort: String, option: String): Flux<LottoStoreTotalInfo> {
val lottoStoreTotalInfoList = mutableListOf<LottoStoreTotalInfo>()

val stores = storeRepositoryImpl.findLottoStore(location = location, subLocation = subLocation)
val drwtStores = drwtStoreRepository.findLottoDrwtStore(ids = stores.map { it.rtlrid!! })
val winAmounts = amountRepository.findLottoWinAmountList(drwtNos = drwtStores.map { it.drwtNo!! })
val scrapStores = storeScrapRepository.findStoreScrapList(userId = userId)
val scrapStoreIds = scrapStores.map { it.storeId }

for(store: LottoStoreDto in stores) {
val drwtNos = drwtStores.filter { it.rtlrid == store.rtlrid }.map { it.drwtNo!! }
Expand Down Expand Up @@ -75,6 +80,7 @@ class StoreService(
storeName = store.firmnm,

isGoodPlace = if(drwtInfos.size >= CommCode.goodPlaceCnt) true else false,
isScrap = if(scrapStoreIds.contains(store.rtlrid)) true else false,

drwtInfos = drwtInfos,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ data class LottoStoreTotalInfo(

@Schema(description = "명당여부", example = "true")
var isGoodPlace: Boolean = false,
@Schema(description = "스크랩된 판매점 여부", example = "true")
var isScrap: Boolean = false,

// 1등 당첨회차
@Schema(description = "당첨정보 리스트", example = "0", type = "array", implementation = LottoStoreTotalInfo.DrwtInfo::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface FindStoreUseCase {
/**
* 로또 판매점 조회
*
* @param userId [String]
* @param location [String]
* @param subLocation [String]
* @param sort [String]
Expand All @@ -20,5 +21,5 @@ interface FindStoreUseCase {
* @author yoonho
* @since 2023.07.18
*/
fun findStore(location: String, subLocation: String, sort: String, option: String): Flux<LottoStoreTotalInfo>
fun findStore(userId: String, location: String, subLocation: String, sort: String, option: String): Flux<LottoStoreTotalInfo>
}
32 changes: 32 additions & 0 deletions core/src/main/kotlin/com/john/lotto/amount/AmountRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,38 @@ class AmountRepository(
if(drwtNos.isEmpty()) null
else lottoWinAmount.drwtNo.`in`(drwtNos)

/**
* 당첨금액별 당첨금액정보
*
* @param size [Long]
* @param isDesc [Boolean]
* @return [List]<[LottoWinAmountDto]>
* @author yoonho
* @since 2023.09.06
*/
@Transactional(readOnly = true)
fun findLottoWinAmountSort(size: Long, isDesc: Boolean): List<LottoWinAmountDto> =
queryFactory
.select(
QLottoWinAmountDto(
lottoWinAmount.drwtNo,
lottoWinAmount.drwtDate,
lottoWinAmount.totSellamnt,
lottoWinAmount.firstWinamnt,
lottoWinAmount.firstPrzwnerCo,
lottoWinAmount.firstAccumamnt,
lottoWinAmount.updatedAt,
lottoWinAmount.createdAt
)
)
.from(lottoWinAmount)
.orderBy(
if(isDesc) lottoWinAmount.firstWinamnt.desc()
else lottoWinAmount.firstWinamnt.asc()
)
.limit(size)
.fetch()

/**
* 로또 당첨금 저장
*
Expand Down

0 comments on commit 205e3c6

Please sign in to comment.