generated from pricelees/issue-pr-template
style: Reformat Code & Optimize Imports
This commit is contained in:
parent
57c890cc64
commit
957996baf6
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class AuthErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String,
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String,
|
||||
) : ErrorCode {
|
||||
TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "A001", "인증 토큰이 없어요."),
|
||||
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "A002", "유효하지 않은 토큰이에요."),
|
||||
|
||||
@ -3,6 +3,6 @@ package roomescape.auth.exception
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class AuthException(
|
||||
override val errorCode: AuthErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: AuthErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -12,11 +12,11 @@ import javax.crypto.SecretKey
|
||||
|
||||
@Component
|
||||
class JwtHandler(
|
||||
@Value("\${security.jwt.token.secret-key}")
|
||||
private val secretKeyString: String,
|
||||
@Value("\${security.jwt.token.secret-key}")
|
||||
private val secretKeyString: String,
|
||||
|
||||
@Value("\${security.jwt.token.ttl-seconds}")
|
||||
private val tokenTtlSeconds: Long
|
||||
@Value("\${security.jwt.token.ttl-seconds}")
|
||||
private val tokenTtlSeconds: Long
|
||||
) {
|
||||
private val secretKey: SecretKey = Keys.hmacShaKeyFor(secretKeyString.toByteArray())
|
||||
|
||||
@ -25,22 +25,22 @@ class JwtHandler(
|
||||
val accessTokenExpiredAt = Date(date.time + tokenTtlSeconds)
|
||||
|
||||
return Jwts.builder()
|
||||
.claim(MEMBER_ID_CLAIM_KEY, memberId)
|
||||
.issuedAt(date)
|
||||
.expiration(accessTokenExpiredAt)
|
||||
.signWith(secretKey)
|
||||
.compact()
|
||||
.claim(MEMBER_ID_CLAIM_KEY, memberId)
|
||||
.issuedAt(date)
|
||||
.expiration(accessTokenExpiredAt)
|
||||
.signWith(secretKey)
|
||||
.compact()
|
||||
}
|
||||
|
||||
fun getMemberIdFromToken(token: String?): Long {
|
||||
try {
|
||||
return Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.payload
|
||||
.get(MEMBER_ID_CLAIM_KEY, Number::class.java)
|
||||
.toLong()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.payload
|
||||
.get(MEMBER_ID_CLAIM_KEY, Number::class.java)
|
||||
.toLong()
|
||||
} catch (_: IllegalArgumentException) {
|
||||
throw AuthException(AuthErrorCode.TOKEN_NOT_FOUND)
|
||||
} catch (_: ExpiredJwtException) {
|
||||
|
||||
@ -18,24 +18,24 @@ class JacksonConfig {
|
||||
|
||||
@Bean
|
||||
fun objectMapper(): ObjectMapper = ObjectMapper()
|
||||
.registerModule(javaTimeModule())
|
||||
.registerModule(kotlinModule())
|
||||
.registerModule(javaTimeModule())
|
||||
.registerModule(kotlinModule())
|
||||
|
||||
private fun javaTimeModule(): JavaTimeModule = JavaTimeModule()
|
||||
.addSerializer(
|
||||
LocalDate::class.java,
|
||||
LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||
)
|
||||
.addDeserializer(
|
||||
LocalDate::class.java,
|
||||
LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||
)
|
||||
.addSerializer(
|
||||
LocalTime::class.java,
|
||||
LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||
)
|
||||
.addDeserializer(
|
||||
LocalTime::class.java,
|
||||
LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||
) as JavaTimeModule
|
||||
.addSerializer(
|
||||
LocalDate::class.java,
|
||||
LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||
)
|
||||
.addDeserializer(
|
||||
LocalDate::class.java,
|
||||
LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||
)
|
||||
.addSerializer(
|
||||
LocalTime::class.java,
|
||||
LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||
)
|
||||
.addDeserializer(
|
||||
LocalTime::class.java,
|
||||
LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||
) as JavaTimeModule
|
||||
}
|
||||
|
||||
@ -15,8 +15,9 @@ class SwaggerConfig {
|
||||
|
||||
private fun apiInfo(): Info {
|
||||
return Info()
|
||||
.title("방탈출 예약 API 문서")
|
||||
.description("""
|
||||
.title("방탈출 예약 API 문서")
|
||||
.description(
|
||||
"""
|
||||
## API 테스트는 '1. 인증 / 인가 API' 의 '/login' 을 통해 로그인 후 사용해주세요.
|
||||
|
||||
### 테스트시 로그인 가능한 계정 정보
|
||||
@ -70,7 +71,8 @@ class SwaggerConfig {
|
||||
|
||||
- 8 ~ 10: 예약 대기 상태
|
||||
|
||||
""".trimIndent())
|
||||
.version("1.0.0")
|
||||
""".trimIndent()
|
||||
)
|
||||
.version("1.0.0")
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ import roomescape.auth.web.support.MemberIdResolver
|
||||
|
||||
@Configuration
|
||||
class WebMvcConfig(
|
||||
private val memberIdResolver: MemberIdResolver,
|
||||
private val authInterceptor: AuthInterceptor
|
||||
private val memberIdResolver: MemberIdResolver,
|
||||
private val authInterceptor: AuthInterceptor
|
||||
) : WebMvcConfigurer {
|
||||
|
||||
override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
|
||||
|
||||
@ -5,15 +5,15 @@ import roomescape.common.exception.ErrorCode
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
data class CommonApiResponse<T>(
|
||||
val data: T? = null,
|
||||
val data: T? = null,
|
||||
)
|
||||
|
||||
data class CommonErrorResponse(
|
||||
val code: String,
|
||||
val message: String
|
||||
val code: String,
|
||||
val message: String
|
||||
) {
|
||||
constructor(errorCode: ErrorCode, message: String = errorCode.message) : this(
|
||||
code = errorCode.errorCode,
|
||||
message = message
|
||||
code = errorCode.errorCode,
|
||||
message = message
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,18 +3,18 @@ package roomescape.common.exception
|
||||
import org.springframework.http.HttpStatus
|
||||
|
||||
enum class CommonErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String,
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String,
|
||||
) : ErrorCode {
|
||||
INVALID_INPUT_VALUE(
|
||||
httpStatus = HttpStatus.BAD_REQUEST,
|
||||
errorCode = "C001",
|
||||
message = "요청 값이 잘못되었어요."
|
||||
httpStatus = HttpStatus.BAD_REQUEST,
|
||||
errorCode = "C001",
|
||||
message = "요청 값이 잘못되었어요."
|
||||
),
|
||||
UNEXPECTED_SERVER_ERROR(
|
||||
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
errorCode = "C999",
|
||||
message = "서버에 예상치 못한 오류가 발생했어요. 관리자에게 문의해주세요.",
|
||||
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
errorCode = "C999",
|
||||
message = "서버에 예상치 못한 오류가 발생했어요. 관리자에게 문의해주세요.",
|
||||
),
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package roomescape.common.exception
|
||||
|
||||
open class RoomescapeException(
|
||||
open val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
open val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RuntimeException(message)
|
||||
|
||||
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class MemberErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
) : ErrorCode {
|
||||
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "M001", "회원을 찾을 수 없어요."),
|
||||
DUPLICATE_EMAIL(HttpStatus.CONFLICT, "M002", "이미 가입된 이메일이에요.")
|
||||
|
||||
@ -3,6 +3,6 @@ package roomescape.member.exception
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class MemberException(
|
||||
override val errorCode: MemberErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: MemberErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -5,15 +5,15 @@ import jakarta.persistence.*
|
||||
@Entity
|
||||
@Table(name = "members")
|
||||
class MemberEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
var name: String,
|
||||
var email: String,
|
||||
var password: String,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
var name: String,
|
||||
var email: String,
|
||||
var password: String,
|
||||
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var role: Role
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var role: Role
|
||||
) {
|
||||
fun isAdmin(): Boolean = role == Role.ADMIN
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class PaymentErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
) : ErrorCode {
|
||||
PAYMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "P001", "결제 정보를 찾을 수 없어요."),
|
||||
CANCELED_PAYMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "P002", "취소된 결제 정보를 찾을 수 없어요."),
|
||||
|
||||
@ -3,6 +3,6 @@ package roomescape.payment.exception
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class PaymentException(
|
||||
override val errorCode: PaymentErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: PaymentErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -9,21 +9,21 @@ import roomescape.payment.web.PaymentCancelResponse
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
class PaymentCancelResponseDeserializer(
|
||||
vc: Class<PaymentCancelResponse>? = null
|
||||
vc: Class<PaymentCancelResponse>? = null
|
||||
) : StdDeserializer<PaymentCancelResponse>(vc) {
|
||||
override fun deserialize(
|
||||
jsonParser: JsonParser,
|
||||
deserializationContext: DeserializationContext?
|
||||
jsonParser: JsonParser,
|
||||
deserializationContext: DeserializationContext?
|
||||
): PaymentCancelResponse {
|
||||
val cancels: JsonNode = jsonParser.codec.readTree<TreeNode>(jsonParser)
|
||||
.get("cancels")
|
||||
.get(0) as JsonNode
|
||||
.get("cancels")
|
||||
.get(0) as JsonNode
|
||||
|
||||
return PaymentCancelResponse(
|
||||
cancels.get("cancelStatus").asText(),
|
||||
cancels.get("cancelReason").asText(),
|
||||
cancels.get("cancelAmount").asLong(),
|
||||
OffsetDateTime.parse(cancels.get("canceledAt").asText())
|
||||
cancels.get("cancelStatus").asText(),
|
||||
cancels.get("cancelReason").asText(),
|
||||
cancels.get("cancelAmount").asLong(),
|
||||
OffsetDateTime.parse(cancels.get("canceledAt").asText())
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@ class PaymentConfig {
|
||||
|
||||
@Bean
|
||||
fun tossPaymentClientBuilder(
|
||||
paymentProperties: PaymentProperties,
|
||||
paymentProperties: PaymentProperties,
|
||||
): RestClient.Builder {
|
||||
val settings: ClientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults().also {
|
||||
it.withReadTimeout(Duration.ofSeconds(paymentProperties.readTimeout.toLong()))
|
||||
@ -25,14 +25,14 @@ class PaymentConfig {
|
||||
val requestFactory = ClientHttpRequestFactoryBuilder.jdk().build(settings)
|
||||
|
||||
return RestClient.builder()
|
||||
.baseUrl(paymentProperties.apiBaseUrl)
|
||||
.defaultHeader("Authorization", getAuthorizations(paymentProperties.confirmSecretKey))
|
||||
.requestFactory(requestFactory)
|
||||
.baseUrl(paymentProperties.apiBaseUrl)
|
||||
.defaultHeader("Authorization", getAuthorizations(paymentProperties.confirmSecretKey))
|
||||
.requestFactory(requestFactory)
|
||||
}
|
||||
|
||||
private fun getAuthorizations(secretKey: String): String {
|
||||
val encodedSecretKey = Base64.getEncoder()
|
||||
.encodeToString("$secretKey:".toByteArray(StandardCharsets.UTF_8))
|
||||
.encodeToString("$secretKey:".toByteArray(StandardCharsets.UTF_8))
|
||||
|
||||
return "Basic $encodedSecretKey"
|
||||
}
|
||||
|
||||
@ -4,8 +4,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ConfigurationProperties(prefix = "payment")
|
||||
data class PaymentProperties(
|
||||
val apiBaseUrl: String,
|
||||
val confirmSecretKey: String,
|
||||
val readTimeout: Int,
|
||||
val connectTimeout: Int
|
||||
val apiBaseUrl: String,
|
||||
val confirmSecretKey: String,
|
||||
val readTimeout: Int,
|
||||
val connectTimeout: Int
|
||||
)
|
||||
|
||||
@ -4,21 +4,21 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
data class TossPaymentErrorResponse(
|
||||
val code: String,
|
||||
val message: String
|
||||
val code: String,
|
||||
val message: String
|
||||
)
|
||||
|
||||
data class PaymentApproveRequest(
|
||||
val paymentKey: String,
|
||||
val orderId: String,
|
||||
val amount: Long,
|
||||
val paymentType: String
|
||||
val paymentKey: String,
|
||||
val orderId: String,
|
||||
val amount: Long,
|
||||
val paymentType: String
|
||||
)
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class PaymentApproveResponse(
|
||||
val paymentKey: String,
|
||||
val orderId: String,
|
||||
val totalAmount: Long,
|
||||
val approvedAt: OffsetDateTime
|
||||
val paymentKey: String,
|
||||
val orderId: String,
|
||||
val totalAmount: Long,
|
||||
val approvedAt: OffsetDateTime
|
||||
)
|
||||
|
||||
@ -6,13 +6,13 @@ import java.time.OffsetDateTime
|
||||
@Entity
|
||||
@Table(name = "canceled_payments")
|
||||
class CanceledPaymentEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
|
||||
var paymentKey: String,
|
||||
var cancelReason: String,
|
||||
var cancelAmount: Long,
|
||||
var approvedAt: OffsetDateTime,
|
||||
var canceledAt: OffsetDateTime,
|
||||
var paymentKey: String,
|
||||
var cancelReason: String,
|
||||
var cancelAmount: Long,
|
||||
var approvedAt: OffsetDateTime,
|
||||
var canceledAt: OffsetDateTime,
|
||||
)
|
||||
|
||||
@ -7,23 +7,23 @@ import java.time.OffsetDateTime
|
||||
@Entity
|
||||
@Table(name = "payments")
|
||||
class PaymentEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
|
||||
@Column(nullable = false)
|
||||
var orderId: String,
|
||||
@Column(nullable = false)
|
||||
var orderId: String,
|
||||
|
||||
@Column(nullable = false)
|
||||
var paymentKey: String,
|
||||
@Column(nullable = false)
|
||||
var paymentKey: String,
|
||||
|
||||
@Column(nullable = false)
|
||||
var totalAmount: Long,
|
||||
@Column(nullable = false)
|
||||
var totalAmount: Long,
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "reservation_id", nullable = false)
|
||||
var reservation: ReservationEntity,
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "reservation_id", nullable = false)
|
||||
var reservation: ReservationEntity,
|
||||
|
||||
@Column(nullable = false)
|
||||
var approvedAt: OffsetDateTime
|
||||
@Column(nullable = false)
|
||||
var approvedAt: OffsetDateTime
|
||||
)
|
||||
@ -8,33 +8,33 @@ import roomescape.reservation.web.toRetrieveResponse
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
data class PaymentCancelRequest(
|
||||
val paymentKey: String,
|
||||
val amount: Long,
|
||||
val cancelReason: String
|
||||
val paymentKey: String,
|
||||
val amount: Long,
|
||||
val cancelReason: String
|
||||
)
|
||||
|
||||
@JsonDeserialize(using = PaymentCancelResponseDeserializer::class)
|
||||
data class PaymentCancelResponse(
|
||||
val cancelStatus: String,
|
||||
val cancelReason: String,
|
||||
val cancelAmount: Long,
|
||||
val canceledAt: OffsetDateTime
|
||||
val cancelStatus: String,
|
||||
val cancelReason: String,
|
||||
val cancelAmount: Long,
|
||||
val canceledAt: OffsetDateTime
|
||||
)
|
||||
|
||||
data class PaymentCreateResponse(
|
||||
val id: Long,
|
||||
val orderId: String,
|
||||
val paymentKey: String,
|
||||
val totalAmount: Long,
|
||||
val reservation: ReservationRetrieveResponse,
|
||||
val approvedAt: OffsetDateTime
|
||||
val id: Long,
|
||||
val orderId: String,
|
||||
val paymentKey: String,
|
||||
val totalAmount: Long,
|
||||
val reservation: ReservationRetrieveResponse,
|
||||
val approvedAt: OffsetDateTime
|
||||
)
|
||||
|
||||
fun PaymentEntity.toCreateResponse(): PaymentCreateResponse = PaymentCreateResponse(
|
||||
id = this.id!!,
|
||||
orderId = this.orderId,
|
||||
paymentKey = this.paymentKey,
|
||||
totalAmount = this.totalAmount,
|
||||
reservation = this.reservation.toRetrieveResponse(),
|
||||
approvedAt = this.approvedAt
|
||||
id = this.id!!,
|
||||
orderId = this.orderId,
|
||||
paymentKey = this.paymentKey,
|
||||
totalAmount = this.totalAmount,
|
||||
reservation = this.reservation.toRetrieveResponse(),
|
||||
approvedAt = this.approvedAt
|
||||
)
|
||||
@ -32,58 +32,66 @@ interface ReservationAPI {
|
||||
@Operation(summary = "자신의 예약 및 대기 조회", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
||||
fun findReservationsByMemberId(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<MyReservationRetrieveListResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "관리자의 예약 검색", description = "특정 조건에 해당되는 예약 검색", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)
|
||||
ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)
|
||||
)
|
||||
fun searchReservations(
|
||||
@RequestParam(required = false) themeId: Long?,
|
||||
@RequestParam(required = false) memberId: Long?,
|
||||
@RequestParam(required = false) dateFrom: LocalDate?,
|
||||
@RequestParam(required = false) dateTo: LocalDate?
|
||||
@RequestParam(required = false) themeId: Long?,
|
||||
@RequestParam(required = false) memberId: Long?,
|
||||
@RequestParam(required = false) dateFrom: LocalDate?,
|
||||
@RequestParam(required = false) dateTo: LocalDate?
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveListResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "관리자의 예약 취소", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "204", description = "성공"),
|
||||
ApiResponse(responseCode = "204", description = "성공"),
|
||||
)
|
||||
fun cancelReservationByAdmin(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
|
||||
@LoginRequired
|
||||
@Operation(summary = "예약 추가", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))]
|
||||
)
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(
|
||||
name = HttpHeaders.LOCATION,
|
||||
description = "생성된 예약 정보 URL",
|
||||
schema = Schema(example = "/reservations/1")
|
||||
)]
|
||||
)
|
||||
)
|
||||
fun createReservationWithPayment(
|
||||
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "관리자 예약 추가", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))],
|
||||
)
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(
|
||||
name = HttpHeaders.LOCATION,
|
||||
description = "생성된 예약 정보 URL",
|
||||
schema = Schema(example = "/reservations/1")
|
||||
)],
|
||||
)
|
||||
)
|
||||
fun createReservationByAdmin(
|
||||
@Valid @RequestBody adminReservationRequest: AdminReservationCreateRequest,
|
||||
@Valid @RequestBody adminReservationRequest: AdminReservationCreateRequest,
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>>
|
||||
|
||||
@Admin
|
||||
@ -94,45 +102,49 @@ interface ReservationAPI {
|
||||
@LoginRequired
|
||||
@Operation(summary = "예약 대기 신청", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(name = HttpHeaders.LOCATION, description = "생성된 예약 정보 URL", schema = Schema(example = "/reservations/1"))]
|
||||
)
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "성공",
|
||||
useReturnTypeSchema = true,
|
||||
headers = [Header(
|
||||
name = HttpHeaders.LOCATION,
|
||||
description = "생성된 예약 정보 URL",
|
||||
schema = Schema(example = "/reservations/1")
|
||||
)]
|
||||
)
|
||||
)
|
||||
fun createWaiting(
|
||||
@Valid @RequestBody waitingCreateRequest: WaitingCreateRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@Valid @RequestBody waitingCreateRequest: WaitingCreateRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>>
|
||||
|
||||
@LoginRequired
|
||||
@Operation(summary = "예약 대기 취소", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "204", description = "성공"),
|
||||
ApiResponse(responseCode = "204", description = "성공"),
|
||||
)
|
||||
fun cancelWaitingByMember(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "대기 중인 예약 승인", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "200", description = "성공"),
|
||||
ApiResponse(responseCode = "200", description = "성공"),
|
||||
)
|
||||
fun confirmWaiting(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "대기 중인 예약 거절", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "204", description = "대기 중인 예약 거절 성공"),
|
||||
ApiResponse(responseCode = "204", description = "대기 중인 예약 거절 성공"),
|
||||
)
|
||||
fun rejectWaiting(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") @Parameter(description = "예약 ID") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class ReservationErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
) : ErrorCode {
|
||||
RESERVATION_NOT_FOUND(HttpStatus.NOT_FOUND, "R001", "예약을 찾을 수 없어요."),
|
||||
RESERVATION_DUPLICATED(HttpStatus.BAD_REQUEST, "R002", "이미 같은 예약이 있어요."),
|
||||
|
||||
@ -4,6 +4,6 @@ import roomescape.common.exception.ErrorCode
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class ReservationException(
|
||||
override val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -10,26 +10,26 @@ import java.time.LocalDate
|
||||
@Entity
|
||||
@Table(name = "reservations")
|
||||
class ReservationEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
|
||||
var date: LocalDate,
|
||||
var date: LocalDate,
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "time_id", nullable = false)
|
||||
var time: TimeEntity,
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "time_id", nullable = false)
|
||||
var time: TimeEntity,
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "theme_id", nullable = false)
|
||||
var theme: ThemeEntity,
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "theme_id", nullable = false)
|
||||
var theme: ThemeEntity,
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "member_id", nullable = false)
|
||||
var member: MemberEntity,
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "member_id", nullable = false)
|
||||
var member: MemberEntity,
|
||||
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var reservationStatus: ReservationStatus
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var reservationStatus: ReservationStatus
|
||||
) {
|
||||
@JsonIgnore
|
||||
fun isWaiting(): Boolean = reservationStatus == ReservationStatus.WAITING
|
||||
|
||||
@ -16,17 +16,20 @@ interface ReservationRepository
|
||||
fun findByDateAndThemeId(date: LocalDate, themeId: Long): List<ReservationEntity>
|
||||
|
||||
@Modifying
|
||||
@Query("""
|
||||
@Query(
|
||||
"""
|
||||
UPDATE ReservationEntity r
|
||||
SET r.reservationStatus = :status
|
||||
WHERE r.id = :id
|
||||
""")
|
||||
"""
|
||||
)
|
||||
fun updateStatusByReservationId(
|
||||
@Param(value = "id") reservationId: Long,
|
||||
@Param(value = "status") statusForChange: ReservationStatus
|
||||
@Param(value = "id") reservationId: Long,
|
||||
@Param(value = "status") statusForChange: ReservationStatus
|
||||
): Int
|
||||
|
||||
@Query("""
|
||||
@Query(
|
||||
"""
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM ReservationEntity r2
|
||||
@ -39,10 +42,12 @@ interface ReservationRepository
|
||||
AND r.reservationStatus != 'WAITING'
|
||||
)
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
fun isExistConfirmedReservation(@Param("id") reservationId: Long): Boolean
|
||||
|
||||
@Query("""
|
||||
@Query(
|
||||
"""
|
||||
SELECT new roomescape.reservation.web.MyReservationRetrieveResponse(
|
||||
r.id,
|
||||
t.name,
|
||||
@ -58,6 +63,7 @@ interface ReservationRepository
|
||||
LEFT JOIN PaymentEntity p
|
||||
ON p.reservation = r
|
||||
WHERE r.member.id = :memberId
|
||||
""")
|
||||
"""
|
||||
)
|
||||
fun findAllByMemberId(memberId: Long): List<MyReservationRetrieveResponse>
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import roomescape.time.infrastructure.persistence.TimeEntity
|
||||
import java.time.LocalDate
|
||||
|
||||
class ReservationSearchSpecification(
|
||||
private var spec: Specification<ReservationEntity> = Specification { _, _, _ -> null }
|
||||
private var spec: Specification<ReservationEntity> = Specification { _, _, _ -> null }
|
||||
) {
|
||||
fun sameThemeId(themeId: Long?): ReservationSearchSpecification = andIfNotNull(themeId?.let {
|
||||
Specification { root, _, cb ->
|
||||
@ -35,21 +35,21 @@ class ReservationSearchSpecification(
|
||||
|
||||
fun confirmed(): ReservationSearchSpecification = andIfNotNull { root, _, cb ->
|
||||
cb.or(
|
||||
cb.equal(
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.CONFIRMED
|
||||
),
|
||||
cb.equal(
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
)
|
||||
cb.equal(
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.CONFIRMED
|
||||
),
|
||||
cb.equal(
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun waiting(): ReservationSearchSpecification = andIfNotNull { root, _, cb ->
|
||||
cb.equal(
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.WAITING
|
||||
root.get<ReservationStatus>("reservationStatus"),
|
||||
ReservationStatus.WAITING
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -18,9 +18,9 @@ import java.time.LocalDate
|
||||
|
||||
@RestController
|
||||
class ReservationController(
|
||||
private val reservationWithPaymentService: ReservationWithPaymentService,
|
||||
private val reservationService: ReservationService,
|
||||
private val paymentClient: TossPaymentClient
|
||||
private val reservationWithPaymentService: ReservationWithPaymentService,
|
||||
private val reservationService: ReservationService,
|
||||
private val paymentClient: TossPaymentClient
|
||||
) : ReservationAPI {
|
||||
@GetMapping("/reservations")
|
||||
override fun findReservations(): ResponseEntity<CommonApiResponse<ReservationRetrieveListResponse>> {
|
||||
@ -31,7 +31,7 @@ class ReservationController(
|
||||
|
||||
@GetMapping("/reservations-mine")
|
||||
override fun findReservationsByMemberId(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<MyReservationRetrieveListResponse>> {
|
||||
val response: MyReservationRetrieveListResponse = reservationService.findReservationsByMemberId(memberId)
|
||||
|
||||
@ -40,16 +40,16 @@ class ReservationController(
|
||||
|
||||
@GetMapping("/reservations/search")
|
||||
override fun searchReservations(
|
||||
@RequestParam(required = false) themeId: Long?,
|
||||
@RequestParam(required = false) memberId: Long?,
|
||||
@RequestParam(required = false) dateFrom: LocalDate?,
|
||||
@RequestParam(required = false) dateTo: LocalDate?
|
||||
@RequestParam(required = false) themeId: Long?,
|
||||
@RequestParam(required = false) memberId: Long?,
|
||||
@RequestParam(required = false) dateFrom: LocalDate?,
|
||||
@RequestParam(required = false) dateTo: LocalDate?
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveListResponse>> {
|
||||
val response: ReservationRetrieveListResponse = reservationService.searchReservations(
|
||||
themeId,
|
||||
memberId,
|
||||
dateFrom,
|
||||
dateTo
|
||||
themeId,
|
||||
memberId,
|
||||
dateFrom,
|
||||
dateTo
|
||||
)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
@ -57,8 +57,8 @@ class ReservationController(
|
||||
|
||||
@DeleteMapping("/reservations/{id}")
|
||||
override fun cancelReservationByAdmin(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
if (reservationWithPaymentService.isNotPaidReservation(reservationId)) {
|
||||
reservationService.deleteReservation(reservationId, memberId)
|
||||
@ -67,47 +67,56 @@ class ReservationController(
|
||||
|
||||
val paymentCancelRequest = reservationWithPaymentService.deleteReservationAndPayment(reservationId, memberId)
|
||||
val paymentCancelResponse = paymentClient.cancel(paymentCancelRequest)
|
||||
reservationWithPaymentService.updateCanceledTime(paymentCancelRequest.paymentKey,
|
||||
paymentCancelResponse.canceledAt)
|
||||
reservationWithPaymentService.updateCanceledTime(
|
||||
paymentCancelRequest.paymentKey,
|
||||
paymentCancelResponse.canceledAt
|
||||
)
|
||||
|
||||
return ResponseEntity.noContent().build()
|
||||
}
|
||||
|
||||
@PostMapping("/reservations")
|
||||
override fun createReservationWithPayment(
|
||||
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>> {
|
||||
val paymentRequest: PaymentApproveRequest = reservationCreateWithPaymentRequest.toPaymentApproveRequest()
|
||||
val paymentResponse: PaymentApproveResponse = paymentClient.confirm(paymentRequest)
|
||||
|
||||
try {
|
||||
val reservationRetrieveResponse: ReservationRetrieveResponse = reservationWithPaymentService.createReservationAndPayment(
|
||||
val reservationRetrieveResponse: ReservationRetrieveResponse =
|
||||
reservationWithPaymentService.createReservationAndPayment(
|
||||
reservationCreateWithPaymentRequest,
|
||||
paymentResponse,
|
||||
memberId
|
||||
)
|
||||
)
|
||||
return ResponseEntity.created(URI.create("/reservations/${reservationRetrieveResponse.id}"))
|
||||
.body(CommonApiResponse(reservationRetrieveResponse))
|
||||
.body(CommonApiResponse(reservationRetrieveResponse))
|
||||
} catch (e: Exception) {
|
||||
val cancelRequest = PaymentCancelRequest(paymentRequest.paymentKey,
|
||||
paymentRequest.amount, e.message!!)
|
||||
val cancelRequest = PaymentCancelRequest(
|
||||
paymentRequest.paymentKey,
|
||||
paymentRequest.amount,
|
||||
e.message!!
|
||||
)
|
||||
val paymentCancelResponse = paymentClient.cancel(cancelRequest)
|
||||
reservationWithPaymentService.createCanceledPayment(paymentCancelResponse, paymentResponse.approvedAt,
|
||||
paymentRequest.paymentKey)
|
||||
reservationWithPaymentService.createCanceledPayment(
|
||||
paymentCancelResponse,
|
||||
paymentResponse.approvedAt,
|
||||
paymentRequest.paymentKey
|
||||
)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/reservations/admin")
|
||||
override fun createReservationByAdmin(
|
||||
@Valid @RequestBody adminReservationRequest: AdminReservationCreateRequest
|
||||
@Valid @RequestBody adminReservationRequest: AdminReservationCreateRequest
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>> {
|
||||
val response: ReservationRetrieveResponse =
|
||||
reservationService.createReservationByAdmin(adminReservationRequest)
|
||||
reservationService.createReservationByAdmin(adminReservationRequest)
|
||||
|
||||
return ResponseEntity.created(URI.create("/reservations/${response.id}"))
|
||||
.body(CommonApiResponse(response))
|
||||
.body(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@GetMapping("/reservations/waiting")
|
||||
@ -119,22 +128,22 @@ class ReservationController(
|
||||
|
||||
@PostMapping("/reservations/waiting")
|
||||
override fun createWaiting(
|
||||
@Valid @RequestBody waitingCreateRequest: WaitingCreateRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@Valid @RequestBody waitingCreateRequest: WaitingCreateRequest,
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
): ResponseEntity<CommonApiResponse<ReservationRetrieveResponse>> {
|
||||
val response: ReservationRetrieveResponse = reservationService.createWaiting(
|
||||
waitingCreateRequest,
|
||||
memberId
|
||||
waitingCreateRequest,
|
||||
memberId
|
||||
)
|
||||
|
||||
return ResponseEntity.created(URI.create("/reservations/${response.id}"))
|
||||
.body(CommonApiResponse(response))
|
||||
.body(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@DeleteMapping("/reservations/waiting/{id}")
|
||||
override fun cancelWaitingByMember(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
reservationService.deleteWaiting(reservationId, memberId)
|
||||
|
||||
@ -143,8 +152,8 @@ class ReservationController(
|
||||
|
||||
@PostMapping("/reservations/waiting/{id}/confirm")
|
||||
override fun confirmWaiting(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
reservationService.confirmWaiting(reservationId, memberId)
|
||||
|
||||
@ -153,8 +162,8 @@ class ReservationController(
|
||||
|
||||
@PostMapping("/reservations/waiting/{id}/reject")
|
||||
override fun rejectWaiting(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
@MemberId @Parameter(hidden = true) memberId: Long,
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
reservationService.rejectWaiting(reservationId, memberId)
|
||||
|
||||
|
||||
@ -5,36 +5,36 @@ import roomescape.payment.infrastructure.client.PaymentApproveRequest
|
||||
import java.time.LocalDate
|
||||
|
||||
data class AdminReservationCreateRequest(
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long,
|
||||
val memberId: Long
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long,
|
||||
val memberId: Long
|
||||
)
|
||||
|
||||
data class ReservationCreateWithPaymentRequest(
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long,
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long,
|
||||
|
||||
@Schema(description = "결제 위젯을 통해 받은 결제 키")
|
||||
val paymentKey: String,
|
||||
@Schema(description = "결제 위젯을 통해 받은 결제 키")
|
||||
val paymentKey: String,
|
||||
|
||||
@Schema(description = "결제 위젯을 통해 받은 주문번호.")
|
||||
val orderId: String,
|
||||
@Schema(description = "결제 위젯을 통해 받은 주문번호.")
|
||||
val orderId: String,
|
||||
|
||||
@Schema(description = "결제 위젯을 통해 받은 결제 금액")
|
||||
val amount: Long,
|
||||
@Schema(description = "결제 위젯을 통해 받은 결제 금액")
|
||||
val amount: Long,
|
||||
|
||||
@Schema(description = "결제 타입", example = "NORMAL")
|
||||
val paymentType: String
|
||||
@Schema(description = "결제 타입", example = "NORMAL")
|
||||
val paymentType: String
|
||||
)
|
||||
|
||||
fun ReservationCreateWithPaymentRequest.toPaymentApproveRequest(): PaymentApproveRequest = PaymentApproveRequest(
|
||||
paymentKey, orderId, amount, paymentType
|
||||
paymentKey, orderId, amount, paymentType
|
||||
)
|
||||
|
||||
data class WaitingCreateRequest(
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long
|
||||
val date: LocalDate,
|
||||
val timeId: Long,
|
||||
val themeId: Long
|
||||
)
|
||||
|
||||
@ -14,49 +14,49 @@ import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
data class MyReservationRetrieveResponse(
|
||||
val id: Long,
|
||||
val themeName: String,
|
||||
val date: LocalDate,
|
||||
val time: LocalTime,
|
||||
val status: ReservationStatus,
|
||||
@Schema(description = "대기 순번. 확정된 예약은 0의 값을 가집니다.")
|
||||
val rank: Long,
|
||||
@Schema(description = "결제 키. 결제가 완료된 예약에만 값이 존재합니다.")
|
||||
val paymentKey: String?,
|
||||
@Schema(description = "결제 금액. 결제가 완료된 예약에만 값이 존재합니다.")
|
||||
val amount: Long?
|
||||
val id: Long,
|
||||
val themeName: String,
|
||||
val date: LocalDate,
|
||||
val time: LocalTime,
|
||||
val status: ReservationStatus,
|
||||
@Schema(description = "대기 순번. 확정된 예약은 0의 값을 가집니다.")
|
||||
val rank: Long,
|
||||
@Schema(description = "결제 키. 결제가 완료된 예약에만 값이 존재합니다.")
|
||||
val paymentKey: String?,
|
||||
@Schema(description = "결제 금액. 결제가 완료된 예약에만 값이 존재합니다.")
|
||||
val amount: Long?
|
||||
)
|
||||
|
||||
data class MyReservationRetrieveListResponse(
|
||||
@Schema(description = "현재 로그인한 회원의 예약 및 대기 목록")
|
||||
val reservations: List<MyReservationRetrieveResponse>
|
||||
@Schema(description = "현재 로그인한 회원의 예약 및 대기 목록")
|
||||
val reservations: List<MyReservationRetrieveResponse>
|
||||
)
|
||||
|
||||
data class ReservationRetrieveResponse(
|
||||
val id: Long,
|
||||
val date: LocalDate,
|
||||
val id: Long,
|
||||
val date: LocalDate,
|
||||
|
||||
@field:JsonProperty("member")
|
||||
val member: MemberRetrieveResponse,
|
||||
@field:JsonProperty("member")
|
||||
val member: MemberRetrieveResponse,
|
||||
|
||||
@field:JsonProperty("time")
|
||||
val time: TimeCreateResponse,
|
||||
@field:JsonProperty("time")
|
||||
val time: TimeCreateResponse,
|
||||
|
||||
@field:JsonProperty("theme")
|
||||
val theme: ThemeRetrieveResponse,
|
||||
@field:JsonProperty("theme")
|
||||
val theme: ThemeRetrieveResponse,
|
||||
|
||||
val status: ReservationStatus
|
||||
val status: ReservationStatus
|
||||
)
|
||||
|
||||
fun ReservationEntity.toRetrieveResponse(): ReservationRetrieveResponse = ReservationRetrieveResponse(
|
||||
id = this.id!!,
|
||||
date = this.date,
|
||||
member = this.member.toRetrieveResponse(),
|
||||
time = this.time.toCreateResponse(),
|
||||
theme = this.theme.toResponse(),
|
||||
status = this.reservationStatus
|
||||
id = this.id!!,
|
||||
date = this.date,
|
||||
member = this.member.toRetrieveResponse(),
|
||||
time = this.time.toCreateResponse(),
|
||||
theme = this.theme.toResponse(),
|
||||
status = this.reservationStatus
|
||||
)
|
||||
|
||||
data class ReservationRetrieveListResponse(
|
||||
val reservations: List<ReservationRetrieveResponse>
|
||||
val reservations: List<ReservationRetrieveResponse>
|
||||
)
|
||||
|
||||
@ -28,24 +28,24 @@ interface ThemeAPI {
|
||||
@Operation(summary = "가장 많이 예약된 테마 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
||||
fun findMostReservedThemes(
|
||||
@RequestParam(defaultValue = "10") @Parameter(description = "최대로 조회할 테마 갯수") count: Int
|
||||
@RequestParam(defaultValue = "10") @Parameter(description = "최대로 조회할 테마 갯수") count: Int
|
||||
): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "테마 추가", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true),
|
||||
ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true),
|
||||
)
|
||||
fun createTheme(
|
||||
@Valid @RequestBody request: ThemeCreateRequest,
|
||||
@Valid @RequestBody request: ThemeCreateRequest,
|
||||
): ResponseEntity<CommonApiResponse<ThemeRetrieveResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "테마 삭제", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true),
|
||||
ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true),
|
||||
)
|
||||
fun deleteTheme(
|
||||
@PathVariable id: Long
|
||||
@PathVariable id: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class ThemeErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
) : ErrorCode {
|
||||
THEME_NOT_FOUND(HttpStatus.NOT_FOUND, "TH001", "테마를 찾을 수 없어요."),
|
||||
THEME_NAME_DUPLICATED(HttpStatus.BAD_REQUEST, "TH002", "이미 같은 이름의 테마가 있어요."),
|
||||
|
||||
@ -3,6 +3,6 @@ package roomescape.theme.exception
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class ThemeException(
|
||||
override val errorCode: ThemeErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: ThemeErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -5,11 +5,11 @@ import jakarta.persistence.*
|
||||
@Entity
|
||||
@Table(name = "themes")
|
||||
class ThemeEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
|
||||
var name: String,
|
||||
var description: String,
|
||||
var thumbnail: String
|
||||
var name: String,
|
||||
var description: String,
|
||||
var thumbnail: String
|
||||
)
|
||||
@ -6,7 +6,8 @@ import java.time.LocalDate
|
||||
|
||||
interface ThemeRepository : JpaRepository<ThemeEntity, Long> {
|
||||
|
||||
@Query(value = """
|
||||
@Query(
|
||||
value = """
|
||||
SELECT t
|
||||
FROM ThemeEntity t
|
||||
RIGHT JOIN ReservationEntity r ON t.id = r.theme.id
|
||||
@ -20,12 +21,14 @@ interface ThemeRepository : JpaRepository<ThemeEntity, Long> {
|
||||
|
||||
fun existsByName(name: String): Boolean
|
||||
|
||||
@Query(value = """
|
||||
@Query(
|
||||
value = """
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM ReservationEntity r
|
||||
WHERE r.theme.id = :id
|
||||
)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
fun isReservedTheme(id: Long): Boolean
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import java.net.URI
|
||||
|
||||
@RestController
|
||||
class ThemeController(
|
||||
private val themeService: ThemeService
|
||||
private val themeService: ThemeService
|
||||
) : ThemeAPI {
|
||||
|
||||
@GetMapping("/themes")
|
||||
@ -23,7 +23,7 @@ class ThemeController(
|
||||
|
||||
@GetMapping("/themes/most-reserved-last-week")
|
||||
override fun findMostReservedThemes(
|
||||
@RequestParam(defaultValue = "10") @Parameter(description = "최대로 조회할 테마 갯수") count: Int
|
||||
@RequestParam(defaultValue = "10") @Parameter(description = "최대로 조회할 테마 갯수") count: Int
|
||||
): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>> {
|
||||
val response: ThemeRetrieveListResponse = themeService.findMostReservedThemes(count)
|
||||
|
||||
@ -32,17 +32,17 @@ class ThemeController(
|
||||
|
||||
@PostMapping("/themes")
|
||||
override fun createTheme(
|
||||
@RequestBody @Valid request: ThemeCreateRequest
|
||||
@RequestBody @Valid request: ThemeCreateRequest
|
||||
): ResponseEntity<CommonApiResponse<ThemeRetrieveResponse>> {
|
||||
val themeResponse: ThemeRetrieveResponse = themeService.createTheme(request)
|
||||
|
||||
return ResponseEntity.created(URI.create("/themes/${themeResponse.id}"))
|
||||
.body(CommonApiResponse(themeResponse))
|
||||
.body(CommonApiResponse(themeResponse))
|
||||
}
|
||||
|
||||
@DeleteMapping("/themes/{id}")
|
||||
override fun deleteTheme(
|
||||
@PathVariable id: Long
|
||||
@PathVariable id: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
themeService.deleteTheme(id)
|
||||
|
||||
|
||||
@ -7,45 +7,45 @@ import org.hibernate.validator.constraints.URL
|
||||
import roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
|
||||
data class ThemeCreateRequest(
|
||||
@NotBlank
|
||||
@Size(max = 20)
|
||||
val name: String,
|
||||
@NotBlank
|
||||
@Size(max = 20)
|
||||
val name: String,
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 100)
|
||||
val description: String,
|
||||
@NotBlank
|
||||
@Size(max = 100)
|
||||
val description: String,
|
||||
|
||||
@URL
|
||||
@NotBlank
|
||||
@Schema(description = "썸네일 이미지 주소(URL).")
|
||||
val thumbnail: String
|
||||
@URL
|
||||
@NotBlank
|
||||
@Schema(description = "썸네일 이미지 주소(URL).")
|
||||
val thumbnail: String
|
||||
)
|
||||
|
||||
fun ThemeCreateRequest.toEntity(): ThemeEntity = ThemeEntity(
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnail = this.thumbnail
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnail = this.thumbnail
|
||||
)
|
||||
|
||||
data class ThemeRetrieveResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val description: String,
|
||||
@Schema(description = "썸네일 이미지 주소(URL).")
|
||||
val thumbnail: String
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val description: String,
|
||||
@Schema(description = "썸네일 이미지 주소(URL).")
|
||||
val thumbnail: String
|
||||
)
|
||||
|
||||
fun ThemeEntity.toResponse(): ThemeRetrieveResponse = ThemeRetrieveResponse(
|
||||
id = this.id!!,
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnail = this.thumbnail
|
||||
id = this.id!!,
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnail = this.thumbnail
|
||||
)
|
||||
|
||||
data class ThemeRetrieveListResponse(
|
||||
val themes: List<ThemeRetrieveResponse>
|
||||
val themes: List<ThemeRetrieveResponse>
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toResponse(): ThemeRetrieveListResponse = ThemeRetrieveListResponse(
|
||||
themes = this.map { it.toResponse() }
|
||||
themes = this.map { it.toResponse() }
|
||||
)
|
||||
|
||||
@ -30,21 +30,21 @@ interface TimeAPI {
|
||||
@Operation(summary = "시간 추가", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true))
|
||||
fun createTime(
|
||||
@Valid @RequestBody timeCreateRequest: TimeCreateRequest,
|
||||
@Valid @RequestBody timeCreateRequest: TimeCreateRequest,
|
||||
): ResponseEntity<CommonApiResponse<TimeCreateResponse>>
|
||||
|
||||
@Admin
|
||||
@Operation(summary = "시간 삭제", tags = ["관리자 로그인이 필요한 API"])
|
||||
@ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true))
|
||||
fun deleteTime(
|
||||
@PathVariable id: Long
|
||||
@PathVariable id: Long
|
||||
): ResponseEntity<CommonApiResponse<Unit>>
|
||||
|
||||
@LoginRequired
|
||||
@Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
||||
fun findTimesWithAvailability(
|
||||
@RequestParam date: LocalDate,
|
||||
@RequestParam themeId: Long
|
||||
@RequestParam date: LocalDate,
|
||||
@RequestParam themeId: Long
|
||||
): ResponseEntity<CommonApiResponse<TimeWithAvailabilityListResponse>>
|
||||
}
|
||||
@ -4,9 +4,9 @@ import org.springframework.http.HttpStatus
|
||||
import roomescape.common.exception.ErrorCode
|
||||
|
||||
enum class TimeErrorCode(
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
override val httpStatus: HttpStatus,
|
||||
override val errorCode: String,
|
||||
override val message: String
|
||||
) : ErrorCode {
|
||||
TIME_NOT_FOUND(HttpStatus.NOT_FOUND, "TM001", "시간을 찾을 수 없어요."),
|
||||
TIME_DUPLICATED(HttpStatus.BAD_REQUEST, "TM002", "이미 같은 시간이 있어요."),
|
||||
|
||||
@ -4,6 +4,6 @@ import roomescape.common.exception.ErrorCode
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
|
||||
class TimeException(
|
||||
override val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
override val errorCode: ErrorCode,
|
||||
override val message: String = errorCode.message
|
||||
) : RoomescapeException(errorCode, message)
|
||||
|
||||
@ -6,8 +6,8 @@ import java.time.LocalTime
|
||||
@Entity
|
||||
@Table(name = "times")
|
||||
class TimeEntity(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
var startAt: LocalTime
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long? = null,
|
||||
var startAt: LocalTime
|
||||
)
|
||||
|
||||
@ -11,7 +11,7 @@ import java.time.LocalDate
|
||||
|
||||
@RestController
|
||||
class TimeController(
|
||||
private val timeService: TimeService
|
||||
private val timeService: TimeService
|
||||
) : TimeAPI {
|
||||
|
||||
@GetMapping("/times")
|
||||
@ -23,13 +23,13 @@ class TimeController(
|
||||
|
||||
@PostMapping("/times")
|
||||
override fun createTime(
|
||||
@Valid @RequestBody timeCreateRequest: TimeCreateRequest,
|
||||
@Valid @RequestBody timeCreateRequest: TimeCreateRequest,
|
||||
): ResponseEntity<CommonApiResponse<TimeCreateResponse>> {
|
||||
val response: TimeCreateResponse = timeService.createTime(timeCreateRequest)
|
||||
|
||||
return ResponseEntity
|
||||
.created(URI.create("/times/${response.id}"))
|
||||
.body(CommonApiResponse(response))
|
||||
.created(URI.create("/times/${response.id}"))
|
||||
.body(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@DeleteMapping("/times/{id}")
|
||||
@ -41,8 +41,8 @@ class TimeController(
|
||||
|
||||
@GetMapping("/times/search")
|
||||
override fun findTimesWithAvailability(
|
||||
@RequestParam date: LocalDate,
|
||||
@RequestParam themeId: Long
|
||||
@RequestParam date: LocalDate,
|
||||
@RequestParam themeId: Long
|
||||
): ResponseEntity<CommonApiResponse<TimeWithAvailabilityListResponse>> {
|
||||
val response: TimeWithAvailabilityListResponse = timeService.findTimesWithAvailability(date, themeId)
|
||||
|
||||
|
||||
@ -6,52 +6,52 @@ import java.time.LocalTime
|
||||
|
||||
@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.")
|
||||
data class TimeCreateRequest(
|
||||
@Schema(description = "시간", type = "string", example = "09:00")
|
||||
val startAt: LocalTime
|
||||
@Schema(description = "시간", type = "string", example = "09:00")
|
||||
val startAt: LocalTime
|
||||
)
|
||||
|
||||
fun TimeCreateRequest.toEntity(): TimeEntity = TimeEntity(startAt = this.startAt)
|
||||
|
||||
@Schema(name = "예약 시간 정보", description = "예약 시간 추가 및 조회 응답시 사용됩니다.")
|
||||
data class TimeCreateResponse(
|
||||
@Schema(description = "시간 식별자")
|
||||
val id: Long,
|
||||
@Schema(description = "시간 식별자")
|
||||
val id: Long,
|
||||
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime
|
||||
)
|
||||
|
||||
fun TimeEntity.toCreateResponse(): TimeCreateResponse = TimeCreateResponse(this.id!!, this.startAt)
|
||||
|
||||
data class TimeRetrieveResponse(
|
||||
@Schema(description = "시간 식별자.")
|
||||
val id: Long,
|
||||
@Schema(description = "시간 식별자.")
|
||||
val id: Long,
|
||||
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime
|
||||
)
|
||||
|
||||
fun TimeEntity.toResponse(): TimeRetrieveResponse = TimeRetrieveResponse(this.id!!, this.startAt)
|
||||
|
||||
data class TimeRetrieveListResponse(
|
||||
val times: List<TimeRetrieveResponse>
|
||||
val times: List<TimeRetrieveResponse>
|
||||
)
|
||||
|
||||
fun List<TimeEntity>.toResponse(): TimeRetrieveListResponse = TimeRetrieveListResponse(
|
||||
this.map { it.toResponse() }
|
||||
this.map { it.toResponse() }
|
||||
)
|
||||
|
||||
data class TimeWithAvailabilityResponse(
|
||||
@Schema(description = "시간 식별자")
|
||||
val id: Long,
|
||||
@Schema(description = "시간 식별자")
|
||||
val id: Long,
|
||||
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime,
|
||||
@Schema(description = "시간")
|
||||
val startAt: LocalTime,
|
||||
|
||||
@Schema(description = "예약 가능 여부")
|
||||
val isAvailable: Boolean
|
||||
@Schema(description = "예약 가능 여부")
|
||||
val isAvailable: Boolean
|
||||
)
|
||||
|
||||
data class TimeWithAvailabilityListResponse(
|
||||
val times: List<TimeWithAvailabilityResponse>
|
||||
val times: List<TimeWithAvailabilityResponse>
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<included>
|
||||
<conversionRule conversionWord="maskedMessage"
|
||||
class="roomescape.common.log.RoomescapeLogMaskingConverter" />
|
||||
class="roomescape.common.log.RoomescapeLogMaskingConverter"/>
|
||||
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %green(${PID:- }) --- [%15.15thread] %cyan(%-40logger{36}) : %maskedMessage%n%throwable"/>
|
||||
|
||||
@ -47,11 +47,11 @@ class JwtHandlerTest : FunSpec({
|
||||
test("시크릿 키가 잘못된 경우 예외를 던진다.") {
|
||||
val now = Date()
|
||||
val invalidSignatureToken: String = Jwts.builder()
|
||||
.claim("memberId", memberId)
|
||||
.issuedAt(now)
|
||||
.expiration(Date(now.time + JwtFixture.EXPIRATION_TIME))
|
||||
.signWith(Keys.hmacShaKeyFor(JwtFixture.SECRET_KEY_STRING.substring(1).toByteArray()))
|
||||
.compact()
|
||||
.claim("memberId", memberId)
|
||||
.issuedAt(now)
|
||||
.expiration(Date(now.time + JwtFixture.EXPIRATION_TIME))
|
||||
.signWith(Keys.hmacShaKeyFor(JwtFixture.SECRET_KEY_STRING.substring(1).toByteArray()))
|
||||
.compact()
|
||||
|
||||
shouldThrow<AuthException> {
|
||||
jwtHandler.getMemberIdFromToken(invalidSignatureToken)
|
||||
|
||||
@ -10,7 +10,7 @@ import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
class JacksonConfigTest(
|
||||
private val objectMapper: ObjectMapper = JacksonConfig().objectMapper()
|
||||
private val objectMapper: ObjectMapper = JacksonConfig().objectMapper()
|
||||
) : FunSpec({
|
||||
|
||||
context("날짜는 yyyy-mm-dd 형식이다.") {
|
||||
|
||||
@ -65,10 +65,10 @@ class PaymentServiceTest : FunSpec({
|
||||
every {
|
||||
canceledPaymentRepository.save(any())
|
||||
} returns PaymentFixture.createCanceled(
|
||||
id = 1L,
|
||||
paymentKey = paymentKey,
|
||||
cancelReason = "Test",
|
||||
cancelAmount = paymentEntity.totalAmount,
|
||||
id = 1L,
|
||||
paymentKey = paymentKey,
|
||||
cancelReason = "Test",
|
||||
cancelAmount = paymentEntity.totalAmount,
|
||||
)
|
||||
|
||||
val result: PaymentCancelRequest = paymentService.createCanceledPaymentByReservationId(reservationId)
|
||||
@ -99,8 +99,8 @@ class PaymentServiceTest : FunSpec({
|
||||
|
||||
test("paymentKey로 canceledPaymentEntity를 찾고, canceledAt을 업데이트한다.") {
|
||||
val canceledPaymentEntity = PaymentFixture.createCanceled(
|
||||
paymentKey = paymentKey,
|
||||
canceledAt = canceledAt.minusMinutes(1)
|
||||
paymentKey = paymentKey,
|
||||
canceledAt = canceledAt.minusMinutes(1)
|
||||
)
|
||||
|
||||
every {
|
||||
|
||||
@ -11,17 +11,17 @@ import roomescape.payment.web.PaymentCancelResponse
|
||||
class PaymentCancelResponseDeserializerTest : StringSpec({
|
||||
|
||||
val objectMapper: ObjectMapper = jacksonObjectMapper().registerModule(
|
||||
SimpleModule().addDeserializer(
|
||||
PaymentCancelResponse::class.java,
|
||||
PaymentCancelResponseDeserializer()
|
||||
)
|
||||
SimpleModule().addDeserializer(
|
||||
PaymentCancelResponse::class.java,
|
||||
PaymentCancelResponseDeserializer()
|
||||
)
|
||||
)
|
||||
|
||||
"결제 취소 응답을 역직렬화하여 PaymentCancelResponse 객체를 생성한다" {
|
||||
val cancelResponseJson: String = SampleTossPaymentConst.cancelJson
|
||||
val cancelResponse: PaymentCancelResponse = objectMapper.readValue(
|
||||
cancelResponseJson,
|
||||
PaymentCancelResponse::class.java
|
||||
cancelResponseJson,
|
||||
PaymentCancelResponse::class.java
|
||||
)
|
||||
|
||||
assertSoftly(cancelResponse) {
|
||||
|
||||
@ -15,10 +15,10 @@ object SampleTossPaymentConst {
|
||||
val cancelReason: String = "테스트 결제 취소"
|
||||
|
||||
val paymentRequest: PaymentApproveRequest = PaymentApproveRequest(
|
||||
paymentKey,
|
||||
orderId,
|
||||
amount,
|
||||
paymentType
|
||||
paymentKey,
|
||||
orderId,
|
||||
amount,
|
||||
paymentType
|
||||
)
|
||||
|
||||
val paymentRequestJson: String = """
|
||||
@ -31,9 +31,9 @@ object SampleTossPaymentConst {
|
||||
""".trimIndent()
|
||||
|
||||
val cancelRequest: PaymentCancelRequest = PaymentCancelRequest(
|
||||
paymentKey,
|
||||
amount,
|
||||
cancelReason
|
||||
paymentKey,
|
||||
amount,
|
||||
cancelReason
|
||||
)
|
||||
|
||||
val cancelRequestJson: String = """
|
||||
|
||||
@ -21,8 +21,8 @@ import roomescape.payment.web.PaymentCancelResponse
|
||||
|
||||
@RestClientTest(TossPaymentClient::class)
|
||||
class TossPaymentClientTest(
|
||||
@Autowired val client: TossPaymentClient,
|
||||
@Autowired val mockServer: MockRestServiceServer
|
||||
@Autowired val client: TossPaymentClient,
|
||||
@Autowired val mockServer: MockRestServiceServer
|
||||
) : FunSpec() {
|
||||
|
||||
init {
|
||||
@ -40,9 +40,9 @@ class TossPaymentClientTest(
|
||||
test("성공 응답") {
|
||||
commonAction().andRespond {
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.confirmJson)
|
||||
.createResponse(it)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.confirmJson)
|
||||
.createResponse(it)
|
||||
}
|
||||
|
||||
// when
|
||||
@ -60,9 +60,9 @@ class TossPaymentClientTest(
|
||||
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) {
|
||||
commonAction().andRespond {
|
||||
withStatus(httpStatus)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||
.createResponse(it)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||
.createResponse(it)
|
||||
}
|
||||
|
||||
// when
|
||||
@ -99,9 +99,9 @@ class TossPaymentClientTest(
|
||||
test("성공 응답") {
|
||||
commonAction().andRespond {
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.cancelJson)
|
||||
.createResponse(it)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.cancelJson)
|
||||
.createResponse(it)
|
||||
}
|
||||
|
||||
// when
|
||||
@ -119,9 +119,9 @@ class TossPaymentClientTest(
|
||||
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) {
|
||||
commonAction().andRespond {
|
||||
withStatus(httpStatus)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||
.createResponse(it)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||
.createResponse(it)
|
||||
}
|
||||
|
||||
val cancelRequest: PaymentCancelRequest = SampleTossPaymentConst.cancelRequest
|
||||
|
||||
@ -10,14 +10,14 @@ import java.util.*
|
||||
|
||||
@DataJpaTest
|
||||
class CanceledPaymentRepositoryTest(
|
||||
@Autowired val canceledPaymentRepository: CanceledPaymentRepository,
|
||||
@Autowired val canceledPaymentRepository: CanceledPaymentRepository,
|
||||
) : FunSpec() {
|
||||
init {
|
||||
context("paymentKey로 CanceledPaymentEntity 조회") {
|
||||
val paymentKey = "test-payment-key"
|
||||
beforeTest {
|
||||
PaymentFixture.createCanceled(paymentKey = paymentKey)
|
||||
.also { canceledPaymentRepository.save(it) }
|
||||
.also { canceledPaymentRepository.save(it) }
|
||||
}
|
||||
|
||||
test("정상 반환") {
|
||||
@ -30,7 +30,7 @@ class CanceledPaymentRepositoryTest(
|
||||
|
||||
test("null 반환") {
|
||||
canceledPaymentRepository.findByPaymentKey(UUID.randomUUID().toString())
|
||||
.also { it shouldBe null }
|
||||
.also { it shouldBe null }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ import roomescape.util.ReservationFixture
|
||||
|
||||
@DataJpaTest
|
||||
class PaymentRepositoryTest(
|
||||
@Autowired val paymentRepository: PaymentRepository,
|
||||
@Autowired val entityManager: EntityManager
|
||||
@Autowired val paymentRepository: PaymentRepository,
|
||||
@Autowired val entityManager: EntityManager
|
||||
) : FunSpec() {
|
||||
|
||||
lateinit var reservation: ReservationEntity
|
||||
@ -23,17 +23,17 @@ class PaymentRepositoryTest(
|
||||
beforeTest {
|
||||
reservation = setupReservation()
|
||||
PaymentFixture.create(reservation = reservation)
|
||||
.also { paymentRepository.save(it) }
|
||||
.also { paymentRepository.save(it) }
|
||||
}
|
||||
|
||||
test("true") {
|
||||
paymentRepository.existsByReservationId(reservation.id!!)
|
||||
.also { it shouldBe true }
|
||||
.also { it shouldBe true }
|
||||
}
|
||||
|
||||
test("false") {
|
||||
paymentRepository.existsByReservationId(reservation.id!! + 1L)
|
||||
.also { it shouldBe false }
|
||||
.also { it shouldBe false }
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,19 +43,19 @@ class PaymentRepositoryTest(
|
||||
beforeTest {
|
||||
reservation = setupReservation()
|
||||
paymentKey = PaymentFixture.create(reservation = reservation)
|
||||
.also { paymentRepository.save(it) }
|
||||
.paymentKey
|
||||
.also { paymentRepository.save(it) }
|
||||
.paymentKey
|
||||
}
|
||||
|
||||
test("정상 반환") {
|
||||
paymentRepository.findPaymentKeyByReservationId(reservation.id!!)
|
||||
?.let { it shouldBe paymentKey }
|
||||
?: throw AssertionError("Unexpected null value")
|
||||
?.let { it shouldBe paymentKey }
|
||||
?: throw AssertionError("Unexpected null value")
|
||||
}
|
||||
|
||||
test("null 반환") {
|
||||
paymentRepository.findPaymentKeyByReservationId(reservation.id!! + 1)
|
||||
.also { it shouldBe null }
|
||||
.also { it shouldBe null }
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,27 +65,27 @@ class PaymentRepositoryTest(
|
||||
beforeTest {
|
||||
reservation = setupReservation()
|
||||
payment = PaymentFixture.create(reservation = reservation)
|
||||
.also { paymentRepository.save(it) }
|
||||
.also { paymentRepository.save(it) }
|
||||
}
|
||||
|
||||
test("정상 반환") {
|
||||
paymentRepository.findByPaymentKey(payment.paymentKey)
|
||||
?.also {
|
||||
assertSoftly(it) {
|
||||
this.id shouldBe payment.id
|
||||
this.orderId shouldBe payment.orderId
|
||||
this.paymentKey shouldBe payment.paymentKey
|
||||
this.totalAmount shouldBe payment.totalAmount
|
||||
this.reservation.id shouldBe payment.reservation.id
|
||||
this.approvedAt shouldBe payment.approvedAt
|
||||
}
|
||||
?.also {
|
||||
assertSoftly(it) {
|
||||
this.id shouldBe payment.id
|
||||
this.orderId shouldBe payment.orderId
|
||||
this.paymentKey shouldBe payment.paymentKey
|
||||
this.totalAmount shouldBe payment.totalAmount
|
||||
this.reservation.id shouldBe payment.reservation.id
|
||||
this.approvedAt shouldBe payment.approvedAt
|
||||
}
|
||||
?: throw AssertionError("Unexpected null value")
|
||||
}
|
||||
?: throw AssertionError("Unexpected null value")
|
||||
}
|
||||
|
||||
test("null 반환") {
|
||||
paymentRepository.findByPaymentKey("non-existent-key")
|
||||
.also { it shouldBe null }
|
||||
.also { it shouldBe null }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,10 +27,10 @@ class ReservationServiceTest : FunSpec({
|
||||
val memberService: MemberService = mockk()
|
||||
val themeService: ThemeService = mockk()
|
||||
val reservationService = ReservationService(
|
||||
reservationRepository,
|
||||
timeService,
|
||||
memberService,
|
||||
themeService
|
||||
reservationRepository,
|
||||
timeService,
|
||||
memberService,
|
||||
themeService
|
||||
)
|
||||
|
||||
context("예약을 추가할 때") {
|
||||
@ -64,7 +64,7 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
test("지난 날짜이면 예외를 던진다.") {
|
||||
val reservationRequest = ReservationFixture.createRequest().copy(
|
||||
date = LocalDate.now().minusDays(1)
|
||||
date = LocalDate.now().minusDays(1)
|
||||
)
|
||||
|
||||
every {
|
||||
@ -80,13 +80,13 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
test("지난 시간이면 예외를 던진다.") {
|
||||
val reservationRequest = ReservationFixture.createRequest().copy(
|
||||
date = LocalDate.now(),
|
||||
date = LocalDate.now(),
|
||||
)
|
||||
|
||||
every {
|
||||
timeService.findById(reservationRequest.timeId)
|
||||
} returns TimeFixture.create(
|
||||
startAt = LocalTime.now().minusMinutes(1)
|
||||
startAt = LocalTime.now().minusMinutes(1)
|
||||
)
|
||||
|
||||
shouldThrow<ReservationException> {
|
||||
@ -101,9 +101,9 @@ class ReservationServiceTest : FunSpec({
|
||||
context("예약 대기를 걸 때") {
|
||||
test("이미 예약한 회원이 같은 날짜와 테마로 대기를 걸면 예외를 던진다.") {
|
||||
val reservationRequest = ReservationFixture.createRequest().copy(
|
||||
date = LocalDate.now(),
|
||||
themeId = 1L,
|
||||
timeId = 1L,
|
||||
date = LocalDate.now(),
|
||||
themeId = 1L,
|
||||
timeId = 1L,
|
||||
)
|
||||
|
||||
every {
|
||||
@ -112,9 +112,9 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
shouldThrow<ReservationException> {
|
||||
val waitingRequest = ReservationFixture.createWaitingRequest(
|
||||
date = reservationRequest.date,
|
||||
themeId = reservationRequest.themeId,
|
||||
timeId = reservationRequest.timeId
|
||||
date = reservationRequest.date,
|
||||
themeId = reservationRequest.themeId,
|
||||
timeId = reservationRequest.timeId
|
||||
)
|
||||
reservationService.createWaiting(waitingRequest, 1L)
|
||||
}.also {
|
||||
@ -140,8 +140,8 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
test("대기중인 해당 예약이 이미 확정된 상태라면 예외를 던진다.") {
|
||||
val alreadyConfirmed = ReservationFixture.create(
|
||||
id = reservationId,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
id = reservationId,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
)
|
||||
every {
|
||||
reservationRepository.findByIdOrNull(reservationId)
|
||||
@ -156,9 +156,9 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
test("타인의 대기를 취소하려고 하면 예외를 던진다.") {
|
||||
val otherMembersWaiting = ReservationFixture.create(
|
||||
id = reservationId,
|
||||
member = MemberFixture.create(id = member.id!! + 1L),
|
||||
status = ReservationStatus.WAITING
|
||||
id = reservationId,
|
||||
member = MemberFixture.create(id = member.id!! + 1L),
|
||||
status = ReservationStatus.WAITING
|
||||
)
|
||||
|
||||
every {
|
||||
@ -180,10 +180,10 @@ class ReservationServiceTest : FunSpec({
|
||||
|
||||
shouldThrow<ReservationException> {
|
||||
reservationService.searchReservations(
|
||||
null,
|
||||
null,
|
||||
startFrom,
|
||||
endAt
|
||||
null,
|
||||
null,
|
||||
startFrom,
|
||||
endAt
|
||||
)
|
||||
}.also {
|
||||
it.errorCode shouldBe ReservationErrorCode.INVALID_SEARCH_DATE_RANGE
|
||||
@ -263,8 +263,8 @@ class ReservationServiceTest : FunSpec({
|
||||
test("이미 확정된 예약이면 예외를 던진다.") {
|
||||
val member = MemberFixture.create(id = 1L, role = Role.ADMIN)
|
||||
val reservation = ReservationFixture.create(
|
||||
id = 1L,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
id = 1L,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
)
|
||||
|
||||
every {
|
||||
|
||||
@ -22,27 +22,27 @@ class ReservationWithPaymentServiceTest : FunSpec({
|
||||
val paymentService: PaymentService = mockk()
|
||||
|
||||
val reservationWithPaymentService = ReservationWithPaymentService(
|
||||
reservationService = reservationService,
|
||||
paymentService = paymentService
|
||||
reservationService = reservationService,
|
||||
paymentService = paymentService
|
||||
)
|
||||
|
||||
val reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest = ReservationFixture.createRequest()
|
||||
val paymentApproveResponse = PaymentFixture.createApproveResponse()
|
||||
val memberId = 1L
|
||||
val reservationEntity: ReservationEntity = ReservationFixture.create(
|
||||
id = 1L,
|
||||
date = reservationCreateWithPaymentRequest.date,
|
||||
time = TimeFixture.create(id = reservationCreateWithPaymentRequest.timeId),
|
||||
theme = ThemeFixture.create(id = reservationCreateWithPaymentRequest.themeId),
|
||||
member = MemberFixture.create(id = memberId),
|
||||
status = ReservationStatus.CONFIRMED
|
||||
id = 1L,
|
||||
date = reservationCreateWithPaymentRequest.date,
|
||||
time = TimeFixture.create(id = reservationCreateWithPaymentRequest.timeId),
|
||||
theme = ThemeFixture.create(id = reservationCreateWithPaymentRequest.themeId),
|
||||
member = MemberFixture.create(id = memberId),
|
||||
status = ReservationStatus.CONFIRMED
|
||||
)
|
||||
val paymentEntity: PaymentEntity = PaymentFixture.create(
|
||||
id = 1L,
|
||||
orderId = reservationCreateWithPaymentRequest.orderId,
|
||||
paymentKey = reservationCreateWithPaymentRequest.paymentKey,
|
||||
totalAmount = reservationCreateWithPaymentRequest.amount,
|
||||
reservation = reservationEntity,
|
||||
id = 1L,
|
||||
orderId = reservationCreateWithPaymentRequest.orderId,
|
||||
paymentKey = reservationCreateWithPaymentRequest.paymentKey,
|
||||
totalAmount = reservationCreateWithPaymentRequest.amount,
|
||||
reservation = reservationEntity,
|
||||
)
|
||||
|
||||
context("addReservationWithPayment") {
|
||||
@ -56,9 +56,9 @@ class ReservationWithPaymentServiceTest : FunSpec({
|
||||
} returns paymentEntity.toCreateResponse()
|
||||
|
||||
val result: ReservationRetrieveResponse = reservationWithPaymentService.createReservationAndPayment(
|
||||
request = reservationCreateWithPaymentRequest,
|
||||
paymentInfo = paymentApproveResponse,
|
||||
memberId = memberId
|
||||
request = reservationCreateWithPaymentRequest,
|
||||
paymentInfo = paymentApproveResponse,
|
||||
memberId = memberId
|
||||
)
|
||||
|
||||
assertSoftly(result) {
|
||||
@ -75,9 +75,9 @@ class ReservationWithPaymentServiceTest : FunSpec({
|
||||
context("removeReservationWithPayment") {
|
||||
test("예약 및 결제 정보를 삭제하고, 결제 취소 정보를 저장한다.") {
|
||||
val paymentCancelRequest: PaymentCancelRequest = PaymentFixture.createCancelRequest().copy(
|
||||
paymentKey = paymentEntity.paymentKey,
|
||||
amount = paymentEntity.totalAmount,
|
||||
cancelReason = "고객 요청"
|
||||
paymentKey = paymentEntity.paymentKey,
|
||||
amount = paymentEntity.totalAmount,
|
||||
cancelReason = "고객 요청"
|
||||
)
|
||||
|
||||
every {
|
||||
@ -89,8 +89,8 @@ class ReservationWithPaymentServiceTest : FunSpec({
|
||||
} just Runs
|
||||
|
||||
val result: PaymentCancelRequest = reservationWithPaymentService.deleteReservationAndPayment(
|
||||
reservationId = reservationEntity.id!!,
|
||||
memberId = reservationEntity.member.id!!
|
||||
reservationId = reservationEntity.id!!,
|
||||
memberId = reservationEntity.member.id!!
|
||||
)
|
||||
|
||||
result shouldBe paymentCancelRequest
|
||||
|
||||
@ -17,8 +17,8 @@ import roomescape.util.TimeFixture
|
||||
|
||||
@DataJpaTest
|
||||
class ReservationRepositoryTest(
|
||||
val entityManager: EntityManager,
|
||||
val reservationRepository: ReservationRepository,
|
||||
val entityManager: EntityManager,
|
||||
val reservationRepository: ReservationRepository,
|
||||
) : FunSpec() {
|
||||
init {
|
||||
context("findByTime") {
|
||||
@ -26,10 +26,12 @@ class ReservationRepositoryTest(
|
||||
|
||||
beforeTest {
|
||||
listOf(
|
||||
ReservationFixture.create(time = time),
|
||||
ReservationFixture.create(time = TimeFixture.create(
|
||||
startAt = time.startAt.plusSeconds(1)
|
||||
))
|
||||
ReservationFixture.create(time = time),
|
||||
ReservationFixture.create(
|
||||
time = TimeFixture.create(
|
||||
startAt = time.startAt.plusSeconds(1)
|
||||
)
|
||||
)
|
||||
).forEach {
|
||||
persistReservation(it)
|
||||
}
|
||||
@ -64,9 +66,9 @@ class ReservationRepositoryTest(
|
||||
}
|
||||
|
||||
listOf(
|
||||
ReservationFixture.create(date = date, theme = theme1),
|
||||
ReservationFixture.create(date = date.plusDays(1), theme = theme1),
|
||||
ReservationFixture.create(date = date, theme = theme2),
|
||||
ReservationFixture.create(date = date, theme = theme1),
|
||||
ReservationFixture.create(date = date.plusDays(1), theme = theme1),
|
||||
ReservationFixture.create(date = date, theme = theme2),
|
||||
).forEach {
|
||||
entityManager.persist(it.time)
|
||||
entityManager.persist(it.member)
|
||||
@ -124,9 +126,10 @@ class ReservationRepositoryTest(
|
||||
persistReservation(it)
|
||||
}
|
||||
|
||||
confirmedPaymentRequired = ReservationFixture.create(status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED).also {
|
||||
persistReservation(it)
|
||||
}
|
||||
confirmedPaymentRequired =
|
||||
ReservationFixture.create(status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED).also {
|
||||
persistReservation(it)
|
||||
}
|
||||
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
@ -134,7 +137,7 @@ class ReservationRepositoryTest(
|
||||
|
||||
test("예약이 없으면 false를 반환한다.") {
|
||||
val maxId: Long = listOf(waiting, confirmed, confirmedPaymentRequired)
|
||||
.maxOfOrNull { it.id ?: 0L } ?: 0L
|
||||
.maxOfOrNull { it.id ?: 0L } ?: 0L
|
||||
reservationRepository.isExistConfirmedReservation(maxId + 1L) shouldBe false
|
||||
}
|
||||
|
||||
@ -161,14 +164,15 @@ class ReservationRepositoryTest(
|
||||
|
||||
test("결제 정보를 포함한 회원의 예약 목록을 반환한다.") {
|
||||
val payment: PaymentEntity = PaymentFixture.create(
|
||||
reservation = reservation
|
||||
reservation = reservation
|
||||
).also {
|
||||
entityManager.persist(it)
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
}
|
||||
|
||||
val result: List<MyReservationRetrieveResponse> = reservationRepository.findAllByMemberId(reservation.member.id!!)
|
||||
val result: List<MyReservationRetrieveResponse> =
|
||||
reservationRepository.findAllByMemberId(reservation.member.id!!)
|
||||
|
||||
result shouldHaveSize 1
|
||||
assertSoftly(result.first()) {
|
||||
@ -179,7 +183,8 @@ class ReservationRepositoryTest(
|
||||
}
|
||||
|
||||
test("결제 정보가 없다면 paymentKey와 amount는 null로 반환한다.") {
|
||||
val result: List<MyReservationRetrieveResponse> = reservationRepository.findAllByMemberId(reservation.member.id!!)
|
||||
val result: List<MyReservationRetrieveResponse> =
|
||||
reservationRepository.findAllByMemberId(reservation.member.id!!)
|
||||
|
||||
result shouldHaveSize 1
|
||||
assertSoftly(result.first()) {
|
||||
|
||||
@ -17,8 +17,8 @@ import java.time.LocalDate
|
||||
|
||||
@DataJpaTest
|
||||
class ReservationSearchSpecificationTest(
|
||||
val entityManager: EntityManager,
|
||||
val reservationRepository: ReservationRepository
|
||||
val entityManager: EntityManager,
|
||||
val reservationRepository: ReservationRepository
|
||||
) : StringSpec() {
|
||||
|
||||
init {
|
||||
@ -31,8 +31,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"동일한 테마의 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.sameThemeId(theme.id)
|
||||
.build()
|
||||
.sameThemeId(theme.id)
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -44,8 +44,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"동일한 회원의 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.sameMemberId(member.id)
|
||||
.build()
|
||||
.sameMemberId(member.id)
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -57,8 +57,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"동일한 예약 시간의 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.sameTimeId(time.id)
|
||||
.build()
|
||||
.sameTimeId(time.id)
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -70,8 +70,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"동일한 날짜의 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.sameDate(LocalDate.now())
|
||||
.build()
|
||||
.sameDate(LocalDate.now())
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -83,8 +83,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"확정 상태인 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.confirmed()
|
||||
.build()
|
||||
.confirmed()
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -96,8 +96,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"대기 상태인 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.waiting()
|
||||
.build()
|
||||
.waiting()
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -109,8 +109,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"예약 날짜가 오늘 이후인 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.dateStartFrom(LocalDate.now())
|
||||
.build()
|
||||
.dateStartFrom(LocalDate.now())
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -122,8 +122,8 @@ class ReservationSearchSpecificationTest(
|
||||
|
||||
"예약 날짜가 내일 이전인 예약을 조회한다" {
|
||||
val spec = ReservationSearchSpecification()
|
||||
.dateEndAt(LocalDate.now().plusDays(1))
|
||||
.build()
|
||||
.dateEndAt(LocalDate.now().plusDays(1))
|
||||
.build()
|
||||
|
||||
val results: List<ReservationEntity> = reservationRepository.findAll(spec)
|
||||
|
||||
@ -145,31 +145,31 @@ class ReservationSearchSpecificationTest(
|
||||
}
|
||||
|
||||
confirmedNow = ReservationFixture.create(
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now(),
|
||||
status = ReservationStatus.CONFIRMED
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now(),
|
||||
status = ReservationStatus.CONFIRMED
|
||||
).also {
|
||||
entityManager.persist(it)
|
||||
}
|
||||
|
||||
confirmedNotPaidYesterday = ReservationFixture.create(
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now().minusDays(1),
|
||||
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now().minusDays(1),
|
||||
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
).also {
|
||||
entityManager.persist(it)
|
||||
}
|
||||
|
||||
waitingTomorrow = ReservationFixture.create(
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now().plusDays(1),
|
||||
status = ReservationStatus.WAITING
|
||||
time = time,
|
||||
member = member,
|
||||
theme = theme,
|
||||
date = LocalDate.now().plusDays(1),
|
||||
status = ReservationStatus.WAITING
|
||||
).also {
|
||||
entityManager.persist(it)
|
||||
}
|
||||
|
||||
@ -61,9 +61,9 @@ class ThemeServiceTest : FunSpec({
|
||||
|
||||
context("save") {
|
||||
val request = ThemeCreateRequest(
|
||||
name = "New Theme",
|
||||
description = "Description",
|
||||
thumbnail = "http://example.com/thumbnail.jpg"
|
||||
name = "New Theme",
|
||||
description = "Description",
|
||||
thumbnail = "http://example.com/thumbnail.jpg"
|
||||
)
|
||||
|
||||
test("저장 성공") {
|
||||
@ -74,10 +74,10 @@ class ThemeServiceTest : FunSpec({
|
||||
every {
|
||||
themeRepository.save(any())
|
||||
} returns ThemeFixture.create(
|
||||
id = 1L,
|
||||
name = request.name,
|
||||
description = request.description,
|
||||
thumbnail = request.thumbnail
|
||||
id = 1L,
|
||||
name = request.name,
|
||||
description = request.description,
|
||||
thumbnail = request.thumbnail
|
||||
)
|
||||
|
||||
val response: ThemeRetrieveResponse = themeService.createTheme(request)
|
||||
|
||||
@ -10,8 +10,8 @@ import java.time.LocalDate
|
||||
|
||||
@DataJpaTest
|
||||
class ThemeRepositoryTest(
|
||||
val themeRepository: ThemeRepository,
|
||||
val entityManager: EntityManager
|
||||
val themeRepository: ThemeRepository,
|
||||
val entityManager: EntityManager
|
||||
) : FunSpec() {
|
||||
|
||||
init {
|
||||
@ -19,65 +19,65 @@ class ThemeRepositoryTest(
|
||||
beforeTest {
|
||||
for (i in 1..10) {
|
||||
TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "테마$i",
|
||||
reservedCount = i,
|
||||
date = LocalDate.now().minusDays(i.toLong()),
|
||||
entityManager = entityManager,
|
||||
name = "테마$i",
|
||||
reservedCount = i,
|
||||
date = LocalDate.now().minusDays(i.toLong()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("지난 10일간 예약 수가 가장 많은 테마 5개를 조회한다.") {
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(1),
|
||||
5
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(1),
|
||||
5
|
||||
).also { themes ->
|
||||
themes.size shouldBe 5
|
||||
themes.map { it.name } shouldContainInOrder listOf(
|
||||
"테마10", "테마9", "테마8", "테마7", "테마6"
|
||||
"테마10", "테마9", "테마8", "테마7", "테마6"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("8일 전부터 5일 전까지 예약 수가 가장 많은 테마 3개를 조회한다.") {
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().minusDays(8),
|
||||
LocalDate.now().minusDays(5),
|
||||
3
|
||||
LocalDate.now().minusDays(8),
|
||||
LocalDate.now().minusDays(5),
|
||||
3
|
||||
).also { themes ->
|
||||
themes.size shouldBe 3
|
||||
themes.map { it.name } shouldContainInOrder listOf(
|
||||
"테마8", "테마7", "테마6"
|
||||
"테마8", "테마7", "테마6"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("예약 수가 동일하면 먼저 생성된 테마를 우선 조회한다.") {
|
||||
TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "테마11",
|
||||
reservedCount = 5,
|
||||
date = LocalDate.now().minusDays(5),
|
||||
entityManager = entityManager,
|
||||
name = "테마11",
|
||||
reservedCount = 5,
|
||||
date = LocalDate.now().minusDays(5),
|
||||
)
|
||||
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().minusDays(6),
|
||||
LocalDate.now().minusDays(4),
|
||||
5
|
||||
LocalDate.now().minusDays(6),
|
||||
LocalDate.now().minusDays(4),
|
||||
5
|
||||
).also { themes ->
|
||||
themes.size shouldBe 4
|
||||
themes.map { it.name } shouldContainInOrder listOf(
|
||||
"테마6", "테마5", "테마11", "테마4"
|
||||
"테마6", "테마5", "테마11", "테마4"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("입력된 갯수보다 조회된 갯수가 작으면, 조회된 갯수만큼 반환한다.") {
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(6),
|
||||
10
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(6),
|
||||
10
|
||||
).also { themes ->
|
||||
themes.size shouldBe 5
|
||||
}
|
||||
@ -85,9 +85,9 @@ class ThemeRepositoryTest(
|
||||
|
||||
test("입력된 갯수보다 조회된 갯수가 많으면, 입력된 갯수만큼 반환한다.") {
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(1),
|
||||
15
|
||||
LocalDate.now().minusDays(10),
|
||||
LocalDate.now().minusDays(1),
|
||||
15
|
||||
).also { themes ->
|
||||
themes.size shouldBe 10
|
||||
}
|
||||
@ -95,9 +95,9 @@ class ThemeRepositoryTest(
|
||||
|
||||
test("입력된 날짜 범위에 예약된 테마가 없을 경우 빈 리스트를 반환한다.") {
|
||||
themeRepository.findPopularThemes(
|
||||
LocalDate.now().plusDays(1),
|
||||
LocalDate.now().plusDays(10),
|
||||
5
|
||||
LocalDate.now().plusDays(1),
|
||||
LocalDate.now().plusDays(10),
|
||||
5
|
||||
).also { themes ->
|
||||
themes.size shouldBe 0
|
||||
}
|
||||
@ -107,10 +107,10 @@ class ThemeRepositoryTest(
|
||||
val themeName = "test-theme"
|
||||
beforeTest {
|
||||
TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = themeName,
|
||||
reservedCount = 0,
|
||||
date = LocalDate.now()
|
||||
entityManager = entityManager,
|
||||
name = themeName,
|
||||
reservedCount = 0,
|
||||
date = LocalDate.now()
|
||||
)
|
||||
}
|
||||
test("테마 이름이 존재하면 true를 반환한다.") {
|
||||
@ -125,20 +125,20 @@ class ThemeRepositoryTest(
|
||||
context("isReservedTheme") {
|
||||
test("테마가 예약 중이면 true를 반환한다.") {
|
||||
val theme = TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "예약된 테마",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now()
|
||||
entityManager = entityManager,
|
||||
name = "예약된 테마",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now()
|
||||
)
|
||||
themeRepository.isReservedTheme(theme.id!!) shouldBe true
|
||||
}
|
||||
|
||||
test("테마가 예약 중이 아니면 false를 반환한다.") {
|
||||
val theme = TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "예약되지 않은 테마",
|
||||
reservedCount = 0,
|
||||
date = LocalDate.now()
|
||||
entityManager = entityManager,
|
||||
name = "예약되지 않은 테마",
|
||||
reservedCount = 0,
|
||||
date = LocalDate.now()
|
||||
)
|
||||
themeRepository.isReservedTheme(theme.id!!) shouldBe false
|
||||
}
|
||||
|
||||
@ -14,25 +14,25 @@ import java.time.LocalTime
|
||||
|
||||
object TestThemeCreateUtil {
|
||||
fun createThemeWithReservations(
|
||||
entityManager: EntityManager,
|
||||
name: String,
|
||||
reservedCount: Int,
|
||||
date: LocalDate,
|
||||
entityManager: EntityManager,
|
||||
name: String,
|
||||
reservedCount: Int,
|
||||
date: LocalDate,
|
||||
): ThemeEntity {
|
||||
val themeEntity: ThemeEntity = ThemeFixture.create(name = name).also { entityManager.persist(it) }
|
||||
val member: MemberEntity = MemberFixture.create().also { entityManager.persist(it) }
|
||||
|
||||
for (i in 1..reservedCount) {
|
||||
val time: TimeEntity = TimeFixture.create(
|
||||
startAt = LocalTime.now().plusMinutes(i.toLong())
|
||||
startAt = LocalTime.now().plusMinutes(i.toLong())
|
||||
).also { entityManager.persist(it) }
|
||||
|
||||
ReservationFixture.create(
|
||||
date = date,
|
||||
theme = themeEntity,
|
||||
member = member,
|
||||
time = time,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
date = date,
|
||||
theme = themeEntity,
|
||||
member = member,
|
||||
time = time,
|
||||
status = ReservationStatus.CONFIRMED
|
||||
).also { entityManager.persist(it) }
|
||||
}
|
||||
|
||||
|
||||
@ -17,9 +17,9 @@ import kotlin.random.Random
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class MostReservedThemeApiTest(
|
||||
@LocalServerPort val port: Int,
|
||||
val transactionTemplate: TransactionTemplate,
|
||||
val entityManager: EntityManager,
|
||||
@LocalServerPort val port: Int,
|
||||
val transactionTemplate: TransactionTemplate,
|
||||
val entityManager: EntityManager,
|
||||
) : FunSpec({
|
||||
extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_SPEC))
|
||||
}) {
|
||||
@ -29,19 +29,19 @@ class MostReservedThemeApiTest(
|
||||
// 지난 7일간 예약된 테마 10개 생성
|
||||
for (i in 1..10) {
|
||||
TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "테마$i",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now().minusDays(Random.nextLong(1, 7))
|
||||
entityManager = entityManager,
|
||||
name = "테마$i",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now().minusDays(Random.nextLong(1, 7))
|
||||
)
|
||||
}
|
||||
|
||||
// 8일 전 예약된 테마 1개 생성
|
||||
TestThemeCreateUtil.createThemeWithReservations(
|
||||
entityManager = entityManager,
|
||||
name = "테마11",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now().minusDays(8)
|
||||
entityManager = entityManager,
|
||||
name = "테마11",
|
||||
reservedCount = 1,
|
||||
date = LocalDate.now().minusDays(8)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,8 +22,8 @@ class TimeServiceTest : FunSpec({
|
||||
val reservationRepository: ReservationRepository = mockk()
|
||||
|
||||
val timeService = TimeService(
|
||||
timeRepository = timeRepository,
|
||||
reservationRepository = reservationRepository
|
||||
timeRepository = timeRepository,
|
||||
reservationRepository = reservationRepository
|
||||
)
|
||||
|
||||
context("findTimeById") {
|
||||
@ -46,8 +46,8 @@ class TimeServiceTest : FunSpec({
|
||||
test("정상 저장") {
|
||||
every { timeRepository.existsByStartAt(request.startAt) } returns false
|
||||
every { timeRepository.save(any()) } returns TimeFixture.create(
|
||||
id = 1L,
|
||||
startAt = request.startAt
|
||||
id = 1L,
|
||||
startAt = request.startAt
|
||||
)
|
||||
|
||||
val response = timeService.createTime(request)
|
||||
|
||||
@ -9,8 +9,8 @@ import java.time.LocalTime
|
||||
|
||||
@DataJpaTest
|
||||
class TimeRepositoryTest(
|
||||
val entityManager: EntityManager,
|
||||
val timeRepository: TimeRepository,
|
||||
val entityManager: EntityManager,
|
||||
val timeRepository: TimeRepository,
|
||||
) : FunSpec({
|
||||
|
||||
context("existsByStartAt") {
|
||||
|
||||
@ -12,8 +12,8 @@ import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class DatabaseCleaner(
|
||||
val entityManager: EntityManager,
|
||||
val jdbcTemplate: JdbcTemplate,
|
||||
val entityManager: EntityManager,
|
||||
val jdbcTemplate: JdbcTemplate,
|
||||
) {
|
||||
val tables: List<String> by lazy {
|
||||
jdbcTemplate.query("SHOW TABLES") { rs, _ ->
|
||||
@ -38,7 +38,7 @@ enum class CleanerMode {
|
||||
}
|
||||
|
||||
class DatabaseCleanerExtension(
|
||||
private val mode: CleanerMode
|
||||
private val mode: CleanerMode
|
||||
) : AfterTestListener, AfterSpecListener {
|
||||
override suspend fun afterTest(testCase: TestCase, result: TestResult) {
|
||||
super.afterTest(testCase, result)
|
||||
@ -58,7 +58,7 @@ class DatabaseCleanerExtension(
|
||||
|
||||
private suspend fun getCleaner(): DatabaseCleaner {
|
||||
return testContextManager().testContext
|
||||
.applicationContext
|
||||
.getBean(DatabaseCleaner::class.java)
|
||||
.applicationContext
|
||||
.getBean(DatabaseCleaner::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,88 +24,88 @@ object MemberFixture {
|
||||
const val NOT_LOGGED_IN_USERID: Long = 0
|
||||
|
||||
fun create(
|
||||
id: Long? = null,
|
||||
name: String = "sangdol",
|
||||
account: String = "default",
|
||||
password: String = "password",
|
||||
role: Role = Role.ADMIN
|
||||
id: Long? = null,
|
||||
name: String = "sangdol",
|
||||
account: String = "default",
|
||||
password: String = "password",
|
||||
role: Role = Role.ADMIN
|
||||
): MemberEntity = MemberEntity(id, name, "$account@email.com", password, role)
|
||||
|
||||
fun admin(): MemberEntity = create(
|
||||
id = 2L,
|
||||
account = "admin",
|
||||
role = Role.ADMIN
|
||||
id = 2L,
|
||||
account = "admin",
|
||||
role = Role.ADMIN
|
||||
)
|
||||
|
||||
fun adminLoginRequest(): LoginRequest = LoginRequest(
|
||||
email = admin().email,
|
||||
password = admin().password
|
||||
email = admin().email,
|
||||
password = admin().password
|
||||
)
|
||||
|
||||
fun user(): MemberEntity = create(
|
||||
id = 1L,
|
||||
account = "user",
|
||||
role = Role.MEMBER
|
||||
id = 1L,
|
||||
account = "user",
|
||||
role = Role.MEMBER
|
||||
)
|
||||
|
||||
fun userLoginRequest(): LoginRequest = LoginRequest(
|
||||
email = user().email,
|
||||
password = user().password
|
||||
email = user().email,
|
||||
password = user().password
|
||||
)
|
||||
}
|
||||
|
||||
object TimeFixture {
|
||||
fun create(
|
||||
id: Long? = null,
|
||||
startAt: LocalTime = LocalTime.now().plusHours(1),
|
||||
id: Long? = null,
|
||||
startAt: LocalTime = LocalTime.now().plusHours(1),
|
||||
): TimeEntity = TimeEntity(id, startAt)
|
||||
}
|
||||
|
||||
object ThemeFixture {
|
||||
fun create(
|
||||
id: Long? = null,
|
||||
name: String = "Default Theme",
|
||||
description: String = "Default Description",
|
||||
thumbnail: String = "https://example.com/default-thumbnail.jpg"
|
||||
id: Long? = null,
|
||||
name: String = "Default Theme",
|
||||
description: String = "Default Description",
|
||||
thumbnail: String = "https://example.com/default-thumbnail.jpg"
|
||||
): ThemeEntity = ThemeEntity(id, name, description, thumbnail)
|
||||
}
|
||||
|
||||
object ReservationFixture {
|
||||
fun create(
|
||||
id: Long? = null,
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
theme: ThemeEntity = ThemeFixture.create(),
|
||||
time: TimeEntity = TimeFixture.create(),
|
||||
member: MemberEntity = MemberFixture.create(),
|
||||
status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
id: Long? = null,
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
theme: ThemeEntity = ThemeFixture.create(),
|
||||
time: TimeEntity = TimeFixture.create(),
|
||||
member: MemberEntity = MemberFixture.create(),
|
||||
status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||
): ReservationEntity = ReservationEntity(id, date, time, theme, member, status)
|
||||
|
||||
fun createRequest(
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
themeId: Long = 1L,
|
||||
timeId: Long = 1L,
|
||||
paymentKey: String = "paymentKey",
|
||||
orderId: String = "orderId",
|
||||
amount: Long = 10000L,
|
||||
paymentType: String = "NORMAL",
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
themeId: Long = 1L,
|
||||
timeId: Long = 1L,
|
||||
paymentKey: String = "paymentKey",
|
||||
orderId: String = "orderId",
|
||||
amount: Long = 10000L,
|
||||
paymentType: String = "NORMAL",
|
||||
): ReservationCreateWithPaymentRequest = ReservationCreateWithPaymentRequest(
|
||||
date = date,
|
||||
timeId = timeId,
|
||||
themeId = themeId,
|
||||
paymentKey = paymentKey,
|
||||
orderId = orderId,
|
||||
amount = amount,
|
||||
paymentType = paymentType
|
||||
date = date,
|
||||
timeId = timeId,
|
||||
themeId = themeId,
|
||||
paymentKey = paymentKey,
|
||||
orderId = orderId,
|
||||
amount = amount,
|
||||
paymentType = paymentType
|
||||
)
|
||||
|
||||
fun createWaitingRequest(
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
themeId: Long = 1L,
|
||||
timeId: Long = 1L
|
||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||
themeId: Long = 1L,
|
||||
timeId: Long = 1L
|
||||
): WaitingCreateRequest = WaitingCreateRequest(
|
||||
date = date,
|
||||
timeId = timeId,
|
||||
themeId = themeId
|
||||
date = date,
|
||||
timeId = timeId,
|
||||
themeId = themeId
|
||||
)
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ object JwtFixture {
|
||||
const val EXPIRATION_TIME: Long = 1000 * 60 * 60
|
||||
|
||||
fun create(
|
||||
secretKey: String = SECRET_KEY_STRING,
|
||||
expirationTime: Long = EXPIRATION_TIME
|
||||
secretKey: String = SECRET_KEY_STRING,
|
||||
expirationTime: Long = EXPIRATION_TIME
|
||||
): JwtHandler = JwtHandler(secretKey, expirationTime)
|
||||
}
|
||||
|
||||
@ -125,63 +125,63 @@ object PaymentFixture {
|
||||
const val AMOUNT: Long = 10000L
|
||||
|
||||
fun create(
|
||||
id: Long? = null,
|
||||
orderId: String = ORDER_ID,
|
||||
paymentKey: String = PAYMENT_KEY,
|
||||
totalAmount: Long = AMOUNT,
|
||||
reservation: ReservationEntity = ReservationFixture.create(id = 1L),
|
||||
approvedAt: OffsetDateTime = OffsetDateTime.now()
|
||||
id: Long? = null,
|
||||
orderId: String = ORDER_ID,
|
||||
paymentKey: String = PAYMENT_KEY,
|
||||
totalAmount: Long = AMOUNT,
|
||||
reservation: ReservationEntity = ReservationFixture.create(id = 1L),
|
||||
approvedAt: OffsetDateTime = OffsetDateTime.now()
|
||||
): PaymentEntity = PaymentEntity(
|
||||
id = id,
|
||||
orderId = orderId,
|
||||
paymentKey = paymentKey,
|
||||
totalAmount = totalAmount,
|
||||
reservation = reservation,
|
||||
approvedAt = approvedAt
|
||||
id = id,
|
||||
orderId = orderId,
|
||||
paymentKey = paymentKey,
|
||||
totalAmount = totalAmount,
|
||||
reservation = reservation,
|
||||
approvedAt = approvedAt
|
||||
)
|
||||
|
||||
fun createCanceled(
|
||||
id: Long? = null,
|
||||
paymentKey: String = PAYMENT_KEY,
|
||||
cancelReason: String = "Test Cancel",
|
||||
cancelAmount: Long = AMOUNT,
|
||||
approvedAt: OffsetDateTime = OffsetDateTime.now(),
|
||||
canceledAt: OffsetDateTime = approvedAt.plusHours(1)
|
||||
id: Long? = null,
|
||||
paymentKey: String = PAYMENT_KEY,
|
||||
cancelReason: String = "Test Cancel",
|
||||
cancelAmount: Long = AMOUNT,
|
||||
approvedAt: OffsetDateTime = OffsetDateTime.now(),
|
||||
canceledAt: OffsetDateTime = approvedAt.plusHours(1)
|
||||
): CanceledPaymentEntity = CanceledPaymentEntity(
|
||||
id = id,
|
||||
paymentKey = paymentKey,
|
||||
cancelReason = cancelReason,
|
||||
cancelAmount = cancelAmount,
|
||||
approvedAt = approvedAt,
|
||||
canceledAt = canceledAt
|
||||
id = id,
|
||||
paymentKey = paymentKey,
|
||||
cancelReason = cancelReason,
|
||||
cancelAmount = cancelAmount,
|
||||
approvedAt = approvedAt,
|
||||
canceledAt = canceledAt
|
||||
|
||||
)
|
||||
|
||||
fun createApproveRequest(): PaymentApproveRequest = PaymentApproveRequest(
|
||||
paymentKey = PAYMENT_KEY,
|
||||
orderId = ORDER_ID,
|
||||
amount = AMOUNT,
|
||||
paymentType = "CARD"
|
||||
paymentKey = PAYMENT_KEY,
|
||||
orderId = ORDER_ID,
|
||||
amount = AMOUNT,
|
||||
paymentType = "CARD"
|
||||
)
|
||||
|
||||
fun createApproveResponse(): PaymentApproveResponse = PaymentApproveResponse(
|
||||
paymentKey = PAYMENT_KEY,
|
||||
orderId = ORDER_ID,
|
||||
approvedAt = OffsetDateTime.now(),
|
||||
totalAmount = AMOUNT
|
||||
paymentKey = PAYMENT_KEY,
|
||||
orderId = ORDER_ID,
|
||||
approvedAt = OffsetDateTime.now(),
|
||||
totalAmount = AMOUNT
|
||||
)
|
||||
|
||||
fun createCancelRequest(): PaymentCancelRequest = PaymentCancelRequest(
|
||||
paymentKey = PAYMENT_KEY,
|
||||
amount = AMOUNT,
|
||||
cancelReason = "Test Cancel"
|
||||
paymentKey = PAYMENT_KEY,
|
||||
amount = AMOUNT,
|
||||
cancelReason = "Test Cancel"
|
||||
)
|
||||
|
||||
fun createCancelResponse(): PaymentCancelResponse = PaymentCancelResponse(
|
||||
cancelStatus = "SUCCESS",
|
||||
cancelReason = "Test Cancel",
|
||||
cancelAmount = AMOUNT,
|
||||
canceledAt = OffsetDateTime.now().plusMinutes(1)
|
||||
cancelStatus = "SUCCESS",
|
||||
cancelReason = "Test Cancel",
|
||||
cancelAmount = AMOUNT,
|
||||
canceledAt = OffsetDateTime.now().plusMinutes(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user