Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/BCSDLab/KOIN_API_V2 into…
Browse files Browse the repository at this point in the history
… fix/1071-modify-admin-history
  • Loading branch information
Soundbar91 committed Dec 8, 2024
2 parents 7c1ecb2 + d874940 commit 4fddc05
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoryResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoriesResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitShopsResponse;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryRequest;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryResponse;
Expand Down Expand Up @@ -44,7 +44,7 @@ public interface AdminBenefitApi {
)
@Operation(summary = "상점 혜택 카테고리를 모두 조회한다.")
@GetMapping("/categories")
ResponseEntity<AdminBenefitCategoryResponse> getBenefitCategories(
ResponseEntity<AdminBenefitCategoriesResponse> getBenefitCategories(
@Auth(permit = {ADMIN}) Integer adminId
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoryResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoriesResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitShopsResponse;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryRequest;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryResponse;
Expand All @@ -36,10 +36,10 @@ public class AdminBenefitController implements AdminBenefitApi {
private final AdminBenefitService adminBenefitService;

@GetMapping("/categories")
public ResponseEntity<AdminBenefitCategoryResponse> getBenefitCategories(
public ResponseEntity<AdminBenefitCategoriesResponse> getBenefitCategories(
@Auth(permit = {ADMIN}) Integer adminId
) {
AdminBenefitCategoryResponse response = adminBenefitService.getBenefitCategories();
AdminBenefitCategoriesResponse response = adminBenefitService.getBenefitCategories();
return ResponseEntity.ok(response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
import io.swagger.v3.oas.annotations.media.Schema;

@JsonNaming(SnakeCaseStrategy.class)
public record AdminBenefitCategoryResponse(
public record AdminBenefitCategoriesResponse(
@Schema(description = "혜택 카테고리 리스트")
List<InnerBenefitResponse> benefits
) {

public static AdminBenefitCategoryResponse from(List<BenefitCategory> benefitCategories) {
return new AdminBenefitCategoryResponse(
public static AdminBenefitCategoriesResponse from(List<BenefitCategory> benefitCategories) {
return new AdminBenefitCategoriesResponse(
benefitCategories.stream().map(InnerBenefitResponse::from).toList()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoryResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitCategoriesResponse;
import in.koreatech.koin.admin.benefit.dto.AdminBenefitShopsResponse;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryRequest;
import in.koreatech.koin.admin.benefit.dto.AdminCreateBenefitCategoryResponse;
Expand Down Expand Up @@ -36,9 +36,9 @@ public class AdminBenefitService {
private final AdminBenefitCategoryMapRepository adminBenefitCategoryMapRepository;
private final AdminShopRepository adminShopRepository;

public AdminBenefitCategoryResponse getBenefitCategories() {
public AdminBenefitCategoriesResponse getBenefitCategories() {
List<BenefitCategory> categories = adminBenefitCategoryRepository.findAllByOrderByTitleAsc();
return AdminBenefitCategoryResponse.from(categories);
return AdminBenefitCategoriesResponse.from(categories);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.time.LocalTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
Expand Down Expand Up @@ -67,7 +68,10 @@ public record InnerShopResponse(
double averageRate,

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

@Schema(example = "콜라 서비스", description = "혜택 설명", requiredMode = NOT_REQUIRED)
String benefitDetail
) {

public static Comparator<InnerShopResponse> getComparator() {
Expand All @@ -80,7 +84,8 @@ public static Comparator<InnerShopResponse> getComparator() {
public static InnerShopResponse from(
Shop shop,
boolean isEvent,
boolean isOpen
boolean isOpen,
String benefitDetail
) {
return new InnerShopResponse(
shop.getShopCategories().stream().map(shopCategoryMap ->
Expand All @@ -102,7 +107,8 @@ public static InnerShopResponse from(
.orElse(0.0) * 10) / 10.0,
shop.getReviews().stream()
.filter(review -> !review.isDeleted())
.count()
.count(),
benefitDetail
);
}

Expand Down
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,13 +2,21 @@

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;

public interface BenefitCategoryMapRepository extends Repository<BenefitCategoryMap, Integer> {

List<BenefitCategoryMap> findAllByBenefitCategoryId(Integer benefitCategoryId);
List<BenefitCategoryMap> findByBenefitCategoryId(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 @@ -35,18 +35,24 @@ public BenefitCategoryResponse getBenefitCategories() {
}

public BenefitShopsResponse getBenefitShops(Integer benefitId) {
List<BenefitCategoryMap> benefitCategoryMaps = benefitCategoryMapRepository
.findAllByBenefitCategoryId(benefitId);
List<BenefitCategoryMap> benefitCategoryMaps = benefitCategoryMapRepository.findByBenefitCategoryId(benefitId);
LocalDateTime now = LocalDateTime.now(clock);

List<InnerShopResponse> innerShopResponses = benefitCategoryMaps.stream()
.map(benefitCategoryMap -> {
Shop shop = benefitCategoryMap.getShop();
String benefitDetail = benefitCategoryMap.getDetail();
boolean isDurationEvent = eventArticleRepository.isDurationEvent(shop.getId(), now.toLocalDate());
return InnerShopResponse.from(shop, isDurationEvent, shop.isOpen(now));
return InnerShopResponse.from(
shop,
isDurationEvent,
shop.isOpen(now),
benefitDetail
);
})
.sorted(InnerShopResponse.getComparator())
.toList();
BenefitShopsResponse shopsResponse = BenefitShopsResponse.from(innerShopResponses);
return shopsResponse;

return BenefitShopsResponse.from(innerShopResponses);
}
}
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
);
}

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
) {
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
);
}

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);
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void setup() {

성빈_학생 = userFixture.성빈_학생();

benefitCategoryMapFixture.혜택_추가(김밥천국, 배달비_무료);
benefitCategoryMapFixture.설명이_포함된_혜택_추가(김밥천국, 배달비_무료, "무료");
benefitCategoryMapFixture.혜택_추가(마슬랜, 배달비_무료);
benefitCategoryMapFixture.혜택_추가(영업중인_티바, 배달비_무료);
benefitCategoryMapFixture.혜택_추가(영업중이_아닌_신전_떡볶이, 배달비_무료);
Expand Down Expand Up @@ -183,7 +183,8 @@ void setup() {
"is_event": false,
"is_open": true,
"average_rate": 5.0,
"review_count": 1
"review_count": 1,
"benefit_detail": "무료"
},
{
"category_ids": [],
Expand Down
Loading

0 comments on commit 4fddc05

Please sign in to comment.