-
Notifications
You must be signed in to change notification settings - Fork 2
MOSU-179 feat: 신청 마감 validator 구현 #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,10 @@ | |
| import java.time.LocalDate; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
| import life.mosu.mosuserver.application.exam.cache.ExamQuotaCacheManager; | ||
| import life.mosu.mosuserver.domain.application.ApplicationJpaRepository; | ||
| import life.mosu.mosuserver.domain.exam.ExamJpaEntity; | ||
| import life.mosu.mosuserver.domain.exam.ExamJpaRepository; | ||
|
|
@@ -20,6 +22,7 @@ public class ApplicationValidator { | |
|
|
||
| private final ExamJpaRepository examJpaRepository; | ||
| private final ApplicationJpaRepository applicationJpaRepository; | ||
| private final ExamQuotaCacheManager examQuotaCacheManager; | ||
|
|
||
| public void requestNoDuplicateExams(List<Long> examIds) { | ||
| Set<Long> examIdSet = new HashSet<>(examIds); | ||
|
|
@@ -30,7 +33,7 @@ public void requestNoDuplicateExams(List<Long> examIds) { | |
|
|
||
| public void examIdsAndLunchSelection(List<ExamApplicationRequest> requests) { | ||
| if (requests == null || requests.isEmpty()) { | ||
| throw new CustomRuntimeException(ErrorCode.EXAM_APPLICATION_NOT_FOUND); | ||
| throw new CustomRuntimeException(ErrorCode.EXAM_NOT_FOUND); | ||
| } | ||
|
|
||
| List<Long> requestedExamIds = requests.stream() | ||
|
|
@@ -68,7 +71,7 @@ public void noDuplicateApplication(Long userId, List<Long> examIds) { | |
| } | ||
| } | ||
|
|
||
| public void ExamDateNotPassed(List<Long> examIds) { | ||
| public void examDateNotPassed(List<Long> examIds) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds); | ||
| boolean hasPassedExam = exams.stream() | ||
| .anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now())); | ||
|
|
@@ -77,4 +80,22 @@ public void ExamDateNotPassed(List<Long> examIds) { | |
| throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED); | ||
| } | ||
| } | ||
|
|
||
| public void examNotFull(List<Long> examIds) { | ||
| boolean isFull = examIds.stream() | ||
| .anyMatch(examId -> { | ||
| Optional<Long> currentApplications = examQuotaCacheManager.getCurrentApplications( | ||
| examId); | ||
| Optional<Long> maxCapacity = examQuotaCacheManager.getMaxCapacity(examId); | ||
|
|
||
| if (currentApplications.isPresent() && maxCapacity.isPresent()) { | ||
| return currentApplications.get() >= maxCapacity.get(); | ||
| } | ||
| return false; | ||
| }); | ||
|
Comment on lines
+86
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The lambda expression within boolean isFull = examIds.stream()
.anyMatch(examId -> examQuotaCacheManager.getMaxCapacity(examId)
.flatMap(maxCapacity -> examQuotaCacheManager.getCurrentApplications(examId)
.map(currentApplications -> currentApplications >= maxCapacity))
.orElse(false)); |
||
|
|
||
| if (isFull) { | ||
| throw new CustomRuntimeException(ErrorCode.APPLICATION_CLOSED); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,6 @@ | |
| import life.mosu.mosuserver.domain.examapplication.projection.ExamApplicationInfoProjection; | ||
| import life.mosu.mosuserver.domain.examapplication.projection.ExamTicketInfoProjection; | ||
| import life.mosu.mosuserver.domain.examapplication.service.ExamNumberGenerationService; | ||
| import life.mosu.mosuserver.domain.payment.PaymentJpaRepository; | ||
| import life.mosu.mosuserver.global.exception.CustomRuntimeException; | ||
| import life.mosu.mosuserver.global.exception.ErrorCode; | ||
| import life.mosu.mosuserver.infra.persistence.s3.S3Service; | ||
|
|
@@ -39,7 +38,6 @@ public class ExamApplicationService { | |
| private final ApplicationJpaRepository applicationJpaRepository; | ||
| private final ExamSubjectJpaRepository examSubjectJpaRepository; | ||
| private final ExamNumberGenerationService examNumberGenerationService; | ||
| private final PaymentJpaRepository paymentJpaRepository; | ||
| private final S3Service s3Service; | ||
| private final FixedQuantityDiscountCalculator calculator; | ||
|
|
||
|
|
@@ -122,7 +120,7 @@ public ExamApplicationInfoResponse getApplication(Long userId, Long examApplicat | |
| // examApplicationId); | ||
| List<ExamApplicationJpaEntity> examApplicationEntities = examApplicationJpaRepository.findByApplicationId( | ||
| applicationId); | ||
| Integer lunchCount = (int) examApplicationEntities.stream() | ||
| int lunchCount = (int) examApplicationEntities.stream() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| .filter(ExamApplicationJpaEntity::getIsLunchChecked) | ||
| .count(); | ||
|
|
||
|
|
@@ -173,8 +171,11 @@ private void validateUser(Long userId, Long examApplicationId) { | |
| } | ||
|
|
||
| private int getAppliedDiscountAmount(Integer totalAmount) { | ||
| log.info("total amount: {}", totalAmount); | ||
| return calculator.getAppliedDiscountAmount(totalAmount); | ||
| try { | ||
| return calculator.getAppliedDiscountAmount(totalAmount); | ||
| } catch (Exception ex) { | ||
| throw new CustomRuntimeException(ErrorCode.PRICE_LOAD_FAILURE); | ||
| } | ||
|
Comment on lines
+174
to
+178
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Catching a generic } catch (IllegalArgumentException ex) { |
||
| } | ||
|
|
||
| private void validateExamTicketOpenDate(LocalDate examDate, String examNumber) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ public interface RefundJpaRepository extends JpaRepository<RefundJpaEntity, Long | |
| JOIN ExamApplicationJpaEntity ea ON r.examApplicationId = ea.id | ||
| JOIN ExamJpaEntity e ON ea.examId = e.id | ||
| WHERE r.examApplicationId = :examApplicationId | ||
| AND p.paymentStatus = 'CANCELLED_DONE' | ||
| AND r.refundStatus = 'DONE' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| """) | ||
| Optional<RefundNotifyProjection> findRefundByExamApplicationId( | ||
| @Param("examApplicationId") Long examApplicationId); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,6 +64,9 @@ public enum ErrorCode { | |
| APPLICATION_SCHOOL_DUPLICATED(HttpStatus.BAD_REQUEST, "동일 일자의 같은 학교를 신청할 수 없습니다."), | ||
| EXAM_DUPLICATED(HttpStatus.BAD_REQUEST, "동일한 시험을 신청할 수 없습니다."), | ||
| WRONG_APPLICATION_ID_TYPE(HttpStatus.BAD_REQUEST, "신청 ID 타입이 올바르지 않습니다."), | ||
| PRICE_LOAD_FAILURE(HttpStatus.CONFLICT, "신청 가격 정보를 가져오는데 실패했습니다."), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Reconsider HTTP status code for PRICE_LOAD_FAILURE. Using HTTP 409 (Conflict) for price loading failure seems semantically incorrect. Consider using HTTP 500 (Internal Server Error) or HTTP 503 (Service Unavailable) instead, as this represents a system/service failure rather than a resource conflict. - PRICE_LOAD_FAILURE(HttpStatus.CONFLICT, "신청 가격 정보를 가져오는데 실패했습니다."),
+ PRICE_LOAD_FAILURE(HttpStatus.INTERNAL_SERVER_ERROR, "신청 가격 정보를 가져오는데 실패했습니다."),🤖 Prompt for AI Agents |
||
| APPLICATION_CLOSED(HttpStatus.BAD_REQUEST, "신청이 마감되었습니다."), | ||
|
|
||
| // 프로필 관련 에러 | ||
| PROFILE_ALREADY_EXISTS(HttpStatus.CONFLICT, "프로필이 이미 존재합니다."), | ||
| PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND, "프로필을 찾을 수 없습니다."), | ||
|
|
@@ -149,6 +152,8 @@ public enum ErrorCode { | |
|
|
||
| //LUA 관련 | ||
| LUA_SCRIPT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "LUA 스크립트 실행 중 오류가 발생했습니다."); | ||
|
|
||
|
|
||
| private final HttpStatus status; | ||
| private final String message; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's good to see the addition of
validator.examNotFull(examIds)to prevent applications for full exams. This enhances the application process by preventing users from applying to exams that have reached their capacity.