generated from pricelees/issue-pr-template
[#44] 매장 기능 도입 #45
134
src/main/kotlin/roomescape/store/business/StoreService.kt
Normal file
134
src/main/kotlin/roomescape/store/business/StoreService.kt
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package roomescape.store.business
|
||||||
|
|
||||||
|
import com.github.f4b6a3.tsid.TsidFactory
|
||||||
|
import io.github.oshai.kotlinlogging.KLogger
|
||||||
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import roomescape.admin.business.AdminService
|
||||||
|
import roomescape.common.config.next
|
||||||
|
import roomescape.common.dto.AuditInfo
|
||||||
|
import roomescape.region.business.RegionService
|
||||||
|
import roomescape.store.exception.StoreErrorCode
|
||||||
|
import roomescape.store.exception.StoreException
|
||||||
|
import roomescape.store.infrastructure.persistence.StoreEntity
|
||||||
|
import roomescape.store.infrastructure.persistence.StoreRepository
|
||||||
|
import roomescape.store.infrastructure.persistence.StoreStatus
|
||||||
|
import roomescape.store.web.*
|
||||||
|
|
||||||
|
private val log: KLogger = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class StoreService(
|
||||||
|
private val storeRepository: StoreRepository,
|
||||||
|
private val adminService: AdminService,
|
||||||
|
private val regionService: RegionService,
|
||||||
|
private val tsidFactory: TsidFactory,
|
||||||
|
) {
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun getDetail(id: Long): DetailStoreResponse {
|
||||||
|
log.info { "[StoreService.getDetail] 매장 상세 조회 시작: id=${id}" }
|
||||||
|
|
||||||
|
val store: StoreEntity = findOrThrow(id)
|
||||||
|
val region = regionService.findRegionInfo(store.regionCode)
|
||||||
|
val audit = getAuditInfo(store)
|
||||||
|
|
||||||
|
return store.toDetailResponse(region, audit)
|
||||||
|
.also { log.info { "[StoreService.getDetail] 매장 상세 조회 완료: id=${id}" } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun register(request: StoreRegisterRequest): StoreRegisterResponse {
|
||||||
|
log.info { "[StoreService.register] 매장 등록 시작: name=${request.name}" }
|
||||||
|
|
||||||
|
val store = StoreEntity(
|
||||||
|
id = tsidFactory.next(),
|
||||||
|
name = request.name,
|
||||||
|
address = request.address,
|
||||||
|
contact = request.contact,
|
||||||
|
businessRegNum = request.businessRegNum,
|
||||||
|
regionCode = request.regionCode,
|
||||||
|
status = StoreStatus.ACTIVE,
|
||||||
|
).also {
|
||||||
|
storeRepository.save(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
return StoreRegisterResponse(store.id).also {
|
||||||
|
log.info { "[StoreService.register] 매장 등록 완료: id=${store.id}, name=${request.name}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun update(id: Long, request: StoreUpdateRequest) {
|
||||||
|
log.info { "[StoreService.update] 매장 수정 시작: id=${id}, request=${request}" }
|
||||||
|
|
||||||
|
findOrThrow(id).apply {
|
||||||
|
this.modifyIfNotNull(request.name, request.address, request.contact)
|
||||||
|
}.also {
|
||||||
|
log.info { "[StoreService.update] 매장 수정 완료: id=${id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun disableById(id: Long) {
|
||||||
|
log.info { "[StoreService.inactive] 매장 비활성화 시작: id=${id}" }
|
||||||
|
|
||||||
|
findOrThrow(id).apply {
|
||||||
|
this.disable()
|
||||||
|
}.also {
|
||||||
|
log.info { "[StoreService.inactive] 매장 비활성화 완료: id=${id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun getAllActiveStores(sidoCode: String?, sigunguCode: String?): SimpleStoreListResponse {
|
||||||
|
log.info { "[StoreService.getAllActiveStores] 전체 매장 조회 시작" }
|
||||||
|
|
||||||
|
val regionCode: String? = when {
|
||||||
|
sidoCode == null && sigunguCode != null -> throw StoreException(StoreErrorCode.SIDO_CODE_REQUIRED)
|
||||||
|
sidoCode != null -> "${sidoCode}${sigunguCode ?: ""}"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
return storeRepository.findAllActiveStoresByRegion(regionCode).toSimpleListResponse()
|
||||||
|
.also { log.info { "[StoreService.getAllActiveStores] 전체 매장 조회 완료: total=${it.stores.size}" } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun findStoreInfo(id: Long): StoreInfoResponse {
|
||||||
|
log.info { "[StoreService.findStoreInfo] 매장 정보 조회 시작: id=${id}" }
|
||||||
|
|
||||||
|
val store: StoreEntity = findOrThrow(id)
|
||||||
|
|
||||||
|
return store.toInfoResponse()
|
||||||
|
.also { log.info { "[StoreService.findStoreInfo] 매장 정보 조회 완료: id=${id}" } }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAuditInfo(store: StoreEntity): AuditInfo {
|
||||||
|
log.info { "[StoreService.getAuditInfo] 감사 정보 조회 시작: storeId=${store.id}" }
|
||||||
|
val createdBy = adminService.findOperatorOrUnknown(store.createdBy)
|
||||||
|
val updatedBy = adminService.findOperatorOrUnknown(store.updatedBy)
|
||||||
|
|
||||||
|
return AuditInfo(
|
||||||
|
createdAt = store.createdAt,
|
||||||
|
createdBy = createdBy,
|
||||||
|
updatedAt = store.updatedAt,
|
||||||
|
updatedBy = updatedBy
|
||||||
|
).also {
|
||||||
|
log.info { "[StoreService.getAuditInfo] 감사 정보 조회 완료: storeId=${store.id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findOrThrow(id: Long): StoreEntity {
|
||||||
|
log.info { "[StoreService.findOrThrow] 매장 조회 시작: id=${id}" }
|
||||||
|
|
||||||
|
return storeRepository.findActiveStoreById(id)
|
||||||
|
?.also {
|
||||||
|
log.info { "[StoreService.findOrThrow] 매장 조회 완료: id=${id}" }
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
log.warn { "[StoreService.findOrThrow] 매장 조회 실패: id=${id}" }
|
||||||
|
throw StoreException(StoreErrorCode.STORE_NOT_FOUND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/main/kotlin/roomescape/store/docs/StoreAPI.kt
Normal file
64
src/main/kotlin/roomescape/store/docs/StoreAPI.kt
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package roomescape.store.docs
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||||
|
import jakarta.validation.Valid
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
|
import roomescape.admin.infrastructure.persistence.AdminType
|
||||||
|
import roomescape.admin.infrastructure.persistence.Privilege
|
||||||
|
import roomescape.auth.web.support.AdminOnly
|
||||||
|
import roomescape.auth.web.support.Public
|
||||||
|
import roomescape.common.dto.response.CommonApiResponse
|
||||||
|
import roomescape.store.web.*
|
||||||
|
|
||||||
|
interface AdminStoreAPI {
|
||||||
|
@AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_DETAIL)
|
||||||
|
@Operation(summary = "특정 매장의 상세 정보 조회")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||||
|
fun findStoreDetail(
|
||||||
|
@PathVariable id: Long
|
||||||
|
): ResponseEntity<CommonApiResponse<DetailStoreResponse>>
|
||||||
|
|
||||||
|
@AdminOnly(type = AdminType.HQ, privilege = Privilege.CREATE)
|
||||||
|
@Operation(summary = "매장 등록")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||||
|
fun registerStore(
|
||||||
|
@Valid @RequestBody request: StoreRegisterRequest
|
||||||
|
): ResponseEntity<CommonApiResponse<StoreRegisterResponse>>
|
||||||
|
|
||||||
|
@AdminOnly(type = AdminType.STORE, privilege = Privilege.UPDATE)
|
||||||
|
@Operation(summary = "매장 정보 수정")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||||
|
fun updateStore(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@Valid @RequestBody request: StoreUpdateRequest
|
||||||
|
): ResponseEntity<CommonApiResponse<Unit>>
|
||||||
|
|
||||||
|
@AdminOnly(type = AdminType.HQ, privilege = Privilege.DELETE)
|
||||||
|
@Operation(summary = "매장 비활성화")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "204", useReturnTypeSchema = true))
|
||||||
|
fun disableStore(
|
||||||
|
@PathVariable id: Long
|
||||||
|
): ResponseEntity<CommonApiResponse<Unit>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PublicStoreAPI {
|
||||||
|
@Public
|
||||||
|
@Operation(summary = "모든 매장의 id / 이름 조회")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||||
|
fun getStores(
|
||||||
|
@RequestParam(value = "sido", required = false) sidoCode: String?,
|
||||||
|
@RequestParam(value = "sigungu", required = false) sigunguCode: String?
|
||||||
|
): ResponseEntity<CommonApiResponse<SimpleStoreListResponse>>
|
||||||
|
|
||||||
|
@Public
|
||||||
|
@Operation(summary = "특정 매장의 정보 조회")
|
||||||
|
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||||
|
fun getStoreInfo(
|
||||||
|
@PathVariable id: Long
|
||||||
|
): ResponseEntity<CommonApiResponse<StoreInfoResponse>>
|
||||||
|
}
|
||||||
19
src/main/kotlin/roomescape/store/exception/StoreException.kt
Normal file
19
src/main/kotlin/roomescape/store/exception/StoreException.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package roomescape.store.exception
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import roomescape.common.exception.ErrorCode
|
||||||
|
import roomescape.common.exception.RoomescapeException
|
||||||
|
|
||||||
|
class StoreException(
|
||||||
|
override val errorCode: StoreErrorCode,
|
||||||
|
override val message: String = errorCode.message
|
||||||
|
) : RoomescapeException(errorCode, message)
|
||||||
|
|
||||||
|
enum class StoreErrorCode(
|
||||||
|
override val httpStatus: HttpStatus,
|
||||||
|
override val errorCode: String,
|
||||||
|
override val message: String
|
||||||
|
) : ErrorCode {
|
||||||
|
STORE_NOT_FOUND(HttpStatus.NOT_FOUND, "ST001", "매장을 찾을 수 없어요."),
|
||||||
|
SIDO_CODE_REQUIRED(HttpStatus.BAD_REQUEST, "ST002", "시/도 정보를 찾을 수 없어요. 다시 시도해주세요.")
|
||||||
|
}
|
||||||
@ -1,11 +1,6 @@
|
|||||||
package roomescape.store.infrastructure.persistence
|
package roomescape.store.infrastructure.persistence
|
||||||
|
|
||||||
import jakarta.persistence.Column
|
import jakarta.persistence.*
|
||||||
import jakarta.persistence.Entity
|
|
||||||
import jakarta.persistence.EntityListeners
|
|
||||||
import jakarta.persistence.EnumType
|
|
||||||
import jakarta.persistence.Enumerated
|
|
||||||
import jakarta.persistence.Table
|
|
||||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener
|
||||||
import roomescape.common.entity.AuditingBaseEntity
|
import roomescape.common.entity.AuditingBaseEntity
|
||||||
|
|
||||||
@ -31,9 +26,23 @@ class StoreEntity(
|
|||||||
|
|
||||||
@Enumerated(value = EnumType.STRING)
|
@Enumerated(value = EnumType.STRING)
|
||||||
var status: StoreStatus
|
var status: StoreStatus
|
||||||
) : AuditingBaseEntity(id)
|
) : AuditingBaseEntity(id) {
|
||||||
|
fun modifyIfNotNull(
|
||||||
|
name: String?,
|
||||||
|
address: String?,
|
||||||
|
contact: String?,
|
||||||
|
) {
|
||||||
|
name?.let { this.name = it }
|
||||||
|
address?.let { this.address = it }
|
||||||
|
contact?.let { this.contact = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disable() {
|
||||||
|
this.status = StoreStatus.DISABLED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class StoreStatus {
|
enum class StoreStatus {
|
||||||
ACTIVE,
|
ACTIVE,
|
||||||
INACTIVE
|
DISABLED
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,33 @@
|
|||||||
package roomescape.store.infrastructure.persistence
|
package roomescape.store.infrastructure.persistence
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import org.springframework.data.jpa.repository.Query
|
||||||
|
|
||||||
interface StoreRepository : JpaRepository<StoreEntity, Long>
|
interface StoreRepository : JpaRepository<StoreEntity, Long> {
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
s
|
||||||
|
FROM
|
||||||
|
StoreEntity s
|
||||||
|
WHERE
|
||||||
|
s._id = :id
|
||||||
|
AND s.status = roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun findActiveStoreById(id: Long): StoreEntity?
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
s
|
||||||
|
FROM
|
||||||
|
StoreEntity s
|
||||||
|
WHERE
|
||||||
|
s.status = roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE
|
||||||
|
AND (:regionCode IS NULL OR s.regionCode LIKE ':regionCode%')
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun findAllActiveStoresByRegion(regionCode: String?): List<StoreEntity>
|
||||||
|
}
|
||||||
|
|||||||
52
src/main/kotlin/roomescape/store/web/AdminStoreController.kt
Normal file
52
src/main/kotlin/roomescape/store/web/AdminStoreController.kt
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package roomescape.store.web
|
||||||
|
|
||||||
|
import jakarta.validation.Valid
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.*
|
||||||
|
import roomescape.common.dto.response.CommonApiResponse
|
||||||
|
import roomescape.store.business.StoreService
|
||||||
|
import roomescape.store.docs.AdminStoreAPI
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin/stores")
|
||||||
|
class AdminStoreController(
|
||||||
|
private val storeService: StoreService
|
||||||
|
) : AdminStoreAPI {
|
||||||
|
|
||||||
|
@GetMapping("/{id}/detail")
|
||||||
|
override fun findStoreDetail(
|
||||||
|
@PathVariable id: Long
|
||||||
|
): ResponseEntity<CommonApiResponse<DetailStoreResponse>> {
|
||||||
|
val response: DetailStoreResponse = storeService.getDetail(id)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
override fun registerStore(
|
||||||
|
@Valid @RequestBody request: StoreRegisterRequest
|
||||||
|
): ResponseEntity<CommonApiResponse<StoreRegisterResponse>> {
|
||||||
|
val response: StoreRegisterResponse = storeService.register(request)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
|
}
|
||||||
|
|
||||||
|
@PatchMapping("/{id}")
|
||||||
|
override fun updateStore(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@Valid @RequestBody request: StoreUpdateRequest
|
||||||
|
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||||
|
storeService.update(id, request)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/disable")
|
||||||
|
override fun disableStore(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||||
|
storeService.disableById(id)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse())
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/main/kotlin/roomescape/store/web/AdminStoreDto.kt
Normal file
46
src/main/kotlin/roomescape/store/web/AdminStoreDto.kt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package roomescape.store.web
|
||||||
|
|
||||||
|
import roomescape.common.dto.AuditInfo
|
||||||
|
import roomescape.region.web.RegionInfoResponse
|
||||||
|
import roomescape.store.infrastructure.persistence.StoreEntity
|
||||||
|
|
||||||
|
data class StoreRegisterRequest(
|
||||||
|
val name: String,
|
||||||
|
val address: String,
|
||||||
|
val contact: String,
|
||||||
|
val businessRegNum: String,
|
||||||
|
val regionCode: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class StoreRegisterResponse(
|
||||||
|
val id: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
data class StoreUpdateRequest(
|
||||||
|
val name: String?,
|
||||||
|
val address: String?,
|
||||||
|
val contact: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class DetailStoreResponse(
|
||||||
|
val id: Long,
|
||||||
|
val name: String,
|
||||||
|
val address: String,
|
||||||
|
val contact: String,
|
||||||
|
val businessRegNum: String,
|
||||||
|
val region: RegionInfoResponse,
|
||||||
|
val audit: AuditInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
fun StoreEntity.toDetailResponse(
|
||||||
|
region: RegionInfoResponse,
|
||||||
|
audit: AuditInfo
|
||||||
|
) = DetailStoreResponse(
|
||||||
|
id = this.id,
|
||||||
|
name = this.name,
|
||||||
|
address = this.address,
|
||||||
|
contact = this.contact,
|
||||||
|
businessRegNum = this.businessRegNum,
|
||||||
|
region = region,
|
||||||
|
audit = audit,
|
||||||
|
)
|
||||||
35
src/main/kotlin/roomescape/store/web/StoreController.kt
Normal file
35
src/main/kotlin/roomescape/store/web/StoreController.kt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package roomescape.store.web
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
import roomescape.common.dto.response.CommonApiResponse
|
||||||
|
import roomescape.store.business.StoreService
|
||||||
|
import roomescape.store.docs.PublicStoreAPI
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
class StoreController(
|
||||||
|
private val storeService: StoreService
|
||||||
|
) : PublicStoreAPI {
|
||||||
|
|
||||||
|
@GetMapping("/stores")
|
||||||
|
override fun getStores(
|
||||||
|
@RequestParam(value = "sido", required = false) sidoCode: String?,
|
||||||
|
@RequestParam(value = "sigungu", required = false) sigunguCode: String?
|
||||||
|
): ResponseEntity<CommonApiResponse<SimpleStoreListResponse>> {
|
||||||
|
val response = storeService.getAllActiveStores(sidoCode, sigunguCode)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/stores/{id}")
|
||||||
|
override fun getStoreInfo(
|
||||||
|
@PathVariable id: Long
|
||||||
|
): ResponseEntity<CommonApiResponse<StoreInfoResponse>> {
|
||||||
|
val response = storeService.findStoreInfo(id)
|
||||||
|
|
||||||
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,5 @@
|
|||||||
package roomescape.store.web
|
package roomescape.store.web
|
||||||
|
|
||||||
import roomescape.common.dto.AuditInfo
|
|
||||||
import roomescape.region.web.RegionInfoResponse
|
|
||||||
import roomescape.store.infrastructure.persistence.StoreEntity
|
import roomescape.store.infrastructure.persistence.StoreEntity
|
||||||
|
|
||||||
data class SimpleStoreResponse(
|
data class SimpleStoreResponse(
|
||||||
@ -40,13 +38,3 @@ data class StoreInfoListResponse(
|
|||||||
fun List<StoreEntity>.toInfoListResponse() = StoreInfoListResponse(
|
fun List<StoreEntity>.toInfoListResponse() = StoreInfoListResponse(
|
||||||
stores = this.map { it.toInfoResponse() }
|
stores = this.map { it.toInfoResponse() }
|
||||||
)
|
)
|
||||||
|
|
||||||
data class StoreDetailResponse(
|
|
||||||
val id: Long,
|
|
||||||
val name: String,
|
|
||||||
val address: String,
|
|
||||||
val contact: String,
|
|
||||||
val businessRegNum: String,
|
|
||||||
val region: RegionInfoResponse,
|
|
||||||
val audit: AuditInfo
|
|
||||||
)
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user