Skip to content

Commit c6ab5db

Browse files
authored
Merge pull request #222 from ASSU-org/develop
[Deply] 대시보드 qa 반영 및 note 필드 추가
2 parents 1981bee + 68adf73 commit c6ab5db

File tree

16 files changed

+158
-114
lines changed

16 files changed

+158
-114
lines changed

src/main/java/com/assu/server/domain/map/dto/MapResponseDTO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static class StoreMapResponseDTO {
6161
private Integer people;
6262
private Long cost;
6363
private String category;
64+
private String note;
6465
private Long discountRate;
6566
private boolean hasPartner;
6667
private Double latitude;

src/main/java/com/assu/server/domain/map/service/MapServiceImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ else if (content.getOptionType() == OptionType.SERVICE) {
223223
.adminName(admin != null ? admin.getName() : null)
224224
.adminId(adminId)
225225
.name(s.getName())
226+
.note(content.getNote())
226227
.address(s.getAddress() != null ? s.getAddress() : s.getDetailAddress())
227228
.rate(s.getRate())
228229
.criterionType(content != null ? content.getCriterionType() : null)

src/main/java/com/assu/server/domain/mapping/repository/StudentAdminRepository.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@
1212
import java.util.List;
1313

1414
public interface StudentAdminRepository extends JpaRepository<StudentAdmin, Long> {
15+
16+
// 총 누적 가입자 수
1517
@Query("""
1618
select count(sa)
1719
from StudentAdmin sa
1820
where sa.admin.id = :adminId
1921
""")
2022
Long countAllByAdminId(@Param("adminId") Long adminId);
2123

22-
24+
// 기간별 가입자 수
2325
@Query("""
2426
select count(sa)
2527
from StudentAdmin sa
@@ -31,12 +33,14 @@ Long countByAdminIdBetween(@Param("adminId") Long adminId,
3133
@Param("from") LocalDateTime from,
3234
@Param("to") LocalDateTime to);
3335

36+
// 이번 달 신규 가입자 수
3437
default Long countThisMonthByAdminId(Long adminId) {
3538
LocalDateTime from = YearMonth.now().atDay(1).atStartOfDay();
3639
LocalDateTime to = LocalDateTime.now();
3740
return countByAdminIdBetween(adminId, from, to);
3841
}
39-
// 오늘 하루, '나를 admin으로 제휴 맺은 partner'의 제휴를 사용한 '고유 사용자 수'
42+
43+
// 오늘 제휴 사용 고유 사용자 수
4044
@Query(value = """
4145
SELECT COUNT(DISTINCT pu.student_id)
4246
FROM partnership_usage pu
@@ -48,25 +52,44 @@ SELECT COUNT(DISTINCT pu.student_id)
4852
""", nativeQuery = true)
4953
Long countTodayUsersByAdmin(@Param("adminId") Long adminId);
5054

51-
// 누적: admin이 제휴한 모든 store의 사용 건수 (0건 포함), 사용량 내림차순
5255
@Query(value = """
5356
SELECT
57+
p.id AS paperId,
5458
p.store_id AS storeId,
5559
s.name AS storeName,
60+
CAST(COUNT(pu.id) AS UNSIGNED) AS usageCount
61+
FROM paper p
62+
JOIN store s ON s.id = p.store_id
63+
JOIN paper_content pc ON pc.paper_id = p.id
64+
JOIN partnership_usage pu ON pu.paper_id = pc.id
65+
WHERE p.admin_id = :adminId
66+
GROUP BY p.id, p.store_id, s.name
67+
HAVING usageCount > 0
68+
ORDER BY usageCount DESC, p.id ASC
69+
""", nativeQuery = true)
70+
List<StoreUsageWithPaper> findUsageByStoreWithPaper(@Param("adminId") Long adminId);
71+
72+
// 0건 포함 조회 (대시보드에서 모든 제휴 업체를 보여줘야 하는 경우)
73+
@Query(value = """
74+
SELECT
75+
p.id AS paperId,
76+
p.store_id AS storeId,
77+
s.name AS storeName,
5678
CAST(COALESCE(COUNT(pu.id), 0) AS UNSIGNED) AS usageCount
5779
FROM paper p
5880
JOIN store s ON s.id = p.store_id
5981
LEFT JOIN paper_content pc ON pc.paper_id = p.id
6082
LEFT JOIN partnership_usage pu ON pu.paper_id = pc.id
6183
WHERE p.admin_id = :adminId
62-
GROUP BY p.store_id, s.name
63-
ORDER BY usageCount DESC, storeId ASC
84+
GROUP BY p.id, p.store_id, s.name
85+
ORDER BY usageCount DESC, p.id ASC
6486
""", nativeQuery = true)
65-
List<StoreUsage> findUsageByStore(@Param("adminId") Long adminId);
87+
List<StoreUsageWithPaper> findUsageByStoreIncludingZero(@Param("adminId") Long adminId);
6688

67-
interface StoreUsage {
89+
interface StoreUsageWithPaper {
90+
Long getPaperId(); // 🆕 추가: Paper ID
6891
Long getStoreId();
6992
String getStoreName();
7093
Long getUsageCount();
7194
}
72-
}
95+
}

src/main/java/com/assu/server/domain/mapping/service/StudentAdminServiceImpl.java

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.assu.server.domain.mapping.dto.StudentAdminResponseDTO;
77
import com.assu.server.domain.mapping.repository.StudentAdminRepository;
88
import com.assu.server.domain.partnership.entity.Paper;
9+
import com.assu.server.domain.partnership.repository.PaperRepository;
910
import com.assu.server.domain.partnership.repository.PartnershipRepository;
1011
import com.assu.server.domain.user.service.StudentService;
1112
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
@@ -15,76 +16,101 @@
1516
import org.springframework.stereotype.Service;
1617

1718
import java.util.List;
19+
import java.util.Map;
20+
import java.util.stream.Collectors;
1821

1922
@Service
2023
@Transactional
2124
@RequiredArgsConstructor
2225
public class StudentAdminServiceImpl implements StudentAdminService {
2326
private final StudentAdminRepository studentAdminRepository;
2427
private final AdminRepository adminRepository;
25-
private final PartnershipRepository partnershipRepository;
28+
private final PaperRepository paperRepository;
2629

2730
@Override
2831
@Transactional
2932
public StudentAdminResponseDTO.CountAdminAuthResponseDTO getCountAdminAuth(Long memberId) {
30-
33+
Admin admin = getAdminOrThrow(memberId);
3134
Long total = studentAdminRepository.countAllByAdminId(memberId);
32-
Admin admin = adminRepository.findById(memberId)
33-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
34-
String adminName = admin.getName();
3535

36-
return StudentAdminConverter.countAdminAuthDTO(memberId, total, adminName);
36+
return StudentAdminConverter.countAdminAuthDTO(memberId, total, admin.getName());
3737
}
38+
3839
@Override
3940
@Transactional
4041
public StudentAdminResponseDTO.NewCountAdminResponseDTO getNewStudentCountAdmin(Long memberId) {
41-
42+
Admin admin = getAdminOrThrow(memberId);
4243
Long total = studentAdminRepository.countThisMonthByAdminId(memberId);
43-
Admin admin = adminRepository.findById(memberId)
44-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
45-
String adminName = admin.getName();
46-
return StudentAdminConverter.newCountAdminResponseDTO(memberId, total, adminName);
44+
45+
return StudentAdminConverter.newCountAdminResponseDTO(memberId, total, admin.getName());
4746
}
4847

4948
@Override
5049
@Transactional
5150
public StudentAdminResponseDTO.CountUsagePersonResponseDTO getCountUsagePerson(Long memberId) {
52-
51+
Admin admin = getAdminOrThrow(memberId);
5352
Long total = studentAdminRepository.countTodayUsersByAdmin(memberId);
54-
Admin admin = adminRepository.findById(memberId)
55-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
56-
String adminName =admin.getName();
57-
return StudentAdminConverter.countUsagePersonDTO(memberId, total, adminName);
53+
54+
return StudentAdminConverter.countUsagePersonDTO(memberId, total, admin.getName());
5855
}
5956

6057
@Override
6158
@Transactional
6259
public StudentAdminResponseDTO.CountUsageResponseDTO getCountUsage(Long memberId) {
63-
Admin admin = adminRepository.findById(memberId)
64-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
65-
String adminName =admin.getName();
66-
List<StudentAdminRepository.StoreUsage> storeUsages = studentAdminRepository.findUsageByStore(memberId);
60+
Admin admin = getAdminOrThrow(memberId);
61+
62+
List<StudentAdminRepository.StoreUsageWithPaper> storeUsages =
63+
studentAdminRepository.findUsageByStoreWithPaper(memberId);
64+
65+
//예외 처리
66+
if (storeUsages.isEmpty()) {
67+
throw new DatabaseException(ErrorStatus.NO_USAGE_DATA);
68+
}
69+
70+
// 첫 번째가 가장 사용량이 많은 업체 (ORDER BY usageCount DESC)
6771
var top = storeUsages.get(0);
68-
Paper paper = partnershipRepository.findFirstByAdmin_IdAndStore_IdOrderByIdAsc(memberId, top.getStoreId())
72+
73+
Paper paper = paperRepository.findById(top.getPaperId())
6974
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE));
70-
Long total = top.getUsageCount();
7175

72-
return StudentAdminConverter.countUsageResponseDTO(admin, paper, total);
76+
return StudentAdminConverter.countUsageResponseDTO(admin, paper, top.getUsageCount());
7377
}
7478

7579
@Override
7680
@Transactional
7781
public StudentAdminResponseDTO.CountUsageListResponseDTO getCountUsageList(Long memberId) {
82+
Admin admin = getAdminOrThrow(memberId);
83+
84+
// 🔧 핵심 수정: Paper 정보를 포함한 조회 (N+1 해결)
85+
List<StudentAdminRepository.StoreUsageWithPaper> storeUsages =
86+
studentAdminRepository.findUsageByStoreWithPaper(memberId);
87+
88+
if (storeUsages.isEmpty()) {
89+
// 빈 리스트 반환 (선택: 예외 처리도 가능)
90+
return StudentAdminConverter.countUsageListResponseDTO(List.of());
91+
}
92+
93+
List<Long> paperIds = storeUsages.stream()
94+
.map(StudentAdminRepository.StoreUsageWithPaper::getPaperId)
95+
.toList();
96+
97+
Map<Long, Paper> paperMap = paperRepository.findAllById(paperIds).stream()
98+
.collect(Collectors.toMap(Paper::getId, paper -> paper));
7899

79-
Admin admin = adminRepository.findById(memberId)
80-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
81-
List<StudentAdminRepository.StoreUsage> storeUsages = studentAdminRepository.findUsageByStore(memberId);
82100
var items = storeUsages.stream().map(row -> {
83-
Paper paper = partnershipRepository.findFirstByAdmin_IdAndStore_IdOrderByIdAsc(memberId, row.getStoreId())
84-
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE));
101+
Paper paper = paperMap.get(row.getPaperId());
102+
if (paper == null) {
103+
throw new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE);
104+
}
85105
return StudentAdminConverter.countUsageResponseDTO(admin, paper, row.getUsageCount());
86106
}).toList();
107+
87108
return StudentAdminConverter.countUsageListResponseDTO(items);
88109
}
89110

90-
}
111+
// Admin 조회 중복 제거
112+
private Admin getAdminOrThrow(Long adminId) {
113+
return adminRepository.findById(adminId)
114+
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
115+
}
116+
}

src/main/java/com/assu/server/domain/partnership/converter/PartnershipConverter.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public static List<PaperContent> toPaperContents(
5656
}
5757
return partnershipRequestDTO.getOptions().stream()
5858
.map(optionDto -> PaperContent.builder()
59+
.note(optionDto.getNote()) // 일단 노트까지 받아서 변환
5960
.paper(paper) // 어떤 Paper에 속하는지 연결
6061
.optionType(optionDto.getOptionType())
6162
.criterionType(optionDto.getCriterionType())
@@ -102,7 +103,14 @@ public static List<PaperContentResponseDTO.storePaperContentResponse> toContentR
102103
public static PaperContentResponseDTO.storePaperContentResponse toContentResponse(PaperContent content) {
103104
List<String> goodsList = extractGoods(content);
104105
Integer peopleValue = extractPeople(content);
105-
String paperContentText = buildPaperContentText(content, goodsList, peopleValue);
106+
107+
String paperContentText;
108+
if(content.getNote()!= null){
109+
paperContentText = content.getNote();
110+
}else{
111+
paperContentText = buildPaperContentText(content, goodsList, peopleValue);
112+
}
113+
106114

107115
return PaperContentResponseDTO.storePaperContentResponse.builder()
108116
.adminId(content.getPaper().getAdmin().getId())
@@ -204,6 +212,7 @@ public static List<PaperContent> toPaperContentsForManual(
204212
.paper(paper)
205213
.optionType(o.getOptionType())
206214
.criterionType(o.getCriterionType())
215+
.note(o.getNote())
207216
.people(o.getPeople())
208217
.cost(o.getCost())
209218
.category(o.getCategory())
@@ -238,13 +247,19 @@ public static PartnershipResponseDTO.WritePartnershipResponseDTO writePartnershi
238247
if (contents != null) {
239248
for (int i = 0; i < contents.size(); i++) {
240249
PaperContent pc = contents.get(i);
250+
251+
String note = null;
252+
if(pc.getNote()!= null){
253+
note = pc.getNote();
254+
}
241255
List<Goods> goods = (goodsBatches != null && goodsBatches.size() > i)
242256
? goodsBatches.get(i) : List.of();
243257
optionDTOS.add(
244258
PartnershipResponseDTO.PartnershipOptionResponseDTO.builder()
245259
.optionType(pc.getOptionType())
246260
.criterionType(pc.getCriterionType())
247261
.people(pc.getPeople())
262+
.note(note)
248263
.cost(pc.getCost())
249264
.category(pc.getCategory())
250265
.discountRate(pc.getDiscount())
@@ -253,6 +268,8 @@ public static PartnershipResponseDTO.WritePartnershipResponseDTO writePartnershi
253268
);
254269
}
255270
}
271+
272+
256273
return PartnershipResponseDTO.WritePartnershipResponseDTO.builder()
257274
.partnershipId(paper.getId())
258275
.partnershipPeriodStart(paper.getPartnershipPeriodStart())
@@ -319,6 +336,10 @@ public static PartnershipResponseDTO.GetPartnershipDetailResponseDTO getPartners
319336
if (contents != null) {
320337
for (int i = 0; i < contents.size(); i++) {
321338
PaperContent pc = contents.get(i);
339+
String note = null;
340+
if(pc.getNote()!= null){
341+
note = pc.getNote();
342+
}
322343
List<Goods> goods = (goodsBatches != null && goodsBatches.size() > i)
323344
? goodsBatches.get(i) : List.of();
324345
optionDTOS.add(
@@ -327,6 +348,7 @@ public static PartnershipResponseDTO.GetPartnershipDetailResponseDTO getPartners
327348
.criterionType(pc.getCriterionType())
328349
.people(pc.getPeople())
329350
.cost(pc.getCost())
351+
.note(note)
330352
.category(pc.getCategory())
331353
.discountRate(pc.getDiscount())
332354
.goods(goodsResultDTO(goods))

src/main/java/com/assu/server/domain/partnership/dto/PartnershipRequestDTO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public static class PartnershipOptionRequestDTO {
4040
private Long cost;
4141
private String category;
4242
private Long discountRate;
43+
private String note;
4344
private List<PartnershipGoodsRequestDTO> goods; // 서비스 제공 항목
4445

4546
}

src/main/java/com/assu/server/domain/partnership/dto/PartnershipResponseDTO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public static class PartnershipOptionResponseDTO {
4040
private CriterionType criterionType;
4141
private Integer people;
4242
private Long cost;
43+
private String note;
4344
private String category;
4445
private Long discountRate;
4546

src/main/java/com/assu/server/domain/partnership/entity/PaperContent.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public class PaperContent extends BaseEntity {
3333
@Enumerated(EnumType.STRING)
3434
private OptionType optionType;
3535

36+
private String note;
37+
3638
private Integer people;
3739

3840
private Long cost;

src/main/java/com/assu/server/domain/partnership/service/PaperQueryServiceImpl.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ public PaperResponseDTO.partnershipContent getStorePaperContent(Long storeId, Me
5050
student.getDepartment(),
5151
student.getMajor());
5252

53-
// // 한번 더 거르기 위해서
54-
// List<Admin> filteredAdmin = adminList.stream()
55-
// .filter(admin -> {
56-
// String name = admin.getName();
57-
// Major major = admin.getMajor();
58-
// return name.contains(student.getUniversity())
59-
// || name.contains(student.getDepartment())
60-
// || major.equals(student.getMajor());
61-
// }).toList();
62-
63-
6453
// 추출한 admin, store와 일치하는 paperId 를 추출합니다.
6554
List<Paper> paperList = adminList.stream()
6655
.flatMap(admin ->

0 commit comments

Comments
 (0)