Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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 @@ -78,4 +78,10 @@ public void deleteFoodTruckImagesFromS3(Long ownerId, Long foodTruckId, DeleteFo

foodTruckImageService.deleteFoodTruckImagesFromS3(owner, foodTruckId, request);
}

public FoodTruckDetailResponse getFoodTruckDetails(Long memberId, Long foodTruckId) {
User member = memberValidator.validateAndGetMember(memberId);

return foodTruckInfoService.getFoodTruckDetails(member, foodTruckId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import konkuk.chacall.domain.foodtruck.presentation.dto.request.DateRangeRequest;
import konkuk.chacall.domain.foodtruck.presentation.dto.request.FoodTruckSearchRequest;
import konkuk.chacall.domain.foodtruck.presentation.dto.request.UpdateFoodTruckInfoRequest;
import konkuk.chacall.domain.foodtruck.presentation.dto.response.FoodTruckDetailResponse;
import konkuk.chacall.domain.foodtruck.presentation.dto.response.FoodTruckResponse;
import konkuk.chacall.domain.member.domain.repository.SavedFoodTruckRepository;
import konkuk.chacall.domain.region.domain.model.Region;
Expand Down Expand Up @@ -133,4 +134,22 @@ private void syncServiceAreas(FoodTruck foodTruck, Set<Long> requestedRegionIds)
foodTruckServiceAreaRepository.deleteAll(serviceAreasToRemove);
}
}

public FoodTruckDetailResponse getFoodTruckDetails(User member, Long foodTruckId) {
FoodTruck foodTruck = foodTruckRepository.findById(foodTruckId)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.FOOD_TRUCK_NOT_FOUND));

switch(member.getRole()) {
case MEMBER -> foodTruck.validateViewableStatusForMember();
case OWNER -> foodTruck.vaildateViewableStatusForOwner(member.getUserId());
case ADMIN -> {}
}

List<FoodTruckServiceArea> foodTruckServiceAreas = foodTruckServiceAreaRepository.findAllByFoodTruckId(foodTruckId);
List<AvailableDate> availableDates = availableDateRepository.findAllByFoodTruckId(foodTruckId);

boolean isSaved = savedFoodTruckRepository.existsByMemberIdAndFoodTruckId(member.getUserId(), foodTruckId);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

SavedFoodTruckRepository의 버그로 인해 이 코드가 실패합니다.

existsByMemberIdAndFoodTruckId 메서드에 파라미터 이름 불일치 버그가 있어, 이 줄이 실행될 때 런타임 오류가 발생합니다. SavedFoodTruckRepository.java 파일의 해당 메서드를 먼저 수정해야 합니다.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java
around line 151, the call to
savedFoodTruckRepository.existsByMemberIdAndFoodTruckId(member.getUserId(),
foodTruckId) fails at runtime because SavedFoodTruckRepository has a
parameter-name mismatch bug; open
src/main/java/konkuk/chacall/domain/foodtruck/repository/SavedFoodTruckRepository.java,
fix the method signature/parameter names to match memberId and foodTruckId (and
any @Param annotations if using JPQL/Query), rebuild so the
existsByMemberIdAndFoodTruckId method accepts the correct parameters and the
runtime error is resolved.


return FoodTruckDetailResponse.from(foodTruck, foodTruckServiceAreas, availableDates, isSaved);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ public static AvailableDate createAvailableDate(LocalDate startDate, LocalDate e
.foodTruck(foodTruck)
.build();
}

