From b7c15567e63d93a98cca3ef7ad5b44928a64c67a Mon Sep 17 00:00:00 2001 From: SCY Date: Fri, 16 Aug 2024 16:51:16 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EA=B3=B5=EB=AA=A8=EA=B8=80=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(#356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 마감임박순 필터링 이름 마감임박만으로 변경 Co-authored-by: fromitive * refactor: 필터링 쿼리 수정 Co-authored-by: fromitive * feat: "참여가능만" 필터링 기능 구현 Co-authored-by: fromitive * feat: "참여가능만" 필터링 기능 연결 Co-authored-by: fromitive * fix: 쿼리 내 불필요한 파라미터 제거 Co-authored-by: fromitive * refactor: 할인율이 null일 경우 높은할인율 필터링 대상에서 제외 Co-authored-by: fromitive * feat: 참여가능만 필터링 전략 클래스 추가 * feat: 공모 목록 조회 API 응답값 변경 * fix: 높은 할인율 단위 변경 및 last-id 필터링 로직 수정 * style: 주석 제거 --------- Co-authored-by: fromitive --- .../offering/domain/OfferingFilter.java | 8 ++-- .../HighDiscountOfferingStrategy.java | 8 ++-- .../ImminentOfferingStrategy.java | 8 +--- .../JoinableOfferingStrategy.java | 25 +++++++++++ .../repository/OfferingRepository.java | 42 +++++++++++-------- .../offering/service/OfferingFetcher.java | 4 +- .../offering/service/OfferingService.java | 3 +- .../service/dto/OfferingAllResponseItem.java | 13 +++--- .../integration/OfferingIntegrationTest.java | 1 + 9 files changed, 71 insertions(+), 41 deletions(-) create mode 100644 backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/JoinableOfferingStrategy.java diff --git a/backend/src/main/java/com/zzang/chongdae/offering/domain/OfferingFilter.java b/backend/src/main/java/com/zzang/chongdae/offering/domain/OfferingFilter.java index adfec2242..03cc95616 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/domain/OfferingFilter.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/domain/OfferingFilter.java @@ -13,10 +13,10 @@ @AllArgsConstructor public enum OfferingFilter { - JOINABLE("참여가능만", VISIBLE), // 처음: 참여 가능한 것 중 id가 가장 높은 값 10개 / 이후: 참여 가능한 것 중 마지막 id보다 낮은 것 x개 찾기 - IMMINENT("마감임박순", VISIBLE), // 처음: 현재 시간보다 큰 것 중 가장 작은 값 10개 / 이후: lastMeetingDate 보다 큰 것 x개 찾기 - HIGH_DISCOUNT("높은할인율순", VISIBLE), // 처음: 할인율(n빵가격/낱개가격) 가장 높은 값 10개 / 이후: 마지막 할인율(n빵가격/낱개가격)보다 낮은 것 x개 찾기 - RECENT("최신순", INVISIBLE); // 처음: id가 가장 높은 값 10개 / 이후: 마지막 id보다 낮은 것 x개 찾기 + JOINABLE("참여가능만", VISIBLE), + IMMINENT("마감임박만", VISIBLE), + HIGH_DISCOUNT("높은할인율순", VISIBLE), + RECENT("최신순", INVISIBLE); private final String value; private final OfferingFilterType type; diff --git a/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/HighDiscountOfferingStrategy.java b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/HighDiscountOfferingStrategy.java index 9e42115cb..5bf460271 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/HighDiscountOfferingStrategy.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/HighDiscountOfferingStrategy.java @@ -13,7 +13,7 @@ public HighDiscountOfferingStrategy(OfferingRepository offeringRepository) { @Override protected List fetchOfferingsWithoutLastId(String searchKeyword, Pageable pageable) { - double outOfRangeDiscountRate = 1; + double outOfRangeDiscountRate = 100; Long outOfRangeId = findOutOfRangeId(); return offeringRepository.findHighDiscountOfferingsWithKeyword( outOfRangeDiscountRate, outOfRangeId, searchKeyword, pageable); @@ -22,8 +22,8 @@ protected List fetchOfferingsWithoutLastId(String searchKeyword, @Override protected List fetchOfferingsWithLastOffering( OfferingEntity lastOffering, String searchKeyword, Pageable pageable) { - double discountRate = lastOffering.toOfferingPrice().calculateDiscountRate(); - return offeringRepository.findHighDiscountOfferingsWithKeyword(discountRate, lastOffering.getId(), - searchKeyword, pageable); + double lastDiscountRate = lastOffering.getDiscountRate(); + return offeringRepository.findHighDiscountOfferingsWithKeyword( + lastDiscountRate, lastOffering.getId(), searchKeyword, pageable); } } diff --git a/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/ImminentOfferingStrategy.java b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/ImminentOfferingStrategy.java index 35d82dc4d..5966f6c5c 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/ImminentOfferingStrategy.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/ImminentOfferingStrategy.java @@ -14,22 +14,18 @@ public ImminentOfferingStrategy(OfferingRepository offeringRepository) { @Override protected List fetchOfferingsWithoutLastId(String searchKeyword, Pageable pageable) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime threshold = LocalDateTime.now().plusHours(6); LocalDateTime outOfRangeMeetingDate = LocalDateTime.now(); Long outOfRangeId = findOutOfRangeId(); return offeringRepository.findImminentOfferingsWithKeyword( - now, threshold, outOfRangeMeetingDate, outOfRangeId, searchKeyword, pageable); + outOfRangeMeetingDate, outOfRangeId, searchKeyword, pageable); } @Override protected List fetchOfferingsWithLastOffering( OfferingEntity lastOffering, String searchKeyword, Pageable pageable) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime threshold = LocalDateTime.now().plusHours(6); LocalDateTime lastMeetingDate = lastOffering.getMeetingDate(); Long lastId = lastOffering.getId(); return offeringRepository.findImminentOfferingsWithKeyword( - now, threshold, lastMeetingDate, lastId, searchKeyword, pageable); + lastMeetingDate, lastId, searchKeyword, pageable); } } diff --git a/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/JoinableOfferingStrategy.java b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/JoinableOfferingStrategy.java new file mode 100644 index 000000000..53f39210e --- /dev/null +++ b/backend/src/main/java/com/zzang/chongdae/offering/domain/offeringfetchstrategy/JoinableOfferingStrategy.java @@ -0,0 +1,25 @@ +package com.zzang.chongdae.offering.domain.offeringfetchstrategy; + +import com.zzang.chongdae.offering.repository.OfferingRepository; +import com.zzang.chongdae.offering.repository.entity.OfferingEntity; +import java.util.List; +import org.springframework.data.domain.Pageable; + +public class JoinableOfferingStrategy extends OfferingFetchStrategy { + + public JoinableOfferingStrategy(OfferingRepository offeringRepository) { + super(offeringRepository); + } + + @Override + protected List fetchOfferingsWithoutLastId(String searchKeyword, Pageable pageable) { + Long outOfRangeId = findOutOfRangeId(); + return offeringRepository.findJoinableOfferingsWithKeyword(outOfRangeId, searchKeyword, pageable); + } + + @Override + protected List fetchOfferingsWithLastOffering(OfferingEntity lastOffering, String searchKeyword, + Pageable pageable) { + return offeringRepository.findJoinableOfferingsWithKeyword(lastOffering.getId(), searchKeyword, pageable); + } +} diff --git a/backend/src/main/java/com/zzang/chongdae/offering/repository/OfferingRepository.java b/backend/src/main/java/com/zzang/chongdae/offering/repository/OfferingRepository.java index 1cf210835..60368caa3 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/repository/OfferingRepository.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/repository/OfferingRepository.java @@ -11,10 +11,10 @@ public interface OfferingRepository extends JpaRepository { @Query(""" - SELECT o - FROM OfferingEntity as o JOIN OfferingMemberEntity as om - ON o.id = om.offering.id - WHERE om.member = :member + SELECT o + FROM OfferingEntity as o JOIN OfferingMemberEntity as om + ON o.id = om.offering.id + WHERE om.member = :member """) List findCommentRoomsByMember(MemberEntity member); @@ -30,30 +30,36 @@ public interface OfferingRepository extends JpaRepository @Query(""" SELECT o FROM OfferingEntity o - WHERE ((o.meetingDate > :lastMeetingDate AND o.meetingDate < :threshold) - OR (o.meetingDate = :lastMeetingDate AND o.id < :lastId AND o.meetingDate < :threshold) - OR (o.totalCount <= 3 AND (o.totalCount - o.currentCount) < 2 AND (o.totalCount - o.currentCount) > 0) - OR (o.totalCount > 3 AND (o.totalCount - o.currentCount) < 3 AND (o.totalCount - o.currentCount) > 0)) - AND (:keyword IS NULL OR o.title LIKE %:keyword% OR o.meetingAddress LIKE %:keyword%) - AND (o.isManualConfirmed IS FALSE) - AND (o.meetingDate >= :now) - AND ((o.meetingDate > :lastMeetingDate) OR (o.meetingDate = :lastMeetingDate AND o.id < :lastId)) + WHERE (o.offeringStatus = 'IMMINENT') + AND (o.meetingDate > :lastMeetingDate OR (o.meetingDate = :lastMeetingDate AND o.id < :lastId)) + AND (:keyword IS NULL OR o.title LIKE %:keyword% OR o.meetingAddress LIKE %:keyword%) ORDER BY o.meetingDate ASC, o.id DESC """) List findImminentOfferingsWithKeyword( - LocalDateTime now, LocalDateTime threshold, LocalDateTime lastMeetingDate, Long lastId, String keyword, - Pageable pageable); + LocalDateTime lastMeetingDate, Long lastId, String keyword, Pageable pageable); @Query(""" SELECT o FROM OfferingEntity o - WHERE ((o.originPrice - (o.totalPrice * 1.0 / o.totalCount)) / o.originPrice < :discountRate - OR ((o.originPrice - (o.totalPrice * 1.0 / o.totalCount)) / o.originPrice = :discountRate AND o.id < :lastId)) + WHERE (o.offeringStatus != 'CONFIRMED') + AND (o.discountRate IS NOT NULL) + AND (o.discountRate < :lastDiscountRate OR (o.discountRate = :lastDiscountRate AND o.id < :lastId)) AND (:keyword IS NULL OR o.title LIKE %:keyword% OR o.meetingAddress LIKE %:keyword%) - ORDER BY (o.originPrice - (o.totalPrice * 1.0 / o.totalCount)) / o.originPrice DESC, o.id DESC + ORDER BY o.discountRate DESC, o.id DESC """) List findHighDiscountOfferingsWithKeyword( - double discountRate, Long lastId, String keyword, Pageable pageable); + double lastDiscountRate, Long lastId, String keyword, Pageable pageable); + + @Query(""" + SELECT o + FROM OfferingEntity o + WHERE (o.offeringStatus = 'AVAILABLE' OR o.offeringStatus = 'IMMINENT') + AND (o.id < :lastId) + AND (:keyword IS NULL OR o.title LIKE %:keyword% OR o.meetingAddress LIKE %:keyword%) + ORDER BY o.id DESC + """) + List findJoinableOfferingsWithKeyword(Long lastId, String keyword, Pageable pageable); + @Query("SELECT MAX(o.id) FROM OfferingEntity o") Long findMaxId(); diff --git a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingFetcher.java b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingFetcher.java index 5877138db..62a6967af 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingFetcher.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingFetcher.java @@ -4,6 +4,7 @@ import com.zzang.chongdae.offering.domain.OfferingFilter; import com.zzang.chongdae.offering.domain.offeringfetchstrategy.HighDiscountOfferingStrategy; import com.zzang.chongdae.offering.domain.offeringfetchstrategy.ImminentOfferingStrategy; +import com.zzang.chongdae.offering.domain.offeringfetchstrategy.JoinableOfferingStrategy; import com.zzang.chongdae.offering.domain.offeringfetchstrategy.OfferingFetchStrategy; import com.zzang.chongdae.offering.domain.offeringfetchstrategy.RecentOfferingStrategy; import com.zzang.chongdae.offering.exception.OfferingErrorCode; @@ -27,7 +28,8 @@ public OfferingFetcher(OfferingRepository offeringRepository) { this.strategyMap = Map.of( OfferingFilter.RECENT, new RecentOfferingStrategy(offeringRepository), OfferingFilter.IMMINENT, new ImminentOfferingStrategy(offeringRepository), - OfferingFilter.HIGH_DISCOUNT, new HighDiscountOfferingStrategy(offeringRepository) + OfferingFilter.HIGH_DISCOUNT, new HighDiscountOfferingStrategy(offeringRepository), + OfferingFilter.JOINABLE, new JoinableOfferingStrategy(offeringRepository) ); } diff --git a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java index 6e6e3dd6c..a2108d07f 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java @@ -59,8 +59,7 @@ public OfferingAllResponse getAllOffering(String filterName, String searchKeywor return new OfferingAllResponse(offerings.stream() .map(offering -> { OfferingPrice offeringPrice = offering.toOfferingPrice(); - OfferingCondition offeringCondition = offering.toOfferingCondition(); - return new OfferingAllResponseItem(offering, offeringPrice, offeringCondition); + return new OfferingAllResponseItem(offering, offeringPrice); }) .toList() ); diff --git a/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingAllResponseItem.java b/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingAllResponseItem.java index e321197e5..1bdaddc7d 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingAllResponseItem.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingAllResponseItem.java @@ -1,8 +1,7 @@ package com.zzang.chongdae.offering.service.dto; -import com.zzang.chongdae.offering.domain.OfferingStatus; import com.zzang.chongdae.offering.domain.OfferingPrice; -import com.zzang.chongdae.offering.domain.OfferingCondition; +import com.zzang.chongdae.offering.domain.OfferingStatus; import com.zzang.chongdae.offering.repository.entity.OfferingEntity; public record OfferingAllResponseItem(Long id, @@ -13,21 +12,23 @@ public record OfferingAllResponseItem(Long id, String thumbnailUrl, Integer dividedPrice, Integer originPrice, + Double discountRate, OfferingStatus status, Boolean isOpen) { public OfferingAllResponseItem( - OfferingEntity offering, OfferingPrice offeringPrice, OfferingCondition offeringCondition) { + OfferingEntity offering, OfferingPrice offeringPrice) { this(offering.getId(), offering.getTitle(), offering.getMeetingAddressDong(), - offeringCondition.getCurrentCount(), + offering.getCurrentCount(), offering.getTotalCount(), offering.getThumbnailUrl(), offeringPrice.calculateDividedPrice(), offeringPrice.getOriginPrice(), - offeringCondition.decideOfferingStatus(), - offeringCondition.isOpen() + offering.getDiscountRate(), + offering.getOfferingStatus(), + offering.getOfferingStatus().isOpen() ); } } diff --git a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java index 879147421..f5805d4d3 100644 --- a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java +++ b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java @@ -134,6 +134,7 @@ class GetAllOffering { fieldWithPath("offerings[].thumbnailUrl").description("사진 링크"), fieldWithPath("offerings[].dividedPrice").description("n빵 가격"), fieldWithPath("offerings[].originPrice").description("원 가격"), + fieldWithPath("offerings[].discountRate").description("할인율"), fieldWithPath("offerings[].status").description("공모 상태" + getEnumValuesAsString(OfferingStatus.class)), fieldWithPath("offerings[].isOpen").description("공모 참여 가능 여부")