Skip to content

Commit cd7df2c

Browse files
committed
feat: 회원별 환급쿠폰 영수증 제출 횟수 통계 조회 기능 추가
1 parent bf44879 commit cd7df2c

7 files changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.appcenter.marketplace.domain.member_payback.dto.res;
2+
3+
import com.querydsl.core.types.dsl.*;
4+
5+
import com.querydsl.core.types.ConstructorExpression;
6+
import javax.annotation.processing.Generated;
7+
8+
/**
9+
* com.appcenter.marketplace.domain.member_payback.dto.res.QTopMemberReceiptRes is a Querydsl Projection type for TopMemberReceiptRes
10+
*/
11+
@Generated("com.querydsl.codegen.DefaultProjectionSerializer")
12+
public class QTopMemberReceiptRes extends ConstructorExpression<TopMemberReceiptRes> {
13+
14+
private static final long serialVersionUID = 1923847561L;
15+
16+
public QTopMemberReceiptRes(com.querydsl.core.types.Expression<Long> memberId, com.querydsl.core.types.Expression<Long> receiptCount) {
17+
super(TopMemberReceiptRes.class, new Class<?>[]{long.class, long.class}, memberId, receiptCount);
18+
}
19+
20+
}

src/main/java/com/appcenter/marketplace/domain/member_payback/controller/MemberPaybackAdminController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.appcenter.marketplace.domain.member_payback.dto.res.CouponPaybackStatsRes;
77
import com.appcenter.marketplace.domain.member_payback.dto.res.RecentMemberPaybackStatsRes;
88
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMarketPaybackRes;
9+
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMemberReceiptRes;
910
import com.appcenter.marketplace.domain.member_payback.service.MemberPaybackAdminService;
1011

1112
import java.util.List;
@@ -105,4 +106,17 @@ public ResponseEntity<CommonResponse<List<TopMarketPaybackRes>>> getTopMarketsBy
105106
.ok(CommonResponse.from(STATS_FOUND.getMessage(),
106107
memberPaybackAdminService.getTopMarketsByCompletedPaybackCount()));
107108
}
109+
110+
@Operation(summary = "영수증 제출 횟수 회원 Top 10 조회",
111+
description = "관리자가 영수증을 가장 많이 제출한 회원 Top 10을 조회합니다. <br>" +
112+
"period 파라미터로 기간 필터 적용 가능합니다. <br>" +
113+
"DAY(하루), WEEK(일주일), MONTH(한달) / 미입력 시 전체 기간")
114+
@GetMapping("/stats/top-members/receipt")
115+
public ResponseEntity<CommonResponse<List<TopMemberReceiptRes>>> getTopMembersByReceiptCount(
116+
@Parameter(description = "기간 필터 (DAY | WEEK | MONTH), 미입력 시 전체")
117+
@RequestParam(required = false) String period) {
118+
return ResponseEntity
119+
.ok(CommonResponse.from(STATS_FOUND.getMessage(),
120+
memberPaybackAdminService.getTopMembersByReceiptCount(period)));
121+
}
108122
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.appcenter.marketplace.domain.member_payback.dto.res;
2+
3+
import com.querydsl.core.annotations.QueryProjection;
4+
import lombok.Getter;
5+
6+
@Getter
7+
public class TopMemberReceiptRes {
8+
private final Long memberId;
9+
private final Long receiptCount;
10+
11+
@QueryProjection
12+
public TopMemberReceiptRes(Long memberId, Long receiptCount) {
13+
this.memberId = memberId;
14+
this.receiptCount = receiptCount;
15+
}
16+
}

src/main/java/com/appcenter/marketplace/domain/member_payback/repository/MemberPaybackRepositoryCustom.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.appcenter.marketplace.domain.member_payback.dto.res.ReceiptRes;
77

88
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMarketPaybackRes;
9+
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMemberReceiptRes;
910

1011
import java.time.LocalDateTime;
1112
import java.util.List;
@@ -24,4 +25,5 @@ public interface MemberPaybackRepositoryCustom {
2425
long countByMemberCreatedAtBetween(LocalDateTime startDateTime, LocalDateTime endDateTime);
2526
List<TopMarketPaybackRes> findTopMarketsByPaybackCount(int limit);
2627
List<TopMarketPaybackRes> findTopMarketsByCompletedPaybackCount(int limit);
28+
List<TopMemberReceiptRes> findTopMembersByReceiptCount(int limit, LocalDateTime start, LocalDateTime end);
2729
}

