-
Notifications
You must be signed in to change notification settings - Fork 2
MOSU-78 feat: 관리자 환불 내역 조회 기능 구현 #81
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 |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package life.mosu.mosuserver.domain.admin; | ||
|
|
||
| import life.mosu.mosuserver.presentation.admin.dto.RefundListResponse; | ||
| import org.springframework.data.domain.Page; | ||
| import org.springframework.data.domain.Pageable; | ||
|
|
||
| public interface RefundQueryRepository { | ||
|
|
||
| Page<RefundListResponse> searchAllRefunds(Pageable pageable); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||
| package life.mosu.mosuserver.domain.admin; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import static life.mosu.mosuserver.domain.base.BaseTimeEntity.formatDate; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import com.querydsl.core.Tuple; | ||||||||||||||||||||||
| import com.querydsl.jpa.impl.JPAQuery; | ||||||||||||||||||||||
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.application.QApplicationJpaEntity; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.applicationschool.QApplicationSchoolJpaEntity; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.payment.PaymentMethod; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.payment.QPaymentJpaEntity; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.profile.QProfileJpaEntity; | ||||||||||||||||||||||
| import life.mosu.mosuserver.domain.refund.QRefundJpaEntity; | ||||||||||||||||||||||
| import life.mosu.mosuserver.presentation.admin.dto.RefundListResponse; | ||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||
| import org.springframework.data.domain.Page; | ||||||||||||||||||||||
| import org.springframework.data.domain.PageImpl; | ||||||||||||||||||||||
| import org.springframework.data.domain.Pageable; | ||||||||||||||||||||||
| import org.springframework.stereotype.Repository; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @Repository | ||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||
| public class RefundQueryRepositoryImpl implements RefundQueryRepository { | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private final JPAQueryFactory queryFactory; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| QRefundJpaEntity refund = QRefundJpaEntity.refundJpaEntity; | ||||||||||||||||||||||
| QApplicationSchoolJpaEntity appSchool = QApplicationSchoolJpaEntity.applicationSchoolJpaEntity; | ||||||||||||||||||||||
| QApplicationJpaEntity application = QApplicationJpaEntity.applicationJpaEntity; | ||||||||||||||||||||||
| QProfileJpaEntity profile = QProfileJpaEntity.profileJpaEntity; | ||||||||||||||||||||||
| QPaymentJpaEntity payment = QPaymentJpaEntity.paymentJpaEntity; | ||||||||||||||||||||||
|
Comment on lines
+28
to
+32
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 Make QueryDSL entity references static final fields. QueryDSL entity references should be static final fields since they're constants and don't need to be instantiated per repository instance. - QRefundJpaEntity refund = QRefundJpaEntity.refundJpaEntity;
- QApplicationSchoolJpaEntity appSchool = QApplicationSchoolJpaEntity.applicationSchoolJpaEntity;
- QApplicationJpaEntity application = QApplicationJpaEntity.applicationJpaEntity;
- QProfileJpaEntity profile = QProfileJpaEntity.profileJpaEntity;
- QPaymentJpaEntity payment = QPaymentJpaEntity.paymentJpaEntity;
+ private static final QRefundJpaEntity refund = QRefundJpaEntity.refundJpaEntity;
+ private static final QApplicationSchoolJpaEntity appSchool = QApplicationSchoolJpaEntity.applicationSchoolJpaEntity;
+ private static final QApplicationJpaEntity application = QApplicationJpaEntity.applicationJpaEntity;
+ private static final QProfileJpaEntity profile = QProfileJpaEntity.profileJpaEntity;
+ private static final QPaymentJpaEntity payment = QPaymentJpaEntity.paymentJpaEntity;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @Override | ||||||||||||||||||||||
| public Page<RefundListResponse> searchAllRefunds(Pageable pageable) { | ||||||||||||||||||||||
| long total = baseQuery().fetch().size(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| List<RefundListResponse> content = baseQuery() | ||||||||||||||||||||||
| .offset(pageable.getOffset()) | ||||||||||||||||||||||
| .limit(pageable.getPageSize()) | ||||||||||||||||||||||
| .fetch() | ||||||||||||||||||||||
| .stream() | ||||||||||||||||||||||
| .map(this::mapToResponse) | ||||||||||||||||||||||
| .toList(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return new PageImpl<>(content, pageable, total); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private JPAQuery<Tuple> baseQuery() { | ||||||||||||||||||||||
| return queryFactory | ||||||||||||||||||||||
| .select( | ||||||||||||||||||||||
| refund.id, | ||||||||||||||||||||||
| appSchool.examinationNumber, | ||||||||||||||||||||||
| profile.userName, | ||||||||||||||||||||||
| profile.phoneNumber, | ||||||||||||||||||||||
| refund.createdAt, | ||||||||||||||||||||||
| refund.agreedAt, | ||||||||||||||||||||||
| payment.paymentMethod, | ||||||||||||||||||||||
| refund.reason | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| .from(refund) | ||||||||||||||||||||||
| .leftJoin(appSchool).on(refund.applicationSchoolId.eq(appSchool.id)) | ||||||||||||||||||||||
| .leftJoin(application).on(appSchool.applicationId.eq(application.id)) | ||||||||||||||||||||||
| .leftJoin(profile).on(profile.userId.eq(application.userId)) | ||||||||||||||||||||||
| .leftJoin(payment).on(payment.applicationSchoolId.eq(appSchool.id)); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| private RefundListResponse mapToResponse(Tuple tuple) { | ||||||||||||||||||||||
| PaymentMethod paymentMethod = tuple.get(payment.paymentMethod); | ||||||||||||||||||||||
| return new RefundListResponse( | ||||||||||||||||||||||
| tuple.get(refund.id), | ||||||||||||||||||||||
| tuple.get(appSchool.examinationNumber), | ||||||||||||||||||||||
| tuple.get(profile.userName), | ||||||||||||||||||||||
| tuple.get(profile.phoneNumber), | ||||||||||||||||||||||
| formatDate(tuple.get(refund.createdAt)), | ||||||||||||||||||||||
| formatDate(tuple.get(refund.agreedAt)), | ||||||||||||||||||||||
| paymentMethod != null ? paymentMethod.getName() : "N/A", | ||||||||||||||||||||||
| tuple.get(refund.reason) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,13 @@ | ||
| package life.mosu.mosuserver.domain.inquiry; | ||
|
|
||
| import lombok.Getter; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @Getter | ||
| @RequiredArgsConstructor | ||
| public enum InquiryStatus { | ||
| PENDING, | ||
| COMPLETED, | ||
| PENDING("미응답"), | ||
| COMPLETED("완료"); | ||
|
|
||
| private final String statusName; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,13 +12,15 @@ | |||||
| import life.mosu.mosuserver.presentation.admin.dto.ApplicationExcelDto; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.ApplicationFilter; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.ApplicationListResponse; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.RefundListResponse; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.SchoolLunchResponse; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.StudentExcelDto; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.StudentFilter; | ||||||
| import life.mosu.mosuserver.presentation.admin.dto.StudentListResponse; | ||||||
| import lombok.RequiredArgsConstructor; | ||||||
| import org.springframework.data.domain.Page; | ||||||
| import org.springframework.data.domain.Pageable; | ||||||
| import org.springframework.data.web.PageableDefault; | ||||||
| import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.http.ResponseEntity; | ||||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||||
|
|
@@ -96,4 +98,14 @@ public void downloadApplicationInfo(HttpServletResponse response) throws IOExcep | |||||
| excelFile.write(response.getOutputStream()); | ||||||
| } | ||||||
|
|
||||||
| @GetMapping("/refunds") | ||||||
| // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") | ||||||
|
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
Suggested change
|
||||||
| public ResponseEntity<ApiResponseWrapper<Page<RefundListResponse>>> getRefundCounts( | ||||||
| @PageableDefault(size = 15) Pageable pageable | ||||||
| ) { | ||||||
| Page<RefundListResponse> result = adminService.getRefunds(pageable); | ||||||
| return ResponseEntity.ok( | ||||||
| ApiResponseWrapper.success(HttpStatus.OK, "환불 신청 수 조회 성공", result)); | ||||||
| } | ||||||
|
|
||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package life.mosu.mosuserver.presentation.admin.dto; | ||
|
|
||
| public record RefundListResponse( | ||
| Long refundId, | ||
| String examNumber, | ||
| String name, | ||
| String phone, | ||
| String requestedAt, | ||
| String completedAt, | ||
| String paymentMethod, | ||
| String reason | ||
|
|
||
| ) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |||||||||||||||||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||
| import life.mosu.mosuserver.domain.inquiry.InquiryJpaEntity; | ||||||||||||||||||||
| import life.mosu.mosuserver.domain.inquiry.InquiryStatus; | ||||||||||||||||||||
| import life.mosu.mosuserver.domain.inquiryAnswer.InquiryAnswerJpaEntity; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| @Schema(description = "1:1 문의 응답 DTO") | ||||||||||||||||||||
|
|
@@ -16,9 +15,9 @@ public record InquiryDetailResponse( | |||||||||||||||||||
| String content, | ||||||||||||||||||||
| @Schema(description = "작성자", example = "홍길동") | ||||||||||||||||||||
| String author, | ||||||||||||||||||||
| @Schema(description = "문의 상태 (WAITING: 답변 대기, COMPLETED: 답변 완료)", example = "WAITING") | ||||||||||||||||||||
| InquiryStatus status, | ||||||||||||||||||||
| @Schema(description = "문의 등록일", example = "2025-07-10T10:00:00") | ||||||||||||||||||||
| @Schema(description = "문의 상태 (미응답, 완료)", example = "완료") | ||||||||||||||||||||
| String status, | ||||||||||||||||||||
| @Schema(description = "문의 등록일", example = "2025-07-10") | ||||||||||||||||||||
| String createdAt, | ||||||||||||||||||||
|
|
||||||||||||||||||||
| List<AttachmentDetailResponse> attachments, | ||||||||||||||||||||
|
|
@@ -36,7 +35,7 @@ public static InquiryDetailResponse of( | |||||||||||||||||||
| inquiry.getTitle(), | ||||||||||||||||||||
| inquiry.getContent(), | ||||||||||||||||||||
| inquiry.getAuthor(), | ||||||||||||||||||||
| inquiry.getStatus(), | ||||||||||||||||||||
| inquiry.getStatus().getStatusName(), | ||||||||||||||||||||
| inquiry.getCreatedAt(), | ||||||||||||||||||||
|
Comment on lines
+38
to
39
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 Potential date formatting inconsistency. The factory method uses Consider using the centralized date formatting: - inquiry.getCreatedAt(),
+ formatDate(inquiry.getCreatedAt()),You'll need to add the static import: +import static life.mosu.mosuserver.domain.base.BaseTimeEntity.formatDate;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| attachments, | ||||||||||||||||||||
| answer | ||||||||||||||||||||
|
|
||||||||||||||||||||
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.
These QueryDSL Q-type fields are effectively constants. It's a good practice to declare them as
private static finalto make it clear they are stateless, shared, and immutable.