public String formatDate() {
return startAt + " ~ " + endAt;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ public String getServiceAreas(List<FoodTruckServiceArea> serviceAreaList) {
.collect(Collectors.joining(", "));
}

// 푸드트럭의 운영 기간을 반환해주는 메서드
public List<String> getAvailableDates(List<AvailableDate> availableDateList) {
return availableDateList.stream()
.map(AvailableDate::formatDate)
.collect(Collectors.toList());
}

public void changeViewedStatus(FoodTruckViewedStatus targetViewedStatus) {
if(this.foodTruckViewedStatus == targetViewedStatus) {
throw new DomainRuleException(ErrorCode.INVALID_FOOD_TRUCK_STATUS_TRANSITION);
Expand All @@ -155,4 +162,16 @@ public void changeViewedStatus(FoodTruckViewedStatus targetViewedStatus) {

this.foodTruckViewedStatus = targetViewedStatus;
}

public void validateViewableStatusForMember() {
if (this.foodTruckViewedStatus != FoodTruckViewedStatus.ON) {
throw new DomainRuleException(ErrorCode.FOOD_TRUCK_NOT_VIEWABLE);
}
}

public void vaildateViewableStatusForOwner(Long userId) {
if(!isOwnedBy(userId)) { // 자신이 소유한 푸드트럭이 아니면
validateViewableStatusForMember();
}
}
Comment on lines +166 to +176
Copy link
Contributor

Choose a reason for hiding this comment

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

검증 로직 따로 뺀 것 좋습니다~

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface AvailableDateRepository extends JpaRepository<AvailableDate, Long> {

@Modifying
@Query("DELETE FROM AvailableDate ad WHERE ad.foodTruck.foodTruckId = :foodTruckId")
void deleteAllByFoodTruckId(@Param("foodTruckId") Long foodTruckId);

@Query("SELECT ad FROM AvailableDate ad WHERE ad.foodTruck.foodTruckId = :foodTruckId")
List<AvailableDate> findAllByFoodTruckId(Long foodTruckId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,18 @@ public BaseResponse<Void> deleteFoodTruckImagesFromS3(
return BaseResponse.ok(null);
}

@Operation(
summary = "푸드트럭 상세조회",
description = "푸드트럭의 상세 정보를 조회합니다."
)
@ExceptionDescription(SwaggerResponseDescription.GET_FOOD_TRUCK_DETAILS)
@GetMapping("/{foodTruckId}/details")
Copy link
Contributor

Choose a reason for hiding this comment

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

푸드트럭 상세 조회 API 의 경우 그냥 /food-trucks/{foodTruckId} 로 엔드포인트를 설정해둬 괜찮을 것 같다는 생각이 드는데 어떠신가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 엔드포인트 간소화시키는게 추후에 더 좋을 것 같네요. 수정하겠습니다~

public BaseResponse<FoodTruckDetailResponse> getFoodTruckDetails(
@Parameter(description = "푸드트럭 ID", example = "1") @PathVariable final Long foodTruckId,
@Parameter(hidden = true) @UserId final Long memberId
) {
return BaseResponse.ok(foodTruckService.getFoodTruckDetails(memberId, foodTruckId));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package konkuk.chacall.domain.foodtruck.presentation.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import konkuk.chacall.domain.foodtruck.domain.model.AvailableDate;
import konkuk.chacall.domain.foodtruck.domain.model.FoodTruck;
import konkuk.chacall.domain.foodtruck.domain.model.FoodTruckServiceArea;
import konkuk.chacall.domain.foodtruck.domain.value.FoodTruckInfo;

import java.util.List;

public record FoodTruckDetailResponse(
@Schema(description = "푸드트럭 식별자", example = "1")
Long foodTruckId,
@Schema(description = "푸드트럭 이름", example = "푸드트럭")
String name,
@Schema(description = "푸드트럭 설명", example = "맛있는 푸드트럭입니다.")
String description,
@Schema(description = "푸드트럭 전화번호", example = "010-1234-5678")
String phoneNumber,
@Schema(description = "푸드트럭 활동 시간", example = "09:00-20:00")
String activeTime,
@Schema(description = "시간 협의 필요 여부", example = "false")
Boolean timeDiscussRequired,
@Schema(description = "호출 가능 지역", example = "서울 광진구, 서울 강남구, 서울 영등포구")
String serviceAreas,
@Schema(description = "푸드트럭 메뉴 카테고리 (라벨 리스트)", example = "[\"한식\",\"분식\"]")
List<String> menuCategories,
@Schema(description = "푸드트럭 제공 가능 수량", example = "200인분 미만")
String availableQuantity,
@Schema(description = "전기 사용 필요 여부", example = "필요")
String needElectricity,
@Schema(description = "결제 방법", example = "무관")
String paymentMethod,
@Schema(description = "푸드트럭 제공 가능 날짜 리스트", example = "[\"2025-10-01 ~ 2025-10-10\",\"2025-11-01 ~ 2025-11-10\"]")
List<String> availableDates,
@Schema(description = "푸드트럭 사진 URL 리스트", example = "[\"http://image.png\",\"http://image2.png\",\"http://image3.png\"]")
List<String> photoUrl,
@Schema(description = "운영 정보", example = "운영정보")
String operatingInfo,
@Schema(description = "추가 옵션 정보", example = "안녕하세요")
String option,
@Schema(description = "푸드트럭 평균 평점", example = "4.5")
Double averageRating,
@Schema(description = "현재 사용자가 저장한 푸드트럭인지 여부", example = "true")
Boolean isSaved
) {
public static FoodTruckDetailResponse from(FoodTruck foodTruck, List<FoodTruckServiceArea> serviceAreas, List<AvailableDate> availableDates, Boolean isSaved) {
FoodTruckInfo foodTruckInfo = foodTruck.getFoodTruckInfo();
return new FoodTruckDetailResponse(
foodTruck.getFoodTruckId(),
foodTruckInfo.getName(),
foodTruckInfo.getDescription(),
foodTruckInfo.getPhoneNumber(),
foodTruckInfo.getActiveTime(),
foodTruckInfo.getTimeDiscussRequired(),
foodTruck.getServiceAreas(serviceAreas),
foodTruckInfo.getMenuCategoryList().getMenuCategoryLabelList(),
foodTruckInfo.getAvailableQuantity().getValue(),
foodTruckInfo.getNeedElectricity().getValue(),
foodTruckInfo.getPaymentMethod().getValue(),
foodTruck.getAvailableDates(availableDates),
foodTruckInfo.getFoodTruckPhotoList().getUrls(),
foodTruckInfo.getOperatingInfo(),
foodTruckInfo.getOption(),
foodTruck.getRatingInfo().getAverageRating(),
isSaved
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,13 @@ Slice<SavedFoodTruck> findMemberSavedFoodTruckWithCursor(
Set<Long> findSavedTruckIdsIn(@Param("userId") Long userId,
@Param("foodTruckIds") List<Long> foodTruckIds);

@Query("""
select exists (
select s
from SavedFoodTruck s
where s.member.userId = :memberId
and s.foodTruck.foodTruckId = :foodTruckId
)
""")
boolean existsByMemberIdAndFoodTruckId(Long userId, Long foodTruckId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public enum ErrorCode implements ResponseCode {
AVAILABLE_QUANTITY_MISMATCH(HttpStatus.BAD_REQUEST, 110007, "제조 가능 수량 값이 올바르지 않습니다."),
NEED_ELECTRICITY_MISMATCH(HttpStatus.BAD_REQUEST, 110008, "전기 사용 여부 값이 올바르지 않습니다."),
PAYMENT_METHOD_MISMATCH(HttpStatus.BAD_REQUEST, 110009, "결제 수단 값이 올바르지 않습니다."),
FOOD_TRUCK_NOT_VIEWABLE(HttpStatus.FORBIDDEN, 110010, "노출 가능한 상태의 푸드트럭이 아닙니다."),

/**
* Image
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ public enum SwaggerResponseDescription {
FOOD_TRUCK_NOT_FOUND,
FOOD_TRUCK_NOT_OWNED
))),
GET_FOOD_TRUCK_DETAILS(new LinkedHashSet<>(Set.of(
USER_NOT_FOUND,
USER_FORBIDDEN,
FOOD_TRUCK_NOT_FOUND,
FOOD_TRUCK_NOT_OWNED,
FOOD_TRUCK_NOT_VIEWABLE
))),

// Default
DEFAULT(new LinkedHashSet<>())
Expand Down