Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: 모든 상점 조회 API에 혜택 상세 필드 추가 #1121

Merged
merged 8 commits into from
Dec 6, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

import in.koreatech.koin.domain.shop.model.shop.Shop;
import in.koreatech.koin.global.domain.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -34,9 +36,14 @@ public class BenefitCategoryMap extends BaseEntity {
@JoinColumn(name = "benefit_id", referencedColumnName = "id", nullable = false)
private BenefitCategory benefitCategory;

@Size(min = 2, max = 20)
@Column(name = "detail")
private String detail;

@Builder
public BenefitCategoryMap(Shop shop, BenefitCategory benefitCategory) {
public BenefitCategoryMap(Shop shop, BenefitCategory benefitCategory, String detail) {
this.shop = shop;
this.benefitCategory = benefitCategory;
this.detail = detail;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;

import in.koreatech.koin.domain.benefit.model.BenefitCategoryMap;
Expand All @@ -10,5 +11,12 @@ public interface BenefitCategoryMapRepository extends Repository<BenefitCategory

List<BenefitCategoryMap> findAllByBenefitCategoryId(Integer benefitCategoryId);

@Query("""
SELECT bcm FROM BenefitCategoryMap bcm
JOIN FETCH bcm.shop s
JOIN FETCH bcm.benefitCategory bc
""")
List<BenefitCategoryMap> findAllWithFetchJoin();

BenefitCategoryMap save(BenefitCategoryMap benefitCategoryMap);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public static ShopsResponseV2 from(
ShopsSortCriteria sortBy,
List<ShopsFilterCriteria> shopsFilterCriterias,
LocalDateTime now,
String query
String query,
Map<Integer, List<String>> benefitDetail
) {
List<InnerShopResponse> innerShopResponses = shops.stream()
.filter(queryPredicate(query))
Expand All @@ -53,7 +54,8 @@ public static ShopsResponseV2 from(
shopInfo.durationEvent(),
it.isOpen(now),
shopInfo.averageRate(),
shopInfo.reviewCount()
shopInfo.reviewCount(),
benefitDetail.getOrDefault(it.id(), List.of())
);
})
.filter(ShopsFilterCriteria.createCombinedFilter(shopsFilterCriterias))
Expand Down Expand Up @@ -101,7 +103,10 @@ public record InnerShopResponse(
double averageRate,

@Schema(example = "10", description = "리뷰 개수", requiredMode = REQUIRED)
long reviewCount
long reviewCount,

@Schema(example = "['배달비 무료', '콜라 서비스']", description = "혜택 설명", requiredMode = NOT_REQUIRED)
List<String> benefitDetails
) {

@JsonNaming(value = SnakeCaseStrategy.class)
Expand Down Expand Up @@ -138,7 +143,8 @@ public static InnerShopResponse from(
Boolean isEvent,
Boolean isOpen,
Double averageRate,
Long reviewCount
Long reviewCount,
List<String> benefitDetails
) {
return new InnerShopResponse(
shop.shopCategories().stream().map(ShopCategoryCache::id).toList(),
Expand All @@ -159,7 +165,8 @@ public static InnerShopResponse from(
isEvent,
isOpen,
averageRate,
reviewCount
reviewCount,
benefitDetails
Comment on lines -162 to +169
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 뭔가 추가적인 공백이있는것같아요

);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static in.koreatech.koin.global.domain.notification.model.NotificationSubscribeType.REVIEW_PROMPT;

import in.koreatech.koin.domain.benefit.model.BenefitCategoryMap;
import in.koreatech.koin.domain.benefit.repository.BenefitCategoryMapRepository;
import in.koreatech.koin.domain.shop.cache.ShopsCacheService;
import in.koreatech.koin.domain.shop.cache.dto.ShopsCache;
import in.koreatech.koin.domain.shop.dto.shop.ShopsFilterCriteria;
Expand All @@ -24,6 +26,8 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
Expand All @@ -43,6 +47,7 @@ public class ShopService {
private final ShopCustomRepository shopCustomRepository;
private final NotificationSubscribeRepository notificationSubscribeRepository;
private final ShopReviewNotificationRedisRepository shopReviewNotificationRedisRepository;
private final BenefitCategoryMapRepository benefitCategoryMapRepository;

public ShopResponse getShop(Integer shopId) {
Shop shop = shopRepository.getById(shopId);
Expand All @@ -63,23 +68,37 @@ public ShopCategoriesResponse getShopsCategories() {
}

public ShopsResponseV2 getShopsV2(
ShopsSortCriteria sortBy,
List<ShopsFilterCriteria> filterCriteria,
String query
ShopsSortCriteria sortBy,
List<ShopsFilterCriteria> filterCriteria,
String query
Comment on lines +71 to +73
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 공백이 생겼어요

) {
if (filterCriteria.contains(null)) {
throw KoinIllegalArgumentException.withDetail("유효하지 않은 필터입니다.");
}
ShopsCache shopCaches = shopsCache.findAllShopCache();
LocalDateTime now = LocalDateTime.now(clock);
Map<Integer, ShopInfo> shopInfoMap = shopCustomRepository.findAllShopInfo(now);
List<BenefitCategoryMap> benefitCategorys = benefitCategoryMapRepository.findAllWithFetchJoin();
Map<Integer, List<String>> benefitDetailMap = new HashMap<>(benefitCategorys.size());
benefitCategorys.forEach(benefitCategory -> {
int shopId = benefitCategory.getShop().getId();
String benefitDetail = benefitCategory.getDetail();
if (benefitDetailMap.containsKey(shopId)) {
benefitDetailMap.get(shopId).add(benefitDetail);
} else {
List<String> details = new ArrayList<>();
details.add(benefitDetail);
benefitDetailMap.put(shopId, details);
}
});
return ShopsResponseV2.from(
shopCaches.shopCaches(),
shopInfoMap,
sortBy,
filterCriteria,
now,
query
shopCaches.shopCaches(),
shopInfoMap,
sortBy,
filterCriteria,
now,
query,
benefitDetailMap
Comment on lines +95 to +101
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 동일하게 공백이 생겼습니다.

);
}

Expand All @@ -88,9 +107,9 @@ public void publishCallNotification(Integer shopId, Integer studentId) {

if (isSubscribeReviewNotification(studentId)) {
ShopReviewNotification shopReviewNotification = ShopReviewNotification.builder()
.shopId(shopId)
.studentId(studentId)
.build();
.shopId(shopId)
.studentId(studentId)
.build();

double score = LocalDateTime.now(clock).plusHours(1).toEpochSecond(ZoneOffset.UTC);
shopReviewNotificationRedisRepository.save(shopReviewNotification, score);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE `shop_benefit_category_map`
ADD COLUMN `detail` VARCHAR(20);
69 changes: 69 additions & 0 deletions src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import in.koreatech.koin.domain.benefit.model.BenefitCategory;
import in.koreatech.koin.fixture.BenefitCategoryFixture;
import in.koreatech.koin.fixture.BenefitCategoryMapFixture;
import java.time.LocalDate;

import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -40,6 +43,12 @@
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ShopApiTest extends AcceptanceTest {

@Autowired
private BenefitCategoryFixture benefitCategoryFixture;

@Autowired
private BenefitCategoryMapFixture benefitCategoryMapFixture;

@Autowired
private UserFixture userFixture;

Expand Down Expand Up @@ -1897,4 +1906,64 @@ void setUp() {
)
.andExpect(status().isOk());
}

@Test
void 리뷰를_조회하면_혜택_정보가_조회된다() throws Exception {
Shop 영업중인_티바 = shopFixture.영업중인_티바(owner);
shopReviewFixture.리뷰_4점(익명_학생, 영업중인_티바);

shopReviewFixture.리뷰_4점(익명_학생, 마슬랜);
shopReviewFixture.리뷰_4점(익명_학생, 마슬랜);
// 2024-01-15 12:00 월요일 기준
boolean 마슬랜_영업여부 = true;
boolean 티바_영업여부 = true;

BenefitCategory 최소주문금액_무료 = benefitCategoryFixture.최소주문금액_무료();
BenefitCategory 서비스_증정 = benefitCategoryFixture.서비스_증정();
benefitCategoryMapFixture.설명이_포함된_혜택_추가(영업중인_티바, 최소주문금액_무료, "무료");
benefitCategoryMapFixture.설명이_포함된_혜택_추가(영업중인_티바, 서비스_증정, "콜라");
mockMvc.perform(
get("/v2/shops")
.queryParam("sorter", "COUNT_DESC")
)
.andExpect(status().isOk())
.andExpect(content().json(String.format("""
{
"count": 2,
"shops": [
{
"category_ids": [
\s
],
"delivery": true,
Comment on lines +1926 to +1938
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 체크해주세요

"id": 1,
"name": "마슬랜 치킨",
"pay_bank": true,
"pay_card": true,
"phone": "010-7574-1212",
"is_event": false,
"is_open": %s,
"average_rate": 4.0,
"review_count": 2,
"benefit_details": []
},{
"category_ids": [
\s
],
"delivery": true,
"id": 2,
"name": "티바",
"pay_bank": true,
"pay_card": true,
"phone": "010-7788-9900",
"is_event": false,
"is_open": %s,
"average_rate": 4.0,
"review_count": 1,
"benefit_details": ["무료", "콜라"]
}
]
}
""", 티바_영업여부, 마슬랜_영업여부)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,12 @@ public BenefitCategoryMapFixture(
.benefitCategory(benefitCategory)
.build());
}

public BenefitCategoryMap 설명이_포함된_혜택_추가(Shop shop, BenefitCategory benefitCategory, String detail) {
return benefitCategoryMapRepository.save(BenefitCategoryMap.builder()
.shop(shop)
.benefitCategory(benefitCategory)
.detail(detail)
.build());
}
}
Loading