diff --git a/src/main/java/spring/fitlinkbe/domain/common/exception/ErrorCode.java b/src/main/java/spring/fitlinkbe/domain/common/exception/ErrorCode.java index ed65d130..169a9e61 100644 --- a/src/main/java/spring/fitlinkbe/domain/common/exception/ErrorCode.java +++ b/src/main/java/spring/fitlinkbe/domain/common/exception/ErrorCode.java @@ -58,6 +58,7 @@ public enum ErrorCode { // Session 관련 ErrorCode SESSION_CREATE_FAILED("세션 생성에 실패하였습니다.", 400), + INVALID_SESSION_COUNT("세션 횟수가 적절하지 않습니다.", 400), SESSION_NOT_FOUND("세션 정보를 찾지 못하였습니다.", 404), SESSION_IS_ALREADY_CANCEL("이미 세션이 취소되었습니다.", 409), SESSION_IS_ALREADY_END("이미 세션이 종료되었습니다.", 409), diff --git a/src/main/java/spring/fitlinkbe/infra/common/sessioninfo/SessionInfoEntity.java b/src/main/java/spring/fitlinkbe/infra/common/sessioninfo/SessionInfoEntity.java index 08bf533d..b4f0fac2 100644 --- a/src/main/java/spring/fitlinkbe/infra/common/sessioninfo/SessionInfoEntity.java +++ b/src/main/java/spring/fitlinkbe/infra/common/sessioninfo/SessionInfoEntity.java @@ -2,6 +2,8 @@ import jakarta.persistence.*; import lombok.*; +import spring.fitlinkbe.domain.common.exception.CustomException; +import spring.fitlinkbe.domain.common.exception.ErrorCode; import spring.fitlinkbe.domain.common.model.SessionInfo; import spring.fitlinkbe.infra.common.model.BaseTimeEntity; import spring.fitlinkbe.infra.member.MemberEntity; @@ -55,4 +57,18 @@ public SessionInfo toDomain() { .remainingCount(remainingCount) .build(); } + + @PrePersist + @PreUpdate + public void prePersist() { + validateSessionCount(); + } + + public void validateSessionCount() { + if (remainingCount > totalCount) { + throw new CustomException(ErrorCode.INVALID_SESSION_COUNT, + "남은 세션 수는 총 세션 수보다 클 수 없습니다. [remainingCount: %d, totalCount: %d]" + .formatted(remainingCount, totalCount)); + } + } } diff --git a/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java b/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java index 7cd4830b..86bd1b11 100644 --- a/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java +++ b/src/test/java/spring/fitlinkbe/integration/MemberIntegrationTest.java @@ -1154,6 +1154,43 @@ public void memberSessionCountUpdateFailByNotConnected() { }); } + @Test + @DisplayName("회원 PT 횟수 수정 실패 - 남은 세션 수가 총 세션 수보다 많을 때") + public void memberSessionCountUpdateFailByRemainingCountExceedingTotalCount() { + // given + // 회원, 트레이너 정보가 있을 때 + Member member = testDataHandler.createMember(); + testDataHandler.createToken(testDataHandler.getMemberPersonalDetail(member.getMemberId())); + Trainer trainer = testDataHandler.createTrainer("AB1423"); + testDataHandler.connectMemberAndTrainer(member, trainer); + String token = testDataHandler.createTokenFromTrainer(trainer); + + SessionInfo sessionInfo = testDataHandler.createSessionInfo(member, trainer); + + // when + // 트레이너가 회원 PT 횟수 수정 요청을 보낸다면 남은 세션 수가 총 세션 수보다 많을 때 + int remainingCount = 6; + int totalCount = 5; + String url = MEMBER_SESSION_COUNT_UPDATE_API.replace("{memberId}", member.getMemberId().toString()) + .replace("{sessionInfoId}", sessionInfo.getSessionInfoId().toString()); + SessionInfoDto.UpdateRequest request = new SessionInfoDto.UpdateRequest(remainingCount, totalCount); + String requestBody = writeValueAsString(request); + ExtractableResponse result = patch(url, requestBody, token); + + // then + // 남은 세션 수가 총 세션 수보다 많다는 에러 응답을 받는다 + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result.statusCode()).isEqualTo(200); + ApiResultResponse response = readValue(result.body().jsonPath().prettify(), new TypeReference<>() { + }); + + softly.assertThat(response).isNotNull(); + softly.assertThat(response.success()).isFalse(); + softly.assertThat(response.status()).isEqualTo(400); + softly.assertThat(response.data()).isNull(); + }); + } + } @Nested