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 @@ -61,6 +61,7 @@ public static class StoreMapResponseDTO {
private Integer people;
private Long cost;
private String category;
private String note;
private Long discountRate;
private boolean hasPartner;
private Double latitude;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ else if (content.getOptionType() == OptionType.SERVICE) {
.adminName(admin != null ? admin.getName() : null)
.adminId(adminId)
.name(s.getName())
.note(content.getNote())
.address(s.getAddress() != null ? s.getAddress() : s.getDetailAddress())
.rate(s.getRate())
.criterionType(content != null ? content.getCriterionType() : null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
import java.util.List;

public interface StudentAdminRepository extends JpaRepository<StudentAdmin, Long> {

// 총 누적 가입자 수
@Query("""
select count(sa)
from StudentAdmin sa
where sa.admin.id = :adminId
""")
Long countAllByAdminId(@Param("adminId") Long adminId);


// 기간별 가입자 수
@Query("""
select count(sa)
from StudentAdmin sa
Expand All @@ -31,12 +33,14 @@ Long countByAdminIdBetween(@Param("adminId") Long adminId,
@Param("from") LocalDateTime from,
@Param("to") LocalDateTime to);

// 이번 달 신규 가입자 수
default Long countThisMonthByAdminId(Long adminId) {
LocalDateTime from = YearMonth.now().atDay(1).atStartOfDay();
LocalDateTime to = LocalDateTime.now();
return countByAdminIdBetween(adminId, from, to);
}
// 오늘 하루, '나를 admin으로 제휴 맺은 partner'의 제휴를 사용한 '고유 사용자 수'

// 오늘 제휴 사용 고유 사용자 수
@Query(value = """
SELECT COUNT(DISTINCT pu.student_id)
FROM partnership_usage pu
Expand All @@ -48,25 +52,44 @@ SELECT COUNT(DISTINCT pu.student_id)
""", nativeQuery = true)
Long countTodayUsersByAdmin(@Param("adminId") Long adminId);

// 누적: admin이 제휴한 모든 store의 사용 건수 (0건 포함), 사용량 내림차순
@Query(value = """
SELECT
p.id AS paperId,
p.store_id AS storeId,
s.name AS storeName,
CAST(COUNT(pu.id) AS UNSIGNED) AS usageCount
FROM paper p
JOIN store s ON s.id = p.store_id
JOIN paper_content pc ON pc.paper_id = p.id
JOIN partnership_usage pu ON pu.paper_id = pc.id
WHERE p.admin_id = :adminId
GROUP BY p.id, p.store_id, s.name
HAVING usageCount > 0
ORDER BY usageCount DESC, p.id ASC
""", nativeQuery = true)
List<StoreUsageWithPaper> findUsageByStoreWithPaper(@Param("adminId") Long adminId);

// 0건 포함 조회 (대시보드에서 모든 제휴 업체를 보여줘야 하는 경우)
@Query(value = """
SELECT
p.id AS paperId,
p.store_id AS storeId,
s.name AS storeName,
CAST(COALESCE(COUNT(pu.id), 0) AS UNSIGNED) AS usageCount
FROM paper p
JOIN store s ON s.id = p.store_id
LEFT JOIN paper_content pc ON pc.paper_id = p.id
LEFT JOIN partnership_usage pu ON pu.paper_id = pc.id
WHERE p.admin_id = :adminId
GROUP BY p.store_id, s.name
ORDER BY usageCount DESC, storeId ASC
GROUP BY p.id, p.store_id, s.name
ORDER BY usageCount DESC, p.id ASC
""", nativeQuery = true)
List<StoreUsage> findUsageByStore(@Param("adminId") Long adminId);
List<StoreUsageWithPaper> findUsageByStoreIncludingZero(@Param("adminId") Long adminId);

interface StoreUsage {
interface StoreUsageWithPaper {
Long getPaperId(); // 🆕 추가: Paper ID
Long getStoreId();
String getStoreName();
Long getUsageCount();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.assu.server.domain.mapping.dto.StudentAdminResponseDTO;
import com.assu.server.domain.mapping.repository.StudentAdminRepository;
import com.assu.server.domain.partnership.entity.Paper;
import com.assu.server.domain.partnership.repository.PaperRepository;
import com.assu.server.domain.partnership.repository.PartnershipRepository;
import com.assu.server.domain.user.service.StudentService;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
Expand All @@ -15,76 +16,101 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
@RequiredArgsConstructor
public class StudentAdminServiceImpl implements StudentAdminService {
private final StudentAdminRepository studentAdminRepository;
private final AdminRepository adminRepository;
private final PartnershipRepository partnershipRepository;
private final PaperRepository paperRepository;

@Override
@Transactional
public StudentAdminResponseDTO.CountAdminAuthResponseDTO getCountAdminAuth(Long memberId) {

Admin admin = getAdminOrThrow(memberId);
Long total = studentAdminRepository.countAllByAdminId(memberId);
Admin admin = adminRepository.findById(memberId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
String adminName = admin.getName();

return StudentAdminConverter.countAdminAuthDTO(memberId, total, adminName);
return StudentAdminConverter.countAdminAuthDTO(memberId, total, admin.getName());
}

@Override
@Transactional
public StudentAdminResponseDTO.NewCountAdminResponseDTO getNewStudentCountAdmin(Long memberId) {

Admin admin = getAdminOrThrow(memberId);
Long total = studentAdminRepository.countThisMonthByAdminId(memberId);
Admin admin = adminRepository.findById(memberId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
String adminName = admin.getName();
return StudentAdminConverter.newCountAdminResponseDTO(memberId, total, adminName);

return StudentAdminConverter.newCountAdminResponseDTO(memberId, total, admin.getName());
}

@Override
@Transactional
public StudentAdminResponseDTO.CountUsagePersonResponseDTO getCountUsagePerson(Long memberId) {

Admin admin = getAdminOrThrow(memberId);
Long total = studentAdminRepository.countTodayUsersByAdmin(memberId);
Admin admin = adminRepository.findById(memberId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
String adminName =admin.getName();
return StudentAdminConverter.countUsagePersonDTO(memberId, total, adminName);

return StudentAdminConverter.countUsagePersonDTO(memberId, total, admin.getName());
}

@Override
@Transactional
public StudentAdminResponseDTO.CountUsageResponseDTO getCountUsage(Long memberId) {
Admin admin = adminRepository.findById(memberId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
String adminName =admin.getName();
List<StudentAdminRepository.StoreUsage> storeUsages = studentAdminRepository.findUsageByStore(memberId);
Admin admin = getAdminOrThrow(memberId);

List<StudentAdminRepository.StoreUsageWithPaper> storeUsages =
studentAdminRepository.findUsageByStoreWithPaper(memberId);

//예외 처리
if (storeUsages.isEmpty()) {
throw new DatabaseException(ErrorStatus.NO_USAGE_DATA);
}

// 첫 번째가 가장 사용량이 많은 업체 (ORDER BY usageCount DESC)
var top = storeUsages.get(0);
Paper paper = partnershipRepository.findFirstByAdmin_IdAndStore_IdOrderByIdAsc(memberId, top.getStoreId())

Paper paper = paperRepository.findById(top.getPaperId())
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE));
Long total = top.getUsageCount();

return StudentAdminConverter.countUsageResponseDTO(admin, paper, total);
return StudentAdminConverter.countUsageResponseDTO(admin, paper, top.getUsageCount());
}

@Override
@Transactional
public StudentAdminResponseDTO.CountUsageListResponseDTO getCountUsageList(Long memberId) {
Admin admin = getAdminOrThrow(memberId);

// 🔧 핵심 수정: Paper 정보를 포함한 조회 (N+1 해결)
List<StudentAdminRepository.StoreUsageWithPaper> storeUsages =
studentAdminRepository.findUsageByStoreWithPaper(memberId);

if (storeUsages.isEmpty()) {
// 빈 리스트 반환 (선택: 예외 처리도 가능)
return StudentAdminConverter.countUsageListResponseDTO(List.of());
}

List<Long> paperIds = storeUsages.stream()
.map(StudentAdminRepository.StoreUsageWithPaper::getPaperId)
.toList();

Map<Long, Paper> paperMap = paperRepository.findAllById(paperIds).stream()
.collect(Collectors.toMap(Paper::getId, paper -> paper));

Admin admin = adminRepository.findById(memberId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
List<StudentAdminRepository.StoreUsage> storeUsages = studentAdminRepository.findUsageByStore(memberId);
var items = storeUsages.stream().map(row -> {
Paper paper = partnershipRepository.findFirstByAdmin_IdAndStore_IdOrderByIdAsc(memberId, row.getStoreId())
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE));
Paper paper = paperMap.get(row.getPaperId());
if (paper == null) {
throw new DatabaseException(ErrorStatus.NO_PAPER_FOR_STORE);
}
return StudentAdminConverter.countUsageResponseDTO(admin, paper, row.getUsageCount());
}).toList();

return StudentAdminConverter.countUsageListResponseDTO(items);
}

}
// Admin 조회 중복 제거
private Admin getAdminOrThrow(Long adminId) {
return adminRepository.findById(adminId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public static List<PaperContent> toPaperContents(
}
return partnershipRequestDTO.getOptions().stream()
.map(optionDto -> PaperContent.builder()
.note(optionDto.getNote()) // 일단 노트까지 받아서 변환
.paper(paper) // 어떤 Paper에 속하는지 연결
.optionType(optionDto.getOptionType())
.criterionType(optionDto.getCriterionType())
Expand Down Expand Up @@ -102,7 +103,14 @@ public static List<PaperContentResponseDTO.storePaperContentResponse> toContentR
public static PaperContentResponseDTO.storePaperContentResponse toContentResponse(PaperContent content) {
List<String> goodsList = extractGoods(content);
Integer peopleValue = extractPeople(content);
String paperContentText = buildPaperContentText(content, goodsList, peopleValue);

String paperContentText;
if(content.getNote()!= null){
paperContentText = content.getNote();
}else{
paperContentText = buildPaperContentText(content, goodsList, peopleValue);
}


return PaperContentResponseDTO.storePaperContentResponse.builder()
.adminId(content.getPaper().getAdmin().getId())
Expand Down Expand Up @@ -204,6 +212,7 @@ public static List<PaperContent> toPaperContentsForManual(
.paper(paper)
.optionType(o.getOptionType())
.criterionType(o.getCriterionType())
.note(o.getNote())
.people(o.getPeople())
.cost(o.getCost())
.category(o.getCategory())
Expand Down Expand Up @@ -238,13 +247,19 @@ public static PartnershipResponseDTO.WritePartnershipResponseDTO writePartnershi
if (contents != null) {
for (int i = 0; i < contents.size(); i++) {
PaperContent pc = contents.get(i);

String note = null;
if(pc.getNote()!= null){
note = pc.getNote();
}
List<Goods> goods = (goodsBatches != null && goodsBatches.size() > i)
? goodsBatches.get(i) : List.of();
optionDTOS.add(
PartnershipResponseDTO.PartnershipOptionResponseDTO.builder()
.optionType(pc.getOptionType())
.criterionType(pc.getCriterionType())
.people(pc.getPeople())
.note(note)
.cost(pc.getCost())
.category(pc.getCategory())
.discountRate(pc.getDiscount())
Expand All @@ -253,6 +268,8 @@ public static PartnershipResponseDTO.WritePartnershipResponseDTO writePartnershi
);
}
}


return PartnershipResponseDTO.WritePartnershipResponseDTO.builder()
.partnershipId(paper.getId())
.partnershipPeriodStart(paper.getPartnershipPeriodStart())
Expand Down Expand Up @@ -319,6 +336,10 @@ public static PartnershipResponseDTO.GetPartnershipDetailResponseDTO getPartners
if (contents != null) {
for (int i = 0; i < contents.size(); i++) {
PaperContent pc = contents.get(i);
String note = null;
if(pc.getNote()!= null){
note = pc.getNote();
}
List<Goods> goods = (goodsBatches != null && goodsBatches.size() > i)
? goodsBatches.get(i) : List.of();
optionDTOS.add(
Expand All @@ -327,6 +348,7 @@ public static PartnershipResponseDTO.GetPartnershipDetailResponseDTO getPartners
.criterionType(pc.getCriterionType())
.people(pc.getPeople())
.cost(pc.getCost())
.note(note)
.category(pc.getCategory())
.discountRate(pc.getDiscount())
.goods(goodsResultDTO(goods))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static class PartnershipOptionRequestDTO {
private Long cost;
private String category;
private Long discountRate;
private String note;
private List<PartnershipGoodsRequestDTO> goods; // 서비스 제공 항목

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static class PartnershipOptionResponseDTO {
private CriterionType criterionType;
private Integer people;
private Long cost;
private String note;
private String category;
private Long discountRate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class PaperContent extends BaseEntity {
@Enumerated(EnumType.STRING)
private OptionType optionType;

private String note;

private Integer people;

private Long cost;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,6 @@ public PaperResponseDTO.partnershipContent getStorePaperContent(Long storeId, Me
student.getDepartment(),
student.getMajor());

// // 한번 더 거르기 위해서
// List<Admin> filteredAdmin = adminList.stream()
// .filter(admin -> {
// String name = admin.getName();
// Major major = admin.getMajor();
// return name.contains(student.getUniversity())
// || name.contains(student.getDepartment())
// || major.equals(student.getMajor());
// }).toList();


// 추출한 admin, store와 일치하는 paperId 를 추출합니다.
List<Paper> paperList = adminList.stream()
.flatMap(admin ->
Expand Down
Loading