diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponController.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponController.java index fc7d8771..bd521656 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponController.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponController.java @@ -1,6 +1,7 @@ package intbyte4.learnsmate.issue_coupon.controller; import intbyte4.learnsmate.issue_coupon.domain.dto.IssuedCouponFilterDTO; +import intbyte4.learnsmate.issue_coupon.domain.pagination.IssueCouponPageResponse; import intbyte4.learnsmate.issue_coupon.domain.vo.request.IssueCouponFilterRequestVO; import intbyte4.learnsmate.issue_coupon.domain.vo.response.AllIssuedCouponResponseVO; import intbyte4.learnsmate.issue_coupon.service.IssueCouponFacade; @@ -86,4 +87,40 @@ public ResponseEntity> findIssuedCouponsByFilter return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); } } + + @Operation(summary = "발급된 쿠폰 전체 조회 - offset pagination") + @GetMapping("/all-issued-coupons2") + public ResponseEntity> getAllIssuedCoupons( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "15") int size) { + + IssueCouponPageResponse response; + + response = issueCouponFacade.findAllIssuedCoupons(page, size); + + return ResponseEntity.ok(response); + } + + @Operation(summary = "발급된 쿠폰 필터링 조회 - offset pagination") + @PostMapping("/filters2") + public ResponseEntity> findIssuedCouponsByFilters( + @RequestBody IssueCouponFilterRequestVO request, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "15") int size) { + log.info("발급 쿠폰 필터링 요청 수신"); + try { + IssuedCouponFilterDTO dto = issueCouponMapper.fromVOToFilterResponseDTO(request); + log.info(dto.toString()); + + IssueCouponPageResponse response + = issueCouponFacade.filterIssuedCoupon(page, size, dto); + + log.info(response.toString()); + + return ResponseEntity.ok(response); + } catch (Exception e) { + log.error("예상치 못한 오류 발생", e); + return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); + } + } } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponExcelController.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponExcelController.java new file mode 100644 index 00000000..dea5e514 --- /dev/null +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/controller/IssueCouponExcelController.java @@ -0,0 +1,45 @@ +package intbyte4.learnsmate.issue_coupon.controller; + +import intbyte4.learnsmate.issue_coupon.domain.dto.IssuedCouponFilterDTO; +import intbyte4.learnsmate.issue_coupon.service.IssueCouponExcelService; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/issue-coupon/excel") +@Slf4j +@RequiredArgsConstructor +public class IssueCouponExcelController { + + private final IssueCouponExcelService issueCouponExcelService; + + @PostMapping("/download") + @Operation(summary = "발급쿠폰 엑셀 다운로드", description = "발급쿠폰 목록을 엑셀 파일로 다운로드합니다.") + public void downloadStudentExcel(HttpServletResponse response, @RequestBody(required = false) IssuedCouponFilterDTO filterDTO) { + try { + log.info("Excel download request received"); + + if (filterDTO != null) { + log.info("Filter DTO parsed: {}", filterDTO); + } + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=\"coupon_data.xlsx\""); + + issueCouponExcelService.exportCouponToExcel(response.getOutputStream(), filterDTO); + + log.info("Excel file successfully written to response output stream."); + } catch (Exception e) { + log.error("Error during excel download:", e); + throw new RuntimeException("Excel download failed", e); + } + } + + + +} diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/dto/IssuedCouponFilterDTO.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/dto/IssuedCouponFilterDTO.java index 6fca1f77..170e6d44 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/dto/IssuedCouponFilterDTO.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/dto/IssuedCouponFilterDTO.java @@ -4,6 +4,7 @@ import lombok.*; import java.time.LocalDateTime; +import java.util.List; @AllArgsConstructor @NoArgsConstructor @@ -30,4 +31,6 @@ public class IssuedCouponFilterDTO { private LocalDateTime endCouponUseDate; private LocalDateTime startCouponIssueDate; private LocalDateTime endCouponIssueDate; + + private List selectedColumns; } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/pagination/IssueCouponPageResponse.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/pagination/IssueCouponPageResponse.java new file mode 100644 index 00000000..74baa916 --- /dev/null +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/domain/pagination/IssueCouponPageResponse.java @@ -0,0 +1,16 @@ +package intbyte4.learnsmate.issue_coupon.domain.pagination; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class IssueCouponPageResponse { + private List content; + private long totalElements; + private int totalPages; + private int currentPage; + private int size; +} diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepository.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepository.java index 798bb2c4..9bc6b459 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepository.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepository.java @@ -3,9 +3,14 @@ import intbyte4.learnsmate.issue_coupon.domain.IssueCoupon; import intbyte4.learnsmate.issue_coupon.domain.vo.request.IssueCouponFilterRequestVO; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import java.util.List; public interface CustomIssueCouponRepository { List findIssuedCouponsByFilters(IssueCouponFilterRequestVO request); + + // 발급 쿠폰 offset 페이지네이션 필터링 + Page getFilteredIssuedCoupons(IssueCouponFilterRequestVO request, PageRequest pageable); } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepositoryImpl.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepositoryImpl.java index 203e8c56..61266abc 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepositoryImpl.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/CustomIssueCouponRepositoryImpl.java @@ -10,6 +10,9 @@ import intbyte4.learnsmate.coupon.domain.entity.QCouponEntity; import intbyte4.learnsmate.member.domain.entity.QMember; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Repository; import java.util.List; @@ -57,6 +60,47 @@ public List findIssuedCouponsByFilters(IssueCouponFilterRequestVO r .fetch(); } + // 이슈 쿠폰 필터링 offset 페이지네이션 + @Override + public Page getFilteredIssuedCoupons(IssueCouponFilterRequestVO request, PageRequest pageable) { + QIssueCoupon issueCoupon = QIssueCoupon.issueCoupon; + QMember member = QMember.member; + QCouponEntity couponEntity = QCouponEntity.couponEntity; + + BooleanBuilder builder = new BooleanBuilder() + .and(likeCouponName(request)) + .and(likeCouponContents(request)) + .and(eqCouponCategoryName(request)) + .and(eqStudentCode(request)) + .and(eqStudentName(request)) + .and(eqCouponUseStatus(request)) + .and(betweenDiscountRate(request)) + .and(betweenCouponStartDate(request)) + .and(betweenCouponEndDate(request)) + .and(betweenCouponUseDate(request)) + .and(betweenCouponIssueDate(request)); + + List results = queryFactory + .selectFrom(issueCoupon) + .join(issueCoupon.coupon, couponEntity).fetchJoin() + .join(issueCoupon.student, member).fetchJoin() + .where(builder) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + // 전체 카운트 조회 + Long total = queryFactory + .select(issueCoupon.count()) + .from(issueCoupon) + .join(issueCoupon.coupon, couponEntity) + .join(issueCoupon.student, member) + .where(builder) + .fetchOne(); + + return new PageImpl<>(results, pageable, total != null ? total : 0L); + } + private BooleanExpression likeCouponName(IssueCouponFilterRequestVO request) { if (request.getCouponName() == null || request.getCouponName().isEmpty()) { diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/IssueCouponRepository.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/IssueCouponRepository.java index a722638f..a762325b 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/IssueCouponRepository.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/repository/IssueCouponRepository.java @@ -1,6 +1,9 @@ package intbyte4.learnsmate.issue_coupon.repository; import intbyte4.learnsmate.issue_coupon.domain.IssueCoupon; +import intbyte4.learnsmate.issue_coupon.domain.dto.IssuedCouponFilterDTO; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -33,4 +36,6 @@ public interface IssueCouponRepository extends JpaRepository, @Query("SELECT c FROM issueCoupon c WHERE c.student.memberCode = :studentCode AND c.couponIssueDate <= CURRENT_TIMESTAMP AND c.couponUseStatus = true AND c.couponUseDate IS NOT NULL") List findUsedCouponsByStudentCode(@Param("studentCode") Long studentCode); + // 발급 쿠폰 offset 페이지네이션 전체 (JPQL 대신) + Page findAllByOrderByCouponIssueDateDesc(PageRequest pageable); } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponExcelService.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponExcelService.java new file mode 100644 index 00000000..c174bc9a --- /dev/null +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponExcelService.java @@ -0,0 +1,152 @@ +package intbyte4.learnsmate.issue_coupon.service; + +import intbyte4.learnsmate.issue_coupon.domain.dto.IssuedCouponFilterDTO; +import intbyte4.learnsmate.issue_coupon.domain.vo.response.AllIssuedCouponResponseVO; +import jakarta.servlet.ServletOutputStream; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Service +@Slf4j +@RequiredArgsConstructor +public class IssueCouponExcelService { + + private static final Map COLUMNS = new LinkedHashMap<>() {{ + put("couponIssuanceCode", "발급 쿠폰 번호"); + put("couponName", "쿠폰 이름"); + put("couponContents", "쿠폰 내용"); + put("couponCategoryName", "쿠폰 종류"); + put("studentCode", "고객 코드"); + put("studentName", "고객 명"); + put("couponUseStatus", "사용 여부"); + put("couponDiscountRate", "할인율"); + put("couponStartDate", "시작일"); + put("couponExpireDate", "만료일"); + put("couponIssueDate", "발급일"); + put("couponUseDate", "사용일"); + }}; + + private final IssueCouponFacade issueCouponFacade; + + public void exportCouponToExcel(ServletOutputStream outputStream, IssuedCouponFilterDTO filterDTO) { + try (Workbook workbook = new XSSFWorkbook()) { + Sheet sheet = workbook.createSheet("Issued Coupon Data"); + CellStyle headerStyle = createHeaderStyle(workbook); + CellStyle dateStyle = createDateStyle(workbook); + + List selectedColumns = filterDTO != null && filterDTO.getSelectedColumns() != null + ? filterDTO.getSelectedColumns() + : new ArrayList<>(COLUMNS.keySet()); + + createHeader(sheet, headerStyle, selectedColumns); + + List issueCouponList; + if (filterDTO != null) { + log.info("Applying filter with DTO: {}", filterDTO); + + issueCouponList = issueCouponFacade.filterIssuedCoupon(filterDTO); + } else { + log.info("No filter applied, getting all Issued Coupons"); + issueCouponList = issueCouponFacade.findAllIssuedCoupons(); + } + log.info("Found {} Issued Coupons to export", issueCouponList.size()); + + writeData(sheet, issueCouponList, dateStyle, selectedColumns); + + for (int i = 0; i < selectedColumns.size(); i++) { + sheet.autoSizeColumn(i); + } + workbook.write(outputStream); + } catch (IOException e) { + log.error("Failed to create Issued Coupon Excel file", e); + throw new RuntimeException("Failed to create Issued Coupon Excel file", e); + } + } + + private void createHeader(Sheet sheet, CellStyle headerStyle, List selectedColumns) { + Row headerRow = sheet.createRow(0); + int columnIndex = 0; + for (String columnKey : selectedColumns) { + Cell cell = headerRow.createCell(columnIndex++); + cell.setCellValue(COLUMNS.get(columnKey)); + cell.setCellStyle(headerStyle); + } + } + + private void writeData(Sheet sheet, List couponList, CellStyle dateStyle, List selectedColumns) { + int rowNum = 1; + for (AllIssuedCouponResponseVO coupon : couponList) { + Row row = sheet.createRow(rowNum++); + int columnIndex = 0; + for (String key : selectedColumns) { + Cell cell = row.createCell(columnIndex++); + setValueByColumnKey(cell, key, coupon, dateStyle); + } + } + } + + private void setValueByColumnKey(Cell cell, String key, AllIssuedCouponResponseVO coupon, CellStyle dateStyle) { + switch (key) { + case "couponIssuanceCode" -> cell.setCellValue(coupon.getCouponIssuanceCode()); + case "couponName" -> cell.setCellValue(coupon.getCouponName()); + case "couponContents" -> cell.setCellValue(coupon.getCouponContents()); + case "couponCategoryName" -> cell.setCellValue(coupon.getCouponCategoryName()); + case "studentCode" -> cell.setCellValue(coupon.getStudentCode()); + case "studentName" -> cell.setCellValue(coupon.getStudentName()); + case "couponUseStatus" -> cell.setCellValue(coupon.getCouponUseStatus() ? "사용" : "미사용"); + case "couponDiscountRate" -> cell.setCellValue(coupon.getCouponDiscountRate() + "%"); + case "couponStartDate" -> { + if (coupon.getCouponStartDate() != null) { + cell.setCellValue(coupon.getCouponStartDate()); + cell.setCellStyle(dateStyle); + } + } + case "couponExpireDate" -> { + if (coupon.getCouponExpireDate() != null) { + cell.setCellValue(coupon.getCouponExpireDate()); + cell.setCellStyle(dateStyle); + } + } + case "couponIssueDate" -> { + if (coupon.getCouponIssueDate() != null) { + cell.setCellValue(coupon.getCouponIssueDate()); + cell.setCellStyle(dateStyle); + } + } + case "couponUseDate" -> { + if (coupon.getCouponUseDate() != null) { + cell.setCellValue(coupon.getCouponUseDate()); + cell.setCellStyle(dateStyle); + } + } + } + } + + private CellStyle createHeaderStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setBorderBottom(BorderStyle.THIN); + style.setAlignment(HorizontalAlignment.CENTER); + + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + return style; + } + + private CellStyle createDateStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setDataFormat(workbook.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss")); + return style; + } +} \ No newline at end of file diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponFacade.java b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponFacade.java index 213420b1..fc9a90d1 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponFacade.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/issue_coupon/service/IssueCouponFacade.java @@ -6,8 +6,11 @@ import intbyte4.learnsmate.issue_coupon.domain.IssueCoupon; import intbyte4.learnsmate.issue_coupon.domain.dto.IssueCouponDTO; import intbyte4.learnsmate.issue_coupon.domain.dto.IssuedCouponFilterDTO; +import intbyte4.learnsmate.issue_coupon.domain.pagination.IssueCouponPageResponse; import intbyte4.learnsmate.issue_coupon.domain.vo.request.IssueCouponRegisterRequestVO; import intbyte4.learnsmate.issue_coupon.domain.vo.response.AllIssuedCouponResponseVO; +import intbyte4.learnsmate.issue_coupon.mapper.IssueCouponMapper; +import intbyte4.learnsmate.issue_coupon.repository.IssueCouponRepository; import intbyte4.learnsmate.member.domain.dto.MemberDTO; import intbyte4.learnsmate.member.domain.entity.Member; import intbyte4.learnsmate.member.mapper.MemberMapper; @@ -15,9 +18,10 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -32,6 +36,8 @@ public class IssueCouponFacade { private final MemberMapper memberMapper; private final CouponService couponService; private final CouponByLectureService couponByLectureService; + private final IssueCouponRepository issueCouponRepository; + private final IssueCouponMapper issueCouponMapper; @Transactional public List issueCouponsToStudents(IssueCouponRegisterRequestVO request) { @@ -95,7 +101,7 @@ public List findAllIssuedCoupons() { return allIssuedCouponResponseVOList; } - public List filterIssuedCoupon (IssuedCouponFilterDTO dto) { + public List filterIssuedCoupon(IssuedCouponFilterDTO dto) { log.info(dto.toString()); // 필터링된 IssueCoupon 가져오기 List filteredIssuedCoupons = issueCouponService.getFilteredIssuedCoupons(dto); @@ -134,31 +140,106 @@ public List filterIssuedCoupon (IssuedCouponFilterDTO log.info(filteredIssuedCoupons.toString()); return responseVO; -// return AllIssuedCouponResponseVO.builder() -// .couponIssuanceCode(issueCoupon.getCouponIssuanceCode()) -// .couponName(coupon.getCouponName() == null || coupon.getCouponName().isEmpty() ? null : coupon.getCouponName()) -// .couponContents(coupon.getCouponContents() == null || coupon.getCouponContents().isEmpty() ? null : coupon.getCouponContents()) -// .couponCategoryName(coupon.getCouponCategory() == null || coupon.getCouponCategory().getCouponCategoryName().isEmpty() -// ? null -// : coupon.getCouponCategory().getCouponCategoryName()) -// .studentCode(studentCode) -// .studentName(studentName) -// .couponDiscountRate(coupon != null ? coupon.getCouponDiscountRate() : null) -// .couponUseStatus(issueCoupon.getCouponUseStatus()) -// .couponUseDate(issueCoupon.getCouponUseDate()) -// .couponIssueDate(issueCoupon.getCouponIssueDate()) -// .couponStartDate(coupon.getCouponStartDate() == null ? null : coupon.getCouponStartDate()) -// .couponExpireDate(coupon != null ? coupon.getCouponExpireDate() : null) -// .couponCode(coupon != null ? coupon.getCouponCode() : null) -// .lectureCode(lectureCodes) -// .lectureName(lectureNames) -// .tutorName(tutorNames) -// .lecturePrice(lecturePrices) -// .build(); }).collect(Collectors.toList()); } + // offset 방식 전체 조회 + public IssueCouponPageResponse findAllIssuedCoupons(int page, int size) { + PageRequest pageable = PageRequest.of(page, size); + Page issueCouponPage = issueCouponRepository.findAllByOrderByCouponIssueDateDesc(pageable); + + List responseList = issueCouponPage.getContent().stream() + .map(issueCoupon -> { + CouponEntity coupon = couponService.findByCouponCode(issueCoupon.getCoupon().getCouponCode()); + List lectureCodes = couponByLectureService.getLectureCodesByCouponCode(coupon.getCouponCode()); + List lectureNames = couponByLectureService.getLectureNamesByCouponCode(coupon.getCouponCode()); + List tutorNames = couponByLectureService.getTutorNamesByCouponCode(coupon.getCouponCode()); + List lecturePrices = couponByLectureService.getLecturePricesByCouponCode(coupon.getCouponCode()); + + MemberDTO student = memberService.findByStudentCode(issueCoupon.getStudent().getMemberCode()); + + return AllIssuedCouponResponseVO.builder() + .couponIssuanceCode(issueCoupon.getCouponIssuanceCode()) + .couponName(coupon.getCouponName()) + .couponContents(coupon.getCouponContents()) + .couponCategoryName(coupon.getCouponCategory().getCouponCategoryName()) + .studentCode(issueCoupon.getStudent().getMemberCode()) + .studentName(student.getMemberName()) + .couponDiscountRate(coupon.getCouponDiscountRate()) + .couponUseStatus(issueCoupon.getCouponUseStatus()) + .couponUseDate(issueCoupon.getCouponUseDate()) + .couponIssueDate(issueCoupon.getCouponIssueDate()) + .couponStartDate(coupon.getCouponStartDate()) + .couponExpireDate(coupon.getCouponExpireDate()) + .couponCode(issueCoupon.getCoupon().getCouponCode()) + .lectureCode(lectureCodes) + .lectureName(lectureNames) + .tutorName(tutorNames) + .lecturePrice(lecturePrices) + .build(); + }) + .collect(Collectors.toList()); + + return new IssueCouponPageResponse<>( + responseList, + issueCouponPage.getTotalElements(), + issueCouponPage.getNumber(), + issueCouponPage.getSize(), + issueCouponPage.getTotalPages() + ); + } + // offset 방식 필터링 + public IssueCouponPageResponse filterIssuedCoupon(int page, int size, IssuedCouponFilterDTO dto) { + log.info(dto.toString()); + PageRequest pageable = PageRequest.of(page, size); + + // dto -> IssueCouponFilterRequestVO 로 변환 후 필터링된 IssueCoupon 가져오기 (페이지네이션 적용) + Page issueCouponPage = issueCouponRepository.getFilteredIssuedCoupons(issueCouponMapper.fromDTOToFilterVO(dto), pageable); + + // DTO 리스트로 변환 + List responseList = issueCouponPage.getContent().stream() + .map(issueCoupon -> { + CouponEntity coupon = issueCoupon.getCoupon(); + + List lectureCodes = couponByLectureService.getLectureCodesByCouponCode(coupon.getCouponCode()); + List lectureNames = couponByLectureService.getLectureNamesByCouponCode(coupon.getCouponCode()); + List tutorNames = couponByLectureService.getTutorNamesByCouponCode(coupon.getCouponCode()); + List lecturePrices = couponByLectureService.getLecturePricesByCouponCode(coupon.getCouponCode()); + + Long studentCode = issueCoupon.getStudent().getMemberCode(); + String studentName = issueCoupon.getStudent().getMemberName(); + + return AllIssuedCouponResponseVO.builder() + .couponIssuanceCode(issueCoupon.getCouponIssuanceCode()) + .couponName(coupon.getCouponName()) + .couponContents(coupon.getCouponContents()) + .couponCategoryName(coupon.getCouponCategory().getCouponCategoryName()) + .studentCode(studentCode) + .studentName(studentName) + .couponDiscountRate(coupon.getCouponDiscountRate()) + .couponUseStatus(issueCoupon.getCouponUseStatus()) + .couponUseDate(issueCoupon.getCouponUseDate()) + .couponIssueDate(issueCoupon.getCouponIssueDate()) + .couponStartDate(coupon.getCouponStartDate()) + .couponExpireDate(coupon.getCouponExpireDate()) + .couponCode(coupon.getCouponCode()) + .lectureCode(lectureCodes) + .lectureName(lectureNames) + .tutorName(tutorNames) + .lecturePrice(lecturePrices) + .build(); + }) + .collect(Collectors.toList()); + + return new IssueCouponPageResponse<>( + responseList, // 데이터 리스트 + issueCouponPage.getTotalElements(), // 전체 데이터 수 + issueCouponPage.getTotalPages(), // 전체 페이지 수 + issueCouponPage.getNumber() + 1, // 현재 페이지 (0-based → 1-based) + issueCouponPage.getSize() // 페이지 크기 + ); + } }