refactor: PaymentEntity 코틀린 전환 및 불필요한 null-check validation 제거

This commit is contained in:
이상진 2025-07-16 13:33:41 +09:00
parent 0791e953c7
commit 2ee1920099
6 changed files with 25 additions and 182 deletions

View File

@ -32,7 +32,7 @@ public class PaymentService {
public ReservationPaymentResponse savePayment(PaymentApprove.Response paymentResponse,
Reservation reservation) {
PaymentEntity paymentEntity = new PaymentEntity(paymentResponse.orderId, paymentResponse.paymentKey,
PaymentEntity paymentEntity = new PaymentEntity(null, paymentResponse.orderId, paymentResponse.paymentKey,
paymentResponse.totalAmount, reservation, paymentResponse.approvedAt);
PaymentEntity saved = paymentRepository.save(paymentEntity);
return ReservationPaymentResponse.from(saved);

View File

@ -1,108 +1,29 @@
package roomescape.payment.infrastructure.persistence;
package roomescape.payment.infrastructure.persistence
import java.time.OffsetDateTime;
import org.springframework.http.HttpStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import roomescape.common.exception.ErrorType;
import roomescape.common.exception.RoomescapeException;
import roomescape.reservation.domain.Reservation;
import jakarta.persistence.*
import roomescape.reservation.domain.Reservation
import java.time.OffsetDateTime
@Entity
public class PaymentEntity {
@Table(name = "payment")
class PaymentEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
var orderId: String,
@Column(nullable = false)
private String orderId;
@Column(nullable = false)
var paymentKey: String,
@Column(nullable = false)
private String paymentKey;
@Column(nullable = false)
var totalAmount: Long,
@Column(nullable = false)
private Long totalAmount;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "reservation_id", nullable = false)
var reservation: Reservation,
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "reservation_id", nullable = false)
private Reservation reservation;
@Column(nullable = false)
private OffsetDateTime approvedAt;
protected PaymentEntity() {
}
public PaymentEntity(String orderId, String paymentKey, Long totalAmount, Reservation reservation,
OffsetDateTime approvedAt) {
validate(orderId, paymentKey, totalAmount, reservation, approvedAt);
this.orderId = orderId;
this.paymentKey = paymentKey;
this.totalAmount = totalAmount;
this.reservation = reservation;
this.approvedAt = approvedAt;
}
private void validate(String orderId, String paymentKey, Long totalAmount, Reservation reservation,
OffsetDateTime approvedAt) {
validateIsNullOrBlank(orderId, "orderId");
validateIsNullOrBlank(paymentKey, "paymentKey");
validateIsInvalidAmount(totalAmount);
validateIsNull(reservation, "reservation");
validateIsNull(approvedAt, "approvedAt");
}
private void validateIsNullOrBlank(String input, String fieldName) {
if (input == null || input.isBlank()) {
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
HttpStatus.BAD_REQUEST);
}
}
private void validateIsInvalidAmount(Long totalAmount) {
if (totalAmount == null || totalAmount < 0) {
throw new RoomescapeException(ErrorType.INVALID_REQUEST_DATA,
String.format("[totalAmount : %d]", totalAmount), HttpStatus.BAD_REQUEST);
}
}
private <T> void validateIsNull(T value, String fieldName) {
if (value == null) {
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
HttpStatus.BAD_REQUEST);
}
}
public Long getId() {
return id;
}
public String getOrderId() {
return orderId;
}
public String getPaymentKey() {
return paymentKey;
}
public Long getTotalAmount() {
return totalAmount;
}
public Reservation getReservation() {
return reservation;
}
public OffsetDateTime getApprovedAt() {
return approvedAt;
}
}
@Column(nullable = false)
var approvedAt: OffsetDateTime
)

View File

@ -58,7 +58,7 @@ data class ReservationPaymentResponse(
@JvmStatic
fun from(saved: PaymentEntity): ReservationPaymentResponse {
return ReservationPaymentResponse(
saved.id,
saved.id!!,
saved.orderId,
saved.paymentKey,
saved.totalAmount,

View File

@ -54,7 +54,7 @@ public interface ReservationRepository extends JpaRepository<Reservation, Long>,
)
FROM Reservation r
JOIN r.theme t
LEFT JOIN Payment p
LEFT JOIN PaymentEntity p
ON p.reservation = r
WHERE r.member.id = :memberId
""")

View File

@ -1,78 +0,0 @@
package roomescape.payment.infrastructure.persistence;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.NullSource;
import roomescape.common.exception.RoomescapeException;
import roomescape.member.infrastructure.persistence.Member;
import roomescape.member.infrastructure.persistence.Role;
import roomescape.reservation.domain.Reservation;
import roomescape.reservation.domain.ReservationStatus;
import roomescape.reservation.domain.ReservationTime;
import roomescape.theme.domain.Theme;
class PaymentEntityTest {
private Reservation reservation;
@BeforeEach
void setUp() {
LocalDate now = LocalDate.now();
ReservationTime reservationTime = new ReservationTime(LocalTime.now());
Theme theme = new Theme("name", "desc", "thumb");
Member member = new Member(null, "name", "email", "password", Role.MEMBER);
reservation = new Reservation(now, reservationTime, theme, member, ReservationStatus.CONFIRMED);
}
@ParameterizedTest
@DisplayName("paymentKey가 null 또는 빈값이면 예외가 발생한다.")
@NullAndEmptySource
void invalidPaymentKey(String paymentKey) {
assertThatThrownBy(() -> new PaymentEntity("order-id", paymentKey, 10000L, reservation, OffsetDateTime.now()))
.isInstanceOf(RoomescapeException.class);
}
@ParameterizedTest
@DisplayName("orderId가 null 또는 빈값이면 예외가 발생한다.")
@NullAndEmptySource
void invalidOrderId(String orderId) {
assertThatThrownBy(() -> new PaymentEntity(orderId, "payment-key", 10000L, reservation, OffsetDateTime.now()))
.isInstanceOf(RoomescapeException.class);
}
@ParameterizedTest
@DisplayName("amount가 null 또는 0 이하면 예외가 발생한다.")
@CsvSource(value = {"null", "-1"}, nullValues = {"null"})
void invalidOrderId(Long totalAmount) {
assertThatThrownBy(
() -> new PaymentEntity("orderId", "payment-key", totalAmount, reservation, OffsetDateTime.now()))
.isInstanceOf(RoomescapeException.class);
}
@ParameterizedTest
@DisplayName("Reservation이 null이면 예외가 발생한다.")
@NullSource
void invalidReservation(Reservation reservation) {
assertThatThrownBy(() -> new PaymentEntity("orderId", "payment-key", 10000L, reservation, OffsetDateTime.now()))
.isInstanceOf(RoomescapeException.class);
}
@ParameterizedTest
@DisplayName("승인 날짜가 null이면 예외가 발생한다.")
@NullSource
void invalidApprovedAt(OffsetDateTime approvedAt) {
assertThatThrownBy(() -> new PaymentEntity("orderId", "payment-key", 10000L, reservation, approvedAt))
.isInstanceOf(RoomescapeException.class);
}
}

View File

@ -399,7 +399,7 @@ public class ReservationControllerTest {
Reservation saved = reservationRepository.save(
new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED));
PaymentEntity savedPaymentEntity = paymentRepository.save(
new PaymentEntity("pk", "oi", 1000L, saved, OffsetDateTime.now().minusHours(1L)));
new PaymentEntity(null, "pk", "oi", 1000L, saved, OffsetDateTime.now().minusHours(1L)));
// when
when(paymentClient.cancelPayment(any(PaymentCancel.Request.class)))