src/main/java/com/appcenter/marketplace/domain/member_payback/repository/MemberPaybackRepositoryCustomImpl.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
import com.appcenter.marketplace.domain.member_payback.dto.res.QAdminReceiptRes;
99
import com.appcenter.marketplace.domain.member_payback.dto.res.QReceiptRes;
1010
import com.appcenter.marketplace.domain.member_payback.dto.res.QTopMarketPaybackRes;
11+
import com.appcenter.marketplace.domain.member_payback.dto.res.QTopMemberReceiptRes;
1112
import com.appcenter.marketplace.domain.member_payback.dto.res.ReceiptRes;
1213
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMarketPaybackRes;
14+
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMemberReceiptRes;
1315
import com.querydsl.core.BooleanBuilder;
1416
import com.querydsl.core.types.dsl.Expressions;
1517
import com.querydsl.jpa.impl.JPAQueryFactory;
@@ -230,6 +232,28 @@ public List<TopMarketPaybackRes> findTopMarketsByPaybackCount(int limit) {
230232
.fetch();
231233
}
232234

235+
// 영수증 제출 수 기준 회원 Top N 조회 (기간 필터)
236+
@Override
237+
public List<TopMemberReceiptRes> findTopMembersByReceiptCount(int limit, LocalDateTime start, LocalDateTime end) {
238+
BooleanBuilder where = new BooleanBuilder();
239+
where.and(memberPayback.receipt.isNotNull());
240+
if (start != null && end != null) {
241+
where.and(memberPayback.modifiedAt.between(start, end));
242+
}
243+
244+
return jpaQueryFactory
245+
.select(new QTopMemberReceiptRes(
246+
member.id,
247+
memberPayback.count()))
248+
.from(memberPayback)
249+
.innerJoin(memberPayback.member, member)
250+
.where(where)
251+
.groupBy(member.id)
252+
.orderBy(memberPayback.count().desc())
253+
.limit(limit)
254+
.fetch();
255+
}
256+
233257
// 환급 완료 수 기준 매장 Top N 조회
234258
@Override
235259
public List<TopMarketPaybackRes> findTopMarketsByCompletedPaybackCount(int limit) {

src/main/java/com/appcenter/marketplace/domain/member_payback/service/MemberPaybackAdminService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.appcenter.marketplace.domain.member_payback.dto.res.CouponPaybackStatsRes;
77
import com.appcenter.marketplace.domain.member_payback.dto.res.RecentMemberPaybackStatsRes;
88
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMarketPaybackRes;
9+
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMemberReceiptRes;
910

1011
import java.util.List;
1112

@@ -25,4 +26,6 @@ public interface MemberPaybackAdminService {
2526

2627
List<TopMarketPaybackRes> getTopMarketsByCompletedPaybackCount();
2728

29+
List<TopMemberReceiptRes> getTopMembersByReceiptCount(String period);
30+
2831
}

src/main/java/com/appcenter/marketplace/domain/member_payback/service/impl/MemberPaybackAdminServiceImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.appcenter.marketplace.domain.member_payback.dto.res.CouponPaybackStatsRes;
1010
import com.appcenter.marketplace.domain.member_payback.dto.res.RecentMemberPaybackStatsRes;
1111
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMarketPaybackRes;
12+
import com.appcenter.marketplace.domain.member_payback.dto.res.TopMemberReceiptRes;
1213
import com.appcenter.marketplace.domain.member_payback.repository.MemberPaybackRepository;
1314
import com.appcenter.marketplace.domain.member_payback.service.MemberPaybackAdminService;
1415
import com.appcenter.marketplace.global.config.MetricsConfig;
@@ -119,6 +120,26 @@ public List<TopMarketPaybackRes> getTopMarketsByCompletedPaybackCount() {
119120
return memberPaybackRepository.findTopMarketsByCompletedPaybackCount(10);
120121
}
121122

123+
@Override
124+
public List<TopMemberReceiptRes> getTopMembersByReceiptCount(String period) {
125+
LocalDateTime start = null;
126+
LocalDateTime end = null;
127+
128+
if (period != null) {
129+
LocalDateTime now = LocalDateTime.now();
130+
end = now;
131+
start = switch (period.toUpperCase()) {
132+
case "DAY" -> now.minusDays(1);
133+
case "WEEK" -> now.minusWeeks(1);
134+
case "MONTH" -> now.minusMonths(1);
135+
default -> null;
136+
};
137+
if (start == null) end = null; // 잘못된 값이면 전체 조회
138+
}
139+
140+
return memberPaybackRepository.findTopMembersByReceiptCount(10, start, end);
141+
}
142+
122143
private MemberPayback findMemberPaybackById(Long couponId) {
123144
return memberPaybackRepository.findById(couponId)
124145
.orElseThrow(() -> new CustomException(COUPON_NOT_EXIST));

0 commit comments

Comments
 (0)