Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package life.mosu.mosuserver.application.admin;

import java.time.LocalDate;
import life.mosu.mosuserver.domain.examapplication.repository.ExamApplicationJpaRepository;
import life.mosu.mosuserver.domain.refund.repository.RefundFailureLogJpaRepository;
import life.mosu.mosuserver.domain.user.entity.UserRole;
import life.mosu.mosuserver.domain.user.repository.UserJpaRepository;
import life.mosu.mosuserver.domain.virtualaccount.DepositStatus;
import life.mosu.mosuserver.domain.virtualaccount.VirtualAccountLogJpaRepository;
import life.mosu.mosuserver.presentation.admin.dto.DashBoardResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -13,13 +16,21 @@
public class AdminDashboardService {

private final ExamApplicationJpaRepository examApplicationJpaRepository;
private final VirtualAccountLogJpaRepository virtualAccountLogJpaRepository;
private final UserJpaRepository userJpaRepository;
private final RefundFailureLogJpaRepository refundFailureLogJpaRepository;

// 대시보드 정보 조회
public DashBoardResponse getAll() {

Long applicationCounts = examApplicationJpaRepository.countAll();
LocalDate startDate = LocalDate.of(2025, 8, 20);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

하드코딩된 날짜 LocalDate.of(2025, 8, 20)가 사용되었습니다. 이러한 '매직 값'은 코드의 의도를 파악하기 어렵게 만들고, 향후 날짜 변경이 필요할 때 여러 곳을 수정해야 하는 등 유지보수를 어렵게 할 수 있습니다. 이 값을 의도를 명확히 나타내는 이름의 상수로 추출하는 것이 좋습니다. 예를 들어, 클래스 상단에 private static final LocalDate APPLICATION_COUNT_START_DATE = LocalDate.of(2025, 8, 20);와 같이 상수를 선언하고 이를 참조하도록 변경하는 것을 권장합니다.

Long paymentCounts = examApplicationJpaRepository.countAllSince(startDate);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the repository methods exist and handle edge cases.

Please ensure that:

  1. The countAllSince(LocalDate) method exists in ExamApplicationJpaRepository
  2. The countByDepositStatus(DepositStatus) method exists in VirtualAccountLogJpaRepository
  3. Both methods handle null inputs gracefully

Also applies to: 29-30


🏁 Script executed:

#!/bin/bash
# Description: Verify the repository methods exist and check their implementations

# Search for countAllSince method in ExamApplicationJpaRepository
echo "=== Checking ExamApplicationJpaRepository.countAllSince method ==="
rg -n "countAllSince" --type=java

# Search for countByDepositStatus method in VirtualAccountLogJpaRepository  
echo -e "\n=== Checking VirtualAccountLogJpaRepository.countByDepositStatus method ==="
rg -n "countByDepositStatus" --type=java

# Check DepositStatus enum values
echo -e "\n=== Checking DepositStatus enum ==="
rg -n "enum DepositStatus|DONE" --type=java -A 5 -B 2

Length of output: 36166


Add null check for startDate
In AdminDashboardService.getDashboardData(), insert

Objects.requireNonNull(startDate, "startDate must not be null");

before calling

examApplicationJpaRepository.countAllSince(startDate);

Methods exist as expected.

🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/admin/AdminDashboardService.java
around line 27, the call to
examApplicationJpaRepository.countAllSince(startDate) lacks a null check for
startDate; insert a null check using Objects.requireNonNull(startDate,
"startDate must not be null") immediately before that call, and add an import
for java.util.Objects if it isn't already present.


Long virtualAccountCounts = virtualAccountLogJpaRepository.countByDepositStatus(
DepositStatus.DONE);

Long applicationCounts = paymentCounts + virtualAccountCounts;

Long refundAbortedCounts = refundFailureLogJpaRepository.count();
Long userCounts = userJpaRepository.countByUserRoleNot(UserRole.ROLE_ADMIN);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package life.mosu.mosuserver.domain.examapplication.repository;

import io.lettuce.core.dynamic.annotation.Param;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import life.mosu.mosuserver.domain.examapplication.entity.ExamApplicationJpaEntity;
Expand Down Expand Up @@ -55,8 +56,8 @@ Optional<ExamApplicationInfoProjection> findExamApplicationInfoById(
@Query("""
SELECT new life.mosu.mosuserver.domain.examapplication.projection.ExamTicketInfoProjection(
et.s3Key,
u.name,
u.birth,
pr.userName,
pr.birth,
ea.examNumber,
e.schoolName,
e.examDate
Expand All @@ -66,6 +67,7 @@ Optional<ExamApplicationInfoProjection> findExamApplicationInfoById(
LEFT JOIN ApplicationJpaEntity a on a.id = ea.applicationId
LEFT JOIN ExamTicketImageJpaEntity et on et.applicationId = a.id
LEFT JOIN UserJpaEntity u on a.userId = u.id
LEFT JOIN ProfileJpaEntity pr on pr.userId = u.id
LEFT JOIN PaymentJpaEntity p on p.examApplicationId = ea.id
WHERE ea.id = :examApplicationId
AND u.id = :userId
Expand Down Expand Up @@ -209,8 +211,9 @@ SELECT COUNT(ea)
JOIN PaymentJpaEntity p ON ea.id = p.examApplicationId
WHERE p.paymentStatus = 'DONE'
AND p.deleted = false
AND p.createdAt >= :startDate
""")
long countAll();
long countAllSince(@Param("startDate") LocalDate startDate);

@Query("""
select exists (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public interface VirtualAccountLogJpaRepository extends

Optional<VirtualAccountLogJpaEntity> findByOrderId(String orderId);

long countByDepositStatus(DepositStatus depositStatus);
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ private JPAQuery<Tuple> baseQuery() {
examApplication.id,
payment.paymentKey,
examApplication.examNumber,
user.name,
user.gender,
user.birth,
profile.userName,
profile.gender,
profile.birth,
profile.phoneNumber,
application.parentPhoneNumber,
profile.recommenderPhoneNumber,
Expand Down Expand Up @@ -132,7 +132,7 @@ private JPAQuery<Tuple> baseQuery() {
private Predicate buildNameCondition(String name) {
return (name == null || name.isBlank())
? null
: user.name.contains(name);
: profile.userName.contains(name);
}

private Predicate buildPhoneCondition(String phone) {
Expand Down Expand Up @@ -163,8 +163,8 @@ private ApplicationListResponse mapToResponse(Tuple tuple, Set<Subject> subjects

ExamTicketResponse examTicketResponse = ExamTicketResponse.of(
url,
tuple.get(user.name),
tuple.get(user.birth),
tuple.get(profile.userName),
tuple.get(profile.birth),
tuple.get(examApplication.examNumber),
subjectNames,
tuple.get(exam.schoolName)
Expand All @@ -174,20 +174,21 @@ private ApplicationListResponse mapToResponse(Tuple tuple, Set<Subject> subjects
Education education = tuple.get(profile.education);
Grade grade = tuple.get(profile.grade);
PaymentMethod paymentMethod = tuple.get(payment.paymentMethod);
Boolean isLunchChecked = tuple.get(examApplication.isLunchChecked);

return new ApplicationListResponse(
tuple.get(payment.paymentKey),
tuple.get(examApplication.examNumber),
tuple.get(user.name),
tuple.get(profile.userName),
gender != null ? gender.getGenderName() : null,
tuple.get(user.birth),
tuple.get(profile.birth),
tuple.get(profile.phoneNumber),
tuple.get(application.parentPhoneNumber),
education != null ? education.getEducationName() : null,
tuple.get(profile.schoolInfo.schoolName),
grade != null ? grade.getGradeName() : null,
tuple.get(examApplication.isLunchChecked),
tuple.get(exam.lunchName),
isLunchChecked,
Boolean.TRUE.equals(isLunchChecked) ? tuple.get(exam.lunchName) : null,
subjectNames,
tuple.get(exam.schoolName),
tuple.get(exam.examDate),
Expand All @@ -208,23 +209,24 @@ private ApplicationExcelDto mapToExcel(Tuple tuple, Set<Subject> subjects) {
Education education = tuple.get(profile.education);
Grade grade = tuple.get(profile.grade);
PaymentMethod paymentMethod = tuple.get(payment.paymentMethod);
Boolean isLunchChecked = tuple.get(examApplication.isLunchChecked);

String appliedAt = tuple.get(application.createdAt)
.format(EXCEL_DT_FORMATTER);

return new ApplicationExcelDto(
tuple.get(payment.paymentKey),
tuple.get(examApplication.examNumber),
tuple.get(user.name),
tuple.get(profile.userName),
gender != null ? gender.getGenderName() : null,
tuple.get(user.birth),
tuple.get(profile.birth),
tuple.get(profile.phoneNumber),
tuple.get(application.parentPhoneNumber),
tuple.get(profile.recommenderPhoneNumber),
education != null ? education.getEducationName() : null,
tuple.get(profile.schoolInfo.schoolName),
grade != null ? grade.getGradeName() : null,
tuple.get(exam.lunchName),
Boolean.TRUE.equals(isLunchChecked) ? tuple.get(exam.lunchName) : null,
subjectNames,
tuple.get(exam.schoolName),
tuple.get(exam.examDate),
Expand Down
Loading