diff --git a/src/main/java/life/mosu/mosuserver/application/application/ApplicationContext.java b/src/main/java/life/mosu/mosuserver/application/application/ApplicationContext.java index 2816e3f1..e6389046 100644 --- a/src/main/java/life/mosu/mosuserver/application/application/ApplicationContext.java +++ b/src/main/java/life/mosu/mosuserver/application/application/ApplicationContext.java @@ -7,110 +7,115 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; + import life.mosu.mosuserver.domain.application.ApplicationJpaEntity; import life.mosu.mosuserver.domain.exam.ExamJpaEntity; import life.mosu.mosuserver.domain.examapplication.ExamApplicationJpaEntity; import life.mosu.mosuserver.domain.examapplication.ExamSubjectJpaEntity; import life.mosu.mosuserver.domain.payment.PaymentJpaEntity; +import life.mosu.mosuserver.domain.refund.RefundJpaEntity; import life.mosu.mosuserver.presentation.application.dto.ApplicationResponse; import life.mosu.mosuserver.presentation.application.dto.ExamApplicationResponse; +import life.mosu.mosuserver.presentation.examapplication.dto.ExamApplicationWithStatus; public record ApplicationContext( List applications, - List examApplications, + List examApplications, Map examMap, Map> subjectMap, - Map paymentMap + Map paymentMap, + Map refundMap ) { - public ApplicationContext(List applications, - List examApplications) { - this(applications, examApplications, Map.of(), Map.of(), Map.of()); + public ApplicationContext( + List applications, + List examApplications + ) { + this(applications, examApplications, Map.of(), Map.of(), Map.of(), Map.of()); } public ApplicationContext fetchExams(Function, List> fetcher) { - List examIds = this.examApplications.stream().map(ExamApplicationJpaEntity::getExamId) - .distinct().toList(); - Map newExamMap = fetcher.apply(examIds).stream() - .collect(Collectors.toMap(ExamJpaEntity::getId, Function.identity())); - return new ApplicationContext(this.applications, this.examApplications, newExamMap, - this.subjectMap, this.paymentMap); + Map newExamMap = fetcher.apply( + examApplications.stream() + .map(e -> e.examApplication().getExamId()) + .distinct() + .toList() + ).stream().collect(Collectors.toMap(ExamJpaEntity::getId, Function.identity())); + + return new ApplicationContext(applications, examApplications, newExamMap, subjectMap, paymentMap, refundMap); } - public ApplicationContext fetchSubjects( - Function, List> fetcher) { - List examApplicationIds = this.examApplications.stream() - .map(ExamApplicationJpaEntity::getId).toList(); - Map> newSubjectMap = fetcher.apply(examApplicationIds) - .stream() - .collect(Collectors.groupingBy(ExamSubjectJpaEntity::getExamApplicationId)); - return new ApplicationContext(this.applications, this.examApplications, this.examMap, - newSubjectMap, this.paymentMap); + public ApplicationContext fetchSubjects(Function, List> fetcher) { + Map> newSubjectMap = fetcher.apply( + examApplications.stream() + .map(e -> e.examApplication().getId()) + .toList() + ).stream().collect(Collectors.groupingBy(ExamSubjectJpaEntity::getExamApplicationId)); + + return new ApplicationContext(applications, examApplications, examMap, newSubjectMap, paymentMap, refundMap); } public ApplicationContext fetchPayments(Function, List> fetcher) { - List examApplicationIds = this.examApplications.stream() - .map(ExamApplicationJpaEntity::getId).toList(); - Map newPaymentMap = fetcher.apply(examApplicationIds).stream() - .collect(Collectors.toMap( - PaymentJpaEntity::getExamApplicationId, - Function.identity())); - - return new ApplicationContext(this.applications, this.examApplications, this.examMap, - this.subjectMap, newPaymentMap); + Map newPaymentMap = fetcher.apply( + examApplications.stream() + .map(e -> e.examApplication().getId()) + .toList() + ).stream().collect(Collectors.toMap(PaymentJpaEntity::getExamApplicationId, Function.identity())); + + return new ApplicationContext(applications, examApplications, examMap, subjectMap, newPaymentMap, refundMap); + } + + public ApplicationContext fetchRefunds(Function, List> fetcher) { + Map newRefundMap = fetcher.apply( + examApplications.stream() + .map(e -> e.examApplication().getId()) + .toList() + ).stream().collect(Collectors.toMap(RefundJpaEntity::getExamApplicationId, Function.identity())); + + return new ApplicationContext(applications, examApplications, examMap, subjectMap, paymentMap, newRefundMap); } public List assemble() { - Map> groupedExamResponses = this.examApplications.stream() + Map> grouped = examApplications.stream() .map(this::createExamApplicationResponse) .filter(Objects::nonNull) .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); - return this.applications.stream() + return applications.stream() .map(app -> ApplicationResponse.of(app.getId(), - groupedExamResponses.getOrDefault(app.getId(), List.of()))) + grouped.getOrDefault(app.getId(), List.of()))) .toList(); } - private Map.Entry createExamApplicationResponse( - ExamApplicationJpaEntity examApp) throws RuntimeException { - - ExamJpaEntity exam = this.examMap.get(examApp.getExamId()); - if (exam == null) { - return null; - } + private Map.Entry createExamApplicationResponse(ExamApplicationWithStatus item) { + ExamApplicationJpaEntity examApp = item.examApplication(); + ExamJpaEntity exam = examMap.get(examApp.getExamId()); + if (exam == null) return null; - List subjectEntities = this.subjectMap.getOrDefault(examApp.getId(), - List.of()); - Set subjects = subjectEntities.stream().map(es -> es.getSubject().getSubjectName()) - .collect(Collectors.toSet()); + Set subjects = subjectMap.getOrDefault(examApp.getId(), List.of()).stream() + .map(s -> s.getSubject().getSubjectName()).collect(Collectors.toSet()); - PaymentJpaEntity payment = this.paymentMap.getOrDefault(examApp.getId(), null); - String paymentStatus = Optional.ofNullable(payment) - .map(p -> p.getPaymentStatus().name()) - .orElse(null); + PaymentJpaEntity payment = paymentMap.get(examApp.getId()); + RefundJpaEntity refund = refundMap.get(examApp.getId()); Integer totalAmount = Optional.ofNullable(payment) .map(p -> p.getPaymentAmount().getTotalAmount()) .orElse(0); - - String lunchName; - if (examApp.getIsLunchChecked()) { - lunchName = exam.getLunchName(); - } else { - lunchName = null; - } + String lunchName = examApp.getIsLunchChecked() ? exam.getLunchName() : null; + String status = item.status(); ExamApplicationResponse response = ExamApplicationResponse.of( examApp.getId(), examApp.getCreatedAt(), - paymentStatus, totalAmount, + status, + totalAmount, exam.getSchoolName(), exam.getExamDate(), subjects, lunchName ); + return Map.entry(examApp.getApplicationId(), response); } } \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/application/application/processor/GetApplicationsStepProcessor.java b/src/main/java/life/mosu/mosuserver/application/application/processor/GetApplicationsStepProcessor.java index a9f0b7ac..98b5183b 100644 --- a/src/main/java/life/mosu/mosuserver/application/application/processor/GetApplicationsStepProcessor.java +++ b/src/main/java/life/mosu/mosuserver/application/application/processor/GetApplicationsStepProcessor.java @@ -9,8 +9,10 @@ import life.mosu.mosuserver.domain.examapplication.ExamApplicationJpaRepository; import life.mosu.mosuserver.domain.examapplication.ExamSubjectJpaRepository; import life.mosu.mosuserver.domain.payment.PaymentJpaRepository; +import life.mosu.mosuserver.domain.refund.RefundJpaRepository; import life.mosu.mosuserver.global.processor.StepProcessor; import life.mosu.mosuserver.presentation.application.dto.ApplicationResponse; +import life.mosu.mosuserver.presentation.examapplication.dto.ExamApplicationWithStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -26,6 +28,7 @@ public class GetApplicationsStepProcessor implements private final ExamApplicationJpaRepository examApplicationJpaRepository; private final ExamJpaRepository examJpaRepository; private final PaymentJpaRepository paymentJpaRepository; + private final RefundJpaRepository refundJpaRepository; @Override public List process(Long userId) { @@ -37,13 +40,14 @@ public List process(Long userId) { } List applicationIds = applications.stream().map(ApplicationJpaEntity::getId).toList(); - List examApplications = examApplicationJpaRepository.findByApplicationIdIn( + List examApplications = examApplicationJpaRepository.findByApplicationIdIn( applicationIds); return new ApplicationContext(applications, examApplications) .fetchExams(examJpaRepository::findByIdIn) .fetchSubjects(examSubjectJpaRepository::findByExamApplicationIdIn) .fetchPayments(paymentJpaRepository::findByExamApplicationIdIn) + .fetchRefunds(refundJpaRepository::findByExamApplicationIdIn) .assemble(); } diff --git a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaRepository.java b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaRepository.java index 2992f655..568399ec 100644 --- a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaRepository.java +++ b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaRepository.java @@ -7,6 +7,7 @@ import life.mosu.mosuserver.domain.examapplication.projection.ExamApplicationNotifyProjection; import life.mosu.mosuserver.domain.examapplication.projection.ExamInfoWithExamNumberProjection; import life.mosu.mosuserver.domain.examapplication.projection.ExamTicketInfoProjection; +import life.mosu.mosuserver.presentation.examapplication.dto.ExamApplicationWithStatus; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -71,7 +72,22 @@ Optional findExamTicketInfoProjectionById( boolean existsByApplicationId(Long applicationId); - List findByApplicationIdIn(List applicationIds); + @Query(""" + SELECT new life.mosu.mosuserver.presentation.examapplication.dto.ExamApplicationWithStatus( + ea, + CASE + WHEN r.refundStatus = 'DONE' THEN '환불완료' + ELSE '결제완료' + END + ) + FROM ExamApplicationJpaEntity ea + JOIN PaymentJpaEntity p ON p.examApplicationId = ea.id + LEFT JOIN RefundJpaEntity r ON r.examApplicationId = ea.id + WHERE p.paymentStatus = 'DONE' + AND (r IS NULL OR r.refundStatus = 'DONE') + AND ea.applicationId IN :applicationIds + """) + List findByApplicationIdIn(List applicationIds); @Query(""" diff --git a/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaRepository.java b/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaRepository.java index a10d64e3..5ca2b5ae 100644 --- a/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaRepository.java +++ b/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaRepository.java @@ -1,9 +1,10 @@ package life.mosu.mosuserver.domain.refund; -import io.lettuce.core.dynamic.annotation.Param; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface RefundJpaRepository extends JpaRepository { @@ -32,4 +33,11 @@ Optional findRefundByExamApplicationId( @Param("examApplicationId") Long examApplicationId); Optional findByTransactionKey(String transactionKey); + + @Query(""" + SELECT r + FROM RefundJpaEntity r + WHERE r.examApplicationId IN :examApplicationIds +""") + List findByExamApplicationIdIn(@Param("examApplicationIds") List examApplicationId); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationResponse.java b/src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationResponse.java index aa612c2c..aa2f741a 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationResponse.java @@ -6,7 +6,7 @@ public record ExamApplicationResponse( Long examApplicationId, String createdAt, - String paymentStatus, + String status, Integer totalAmount, String schoolName, LocalDate examDate, @@ -17,7 +17,7 @@ public record ExamApplicationResponse( public static ExamApplicationResponse of( Long examApplicationId, String createdAt, - String paymentStatus, + String status, Integer totalAmount, String schoolName, LocalDate examDate, @@ -27,7 +27,7 @@ public static ExamApplicationResponse of( return new ExamApplicationResponse( examApplicationId, createdAt, - paymentStatus, + status, totalAmount, schoolName, examDate, diff --git a/src/main/java/life/mosu/mosuserver/presentation/examapplication/dto/ExamApplicationWithStatus.java b/src/main/java/life/mosu/mosuserver/presentation/examapplication/dto/ExamApplicationWithStatus.java new file mode 100644 index 00000000..50db32f8 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/examapplication/dto/ExamApplicationWithStatus.java @@ -0,0 +1,8 @@ +package life.mosu.mosuserver.presentation.examapplication.dto; + +import life.mosu.mosuserver.domain.examapplication.ExamApplicationJpaEntity; + +public record ExamApplicationWithStatus( + ExamApplicationJpaEntity examApplication, + String status +) { }