Skip to content
Merged
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
Expand Up @@ -183,30 +183,58 @@ public List<MapResponseDTO.StoreMapResponseV2DTO> getStoresV2(MapRequestDTO.View
final List<Store> stores = storeRepository.findAllWithinViewport(wkt);
final List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId, java.time.LocalDate.now());

// 모든 매장 ID 수집
List<Long> storeIds = stores.stream().map(Store::getId).toList();

// 빈 화면(매장 없음) 방어 코드
if (storeIds.isEmpty()) {
return java.util.Collections.emptyList();
}

// 사용자가 가진 Paper ID 수집 (쿼리에 파라미터로 넘기기 위해 위치를 위로 올림!)
List<Long> userPaperIds = userPapers.stream()
.map(up -> up.getPaper().getId())
.toList();

// 일괄 조회 1: 모든 매장의 PaperContent (내 혜택 기준 매장당 최대 2개)
List<PaperContent> allContents;
if (userPaperIds.isEmpty()) {
// 방어 코드: 사용자가 가진 혜택이 없다면 IN () 에러 방지를 위해 쿼리 실행 없이 빈 리스트 할당
allContents = java.util.Collections.emptyList();
} else {
allContents = paperContentRepository.findLatestValidByStoreIdInNativeMax2(
storeIds,
ActivationStatus.ACTIVE.name(),
OptionType.SERVICE.name(),
OptionType.DISCOUNT.name(),
CriterionType.PRICE.name(),
CriterionType.HEADCOUNT.name(),
userPaperIds // ⭐️ 새로 추가된 파라미터 전달!
);
}

// 일괄 조회 2: 모든 매장의 Paper와 Admin 정보 (Fetch Join)
List<Paper> allPapers = paperRepository.findLatestPapersByStoreIds(storeIds);

// 매장별 Paper 매핑 (매장당 최신 1개)
java.util.Map<Long, Paper> paperByStore = allPapers.stream()
.collect(java.util.stream.Collectors.toMap(
p -> p.getStore().getId(),
p -> p,
(existing, replacement) -> existing // 이미 키가 있으면 기존 값(최신) 유지
));

// 매장별로 PaperContent 그룹화
java.util.Map<Long, List<PaperContent>> contentsByStore = allContents.stream()
.collect(java.util.stream.Collectors.groupingBy(
pc -> pc.getPaper().getStore().getId()
));

return stores.stream().map(s -> {
final boolean hasPartner = (s.getPartner() != null);

// 사용자의 제휴권으로 이 매장에서 받을 수 있는 혜택 수집 (최대 2개)
List<PaperContent> benefits = new java.util.ArrayList<>();
for (UserPaper userPaper : userPapers) {
if (benefits.size() >= 2) break;

Paper paper = userPaper.getPaper();
if (paper.getStore() != null && paper.getStore().getId().equals(s.getId())) {
PaperContent content = paperContentRepository.findLatestValidByStoreIdNative(
s.getId(),
ActivationStatus.ACTIVE.name(),
OptionType.SERVICE.name(),
OptionType.DISCOUNT.name(),
CriterionType.PRICE.name(),
CriterionType.HEADCOUNT.name()
).orElse(null);

if (content != null) {
benefits.add(content);
}
}
}
// ⭐️ DB에서 이미 '내 혜택 중 상위 2개'만 가져왔으므로 filter와 limit이 필요 없음! 꺼내기만 하면 끝.
List<PaperContent> benefits = contentsByStore.getOrDefault(s.getId(), java.util.Collections.emptyList());

// 혜택 텍스트 생성
String partner1 = null;
Expand All @@ -228,15 +256,13 @@ public List<MapResponseDTO.StoreMapResponseV2DTO> getStoresV2(MapRequestDTO.View
benefit2 = generateBenefitText(content2);
}

// admin 정보
final Long adminId = paperRepository.findTopPaperByStoreId(s.getId())
.map(p -> p.getAdmin() != null ? p.getAdmin().getId() : null)
.orElse(null);

Paper paper = paperByStore.get(s.getId());
Long adminId = null;
String adminName = null;
if (adminId != null) {
final Admin admin = adminRepository.findById(adminId).orElse(null);
adminName = (admin != null ? admin.getName() : null);
if (paper != null && paper.getAdmin() != null) {
adminId = paper.getAdmin().getId();
String name = paper.getAdmin().getName();
adminName = (name != null) ? name : ""; // Null이면 빈 문자열로 덮어쓰기!
}

// S3 presigned URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ Optional<PaperContent> findLatestValidByStoreIdNative(
@Param("headcount") String headcount // CriterionType.HEADCOUNT.name()
);

@Query(value = """
WITH ranked_content AS (
SELECT pc.*,
ROW_NUMBER() OVER (
PARTITION BY p.store_id
ORDER BY
CASE pc.option_type
WHEN :service THEN 0 ELSE 1 END,
CASE pc.criterion_type
WHEN :price THEN 0
WHEN :headcount THEN 1
ELSE 2 END,
pc.updated_at DESC,
pc.id DESC
) AS rn
FROM paper_content pc
JOIN paper p ON p.id = pc.paper_id
WHERE p.store_id IN :storeIds
AND p.id IN :userPaperIds -- 대장님이 추가하신 핵심 조건!
AND p.is_activated = :active
AND CURRENT_DATE BETWEEN p.partnership_period_start AND p.partnership_period_end
AND (
(pc.option_type = :service AND
((pc.criterion_type = :price AND pc.cost IS NOT NULL)
OR (pc.criterion_type = :headcount AND pc.cost IS NOT NULL AND pc.people IS NOT NULL)))
OR (pc.option_type = :discount AND pc.discount IS NOT NULL)
)
)
SELECT * FROM ranked_content WHERE rn <= 2
""", nativeQuery = true)
List<PaperContent> findLatestValidByStoreIdInNativeMax2(
@Param("storeIds") List<Long> storeIds,
@Param("active") String active,
@Param("service") String service,
@Param("discount") String discount,
@Param("price") String price,
@Param("headcount") String headcount,
@Param("userPaperIds") List<Long> userPaperIds // 수정된 부분: 이름과 타입 변경
);

Optional<PaperContent> findTopByPaperIdOrderByIdDesc(Long paperId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,18 @@ List<Paper> findActivePapersByAdminIds(@Param("adminIds") List<Long> adminIds,
@Param("status") ActivationStatus status);

List<Paper> findByStoreIdAndAdminIdAndIsActivated(Long storeId, Long adminId, ActivationStatus isActivated);

// PaperRepository.java에 추가
@Query("""
SELECT p
FROM Paper p
LEFT JOIN FETCH p.admin a
WHERE p.store.id IN :storeIds
AND p.isActivated = com.assu.server.domain.common.enums.ActivationStatus.ACTIVE
AND p.partnershipPeriodStart <= CURRENT_DATE
AND p.partnershipPeriodEnd >= CURRENT_DATE
ORDER BY p.id DESC
""")
List<Paper> findLatestPapersByStoreIds(@Param("storeIds") List<Long> storeIds);

}