diff --git a/src/main/java/com/kau/capstone/entity/food/Food.java b/src/main/java/com/kau/capstone/entity/food/Food.java index 6cfa290..3211fa2 100644 --- a/src/main/java/com/kau/capstone/entity/food/Food.java +++ b/src/main/java/com/kau/capstone/entity/food/Food.java @@ -13,11 +13,8 @@ @Entity @Getter -@Builder -@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Food { - @Id @Comment("강아지 사료 식별자") @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -30,5 +27,11 @@ public class Food { private String imageUrl; @Comment("사료 가격") - private Long price; + private long price; + + private Food(String name, String imageUrl, Long price) { + this.name = name; + this.imageUrl = imageUrl; + this.price = price; + } } diff --git a/src/main/java/com/kau/capstone/entity/food/repository/FoodRepository.java b/src/main/java/com/kau/capstone/entity/food/repository/FoodRepository.java index f1f1960..66543e9 100644 --- a/src/main/java/com/kau/capstone/entity/food/repository/FoodRepository.java +++ b/src/main/java/com/kau/capstone/entity/food/repository/FoodRepository.java @@ -1,7 +1,12 @@ package com.kau.capstone.entity.food.repository; import com.kau.capstone.entity.food.Food; +import com.kau.capstone.v2.food.exception.FoodNotFoundExceptionV2; +import lombok.NonNull; import org.springframework.data.jpa.repository.JpaRepository; public interface FoodRepository extends JpaRepository { + default @NonNull Food getById(@NonNull Long id){ + return findById(id).orElseThrow(FoodNotFoundExceptionV2::new); + } } diff --git a/src/main/java/com/kau/capstone/entity/member/repository/MemberRepository.java b/src/main/java/com/kau/capstone/entity/member/repository/MemberRepository.java index 104d992..57bccf9 100644 --- a/src/main/java/com/kau/capstone/entity/member/repository/MemberRepository.java +++ b/src/main/java/com/kau/capstone/entity/member/repository/MemberRepository.java @@ -2,7 +2,6 @@ import com.kau.capstone.entity.member.Member; import com.kau.capstone.v1.member.exception.MemberNotFoundException; -import java.util.Optional; import lombok.NonNull; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; diff --git a/src/main/java/com/kau/capstone/entity/point/History.java b/src/main/java/com/kau/capstone/entity/point/History.java index a89f069..610a590 100644 --- a/src/main/java/com/kau/capstone/entity/point/History.java +++ b/src/main/java/com/kau/capstone/entity/point/History.java @@ -51,6 +51,9 @@ private History(Point point, Long totalPoint, Long changePoint, String name) { this.name = name; } + public static History of(Point point, Long changePoint, String name) { + return new History(point, point.getAmount(), changePoint, name); + } public static History of(Point point, PayPointReqV2 req, PointType type) { return new History(point, point.getAmount(), -req.point(), type.description); } diff --git a/src/main/java/com/kau/capstone/initial/FoodInitializer.java b/src/main/java/com/kau/capstone/initial/FoodInitializer.java index c0d2986..5750b53 100644 --- a/src/main/java/com/kau/capstone/initial/FoodInitializer.java +++ b/src/main/java/com/kau/capstone/initial/FoodInitializer.java @@ -16,28 +16,28 @@ public class FoodInitializer { private final FoodRepository foodRepository; - @PostConstruct - public void init() { - // 사료 이미지 추가 - var food1 = create("시저 성견용 연어맛이 곁들여진 쇠고기 건식 사료", 8500L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2256824262381067-6cbaab6b-0381-4ac1-bb4d-e3cde73a8020.jpg"); - var food2 = create("지니펫 유기농&활기찬일상 강아지사료 항산화 건식사료, 닭", 22000L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/1066056294989691-10dab58a-4aea-4dcb-9a3f-c082d31b0d7f.jpg"); - var food3 = create("무마진 강아지 전연령용 소프트사료, 연어", 14900L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2791828730297325-4999e7fd-60dd-4c19-89c5-6e39a985641d.png"); - var food4 = create("버틀러 3개월령 이상 더텐 소프트 밀웜 소프트사료, 오리", 21000L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2268100251879690-7d94cf09-07d9-4cf7-b8c8-4951bdecc6e4.png"); - var food5 = create("소프트플러스 전연령 참 좋은 황태 강아지 소프트사료, 연어", 11700L, "https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/vendor_inventory/b119/c157e5ee1c9140c28de31446550a9eb84c84ac3125a011f5631a17f500b0.jpg"); - var food6 = create("마이펫닥터 전연령 시그니처 티어스컨트롤 유기농 강아지사료, 눈물 개선/눈건강", 30000L, "https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/1072637633682648-fadc9cb3-f91f-41c9-99e7-ae611099246c.jpg"); - - save(food1, food2, food3, food4, food5, food6); - } - - private Food create(String name, Long price, String imageUrl) { - return Food.builder() - .name(name) - .price(price) - .imageUrl(imageUrl) - .build(); - } - - private void save(Food... foods) { - foodRepository.saveAll(Arrays.stream(foods).toList()); - } +// @PostConstruct +// public void init() { +// // 사료 이미지 추가 +// var food1 = create("시저 성견용 연어맛이 곁들여진 쇠고기 건식 사료", 8500L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2256824262381067-6cbaab6b-0381-4ac1-bb4d-e3cde73a8020.jpg"); +// var food2 = create("지니펫 유기농&활기찬일상 강아지사료 항산화 건식사료, 닭", 22000L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/1066056294989691-10dab58a-4aea-4dcb-9a3f-c082d31b0d7f.jpg"); +// var food3 = create("무마진 강아지 전연령용 소프트사료, 연어", 14900L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2791828730297325-4999e7fd-60dd-4c19-89c5-6e39a985641d.png"); +// var food4 = create("버틀러 3개월령 이상 더텐 소프트 밀웜 소프트사료, 오리", 21000L, "https://thumbnail10.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2268100251879690-7d94cf09-07d9-4cf7-b8c8-4951bdecc6e4.png"); +// var food5 = create("소프트플러스 전연령 참 좋은 황태 강아지 소프트사료, 연어", 11700L, "https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/vendor_inventory/b119/c157e5ee1c9140c28de31446550a9eb84c84ac3125a011f5631a17f500b0.jpg"); +// var food6 = create("마이펫닥터 전연령 시그니처 티어스컨트롤 유기농 강아지사료, 눈물 개선/눈건강", 30000L, "https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/1072637633682648-fadc9cb3-f91f-41c9-99e7-ae611099246c.jpg"); +// +// save(food1, food2, food3, food4, food5, food6); +// } +// +// private Food create(String name, Long price, String imageUrl) { +// return Food.builder() +// .name(name) +// .price(price) +// .imageUrl(imageUrl) +// .build(); +// } +// +// private void save(Food... foods) { +// foodRepository.saveAll(Arrays.stream(foods).toList()); +// } } diff --git a/src/main/java/com/kau/capstone/v1/food/dto/FoodResponse.java b/src/main/java/com/kau/capstone/v1/food/dto/FoodResponse.java index 0c82826..58ebdca 100644 --- a/src/main/java/com/kau/capstone/v1/food/dto/FoodResponse.java +++ b/src/main/java/com/kau/capstone/v1/food/dto/FoodResponse.java @@ -11,10 +11,10 @@ public record FoodResponse( ) { public static FoodResponse toResponse(Food food) { - return FoodResponse.builder() - .id(food.getId()) - .imageUrl(food.getImageUrl()) - .price(food.getPrice()) - .build(); + return new FoodResponse( + food.getId(), + food.getImageUrl(), + food.getPrice() + ); } } diff --git a/src/main/java/com/kau/capstone/v1/food/dto/FoodsResponse.java b/src/main/java/com/kau/capstone/v1/food/dto/FoodsResponse.java index 90d9661..e2b1974 100644 --- a/src/main/java/com/kau/capstone/v1/food/dto/FoodsResponse.java +++ b/src/main/java/com/kau/capstone/v1/food/dto/FoodsResponse.java @@ -15,8 +15,6 @@ public static FoodsResponse toResponse(List foods) { .map(FoodResponse::toResponse) .toList(); - return FoodsResponse.builder() - .foods(foodResponses) - .build(); + return new FoodsResponse(foodResponses); } } diff --git a/src/main/java/com/kau/capstone/v1/food/exception/FoodNotFoundException.java b/src/main/java/com/kau/capstone/v1/food/exception/FoodNotFoundException.java index d4955e5..0828dbe 100644 --- a/src/main/java/com/kau/capstone/v1/food/exception/FoodNotFoundException.java +++ b/src/main/java/com/kau/capstone/v1/food/exception/FoodNotFoundException.java @@ -1,11 +1,14 @@ package com.kau.capstone.v1.food.exception; +import com.kau.capstone._core.exception.ApiException; import com.kau.capstone.global.exception.ApplicationException; import com.kau.capstone.global.exception.ErrorCode; +import org.springframework.http.HttpStatus; -public class FoodNotFoundException extends ApplicationException { +public class FoodNotFoundException extends ApiException { + private static final String message = "해당 사료를 찾을 수 없습니다."; - public FoodNotFoundException(ErrorCode errorCode) { - super(errorCode); + public FoodNotFoundException() { + super(HttpStatus.NOT_FOUND, message); } } diff --git a/src/main/java/com/kau/capstone/v1/point/service/PointService.java b/src/main/java/com/kau/capstone/v1/point/service/PointService.java index 533fc73..ab3b2b5 100644 --- a/src/main/java/com/kau/capstone/v1/point/service/PointService.java +++ b/src/main/java/com/kau/capstone/v1/point/service/PointService.java @@ -78,8 +78,7 @@ public void processPointPaymentForFood(long memberId, Long foodId, Long delivery Member member = memberRepository.getById(memberId); Point point = member.getPoint(); - Food food = foodRepository.findById(foodId) - .orElseThrow(() -> new FoodNotFoundException(FOOD_NOT_FOUND)); + Food food = foodRepository.getById(foodId); Long totalPrice = food.getPrice() + deliveryFee; if (point.getAmount() < totalPrice) { diff --git a/src/main/java/com/kau/capstone/v2/food/controller/FoodControllerV2.java b/src/main/java/com/kau/capstone/v2/food/controller/FoodControllerV2.java new file mode 100644 index 0000000..438d38c --- /dev/null +++ b/src/main/java/com/kau/capstone/v2/food/controller/FoodControllerV2.java @@ -0,0 +1,35 @@ +package com.kau.capstone.v2.food.controller; + +import com.kau.capstone._core.dto.ApiResponse; +import com.kau.capstone.v1.auth.dto.LoginInfo; +import com.kau.capstone.v1.auth.util.LoginUser; +import com.kau.capstone.v1.point.dto.DeliveryFeeRequest; +import com.kau.capstone.v1.point.service.PointService; +import com.kau.capstone.v2.food.dto.response.FoodsResponseV2; +import com.kau.capstone.v2.food.service.FoodServiceV2; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +public class FoodControllerV2 { + private final FoodServiceV2 foodServiceV2; + private final PointService pointService; + + @GetMapping("/api/v2/foods") + public ResponseEntity> getFoodsInfo() { + FoodsResponseV2 response = foodServiceV2.getFoodsInfo(); + + return ApiResponse.ok(response); + } + + @PostMapping("/api/v2/foods/{foodId}/points/payment") + public ResponseEntity> payFoodWithPoints(@LoginUser LoginInfo loginInfo, + @PathVariable Long foodId, + @RequestBody DeliveryFeeRequest request) { + foodServiceV2.payFoodWithPoints(loginInfo.memberId(), foodId, request.deliveryFee()); + + return ApiResponse.ok(); + } +} diff --git a/src/main/java/com/kau/capstone/v2/food/dto/response/FoodResponseV2.java b/src/main/java/com/kau/capstone/v2/food/dto/response/FoodResponseV2.java new file mode 100644 index 0000000..70c0b8d --- /dev/null +++ b/src/main/java/com/kau/capstone/v2/food/dto/response/FoodResponseV2.java @@ -0,0 +1,18 @@ +package com.kau.capstone.v2.food.dto.response; + +import com.kau.capstone.entity.food.Food; + +public record FoodResponseV2( + Long id, + String imageUrl, + Long price +) { + + public static FoodResponseV2 of(Food food) { + return new FoodResponseV2( + food.getId(), + food.getImageUrl(), + food.getPrice() + ); + } +} diff --git a/src/main/java/com/kau/capstone/v2/food/dto/response/FoodsResponseV2.java b/src/main/java/com/kau/capstone/v2/food/dto/response/FoodsResponseV2.java new file mode 100644 index 0000000..bd406be --- /dev/null +++ b/src/main/java/com/kau/capstone/v2/food/dto/response/FoodsResponseV2.java @@ -0,0 +1,18 @@ +package com.kau.capstone.v2.food.dto.response; + +import com.kau.capstone.entity.food.Food; + +import java.util.List; + +public record FoodsResponseV2( + List foods +) { + + public static FoodsResponseV2 of(List foods) { + List foodResponses = foods.stream() + .map(FoodResponseV2::of) + .toList(); + + return new FoodsResponseV2(foodResponses); + } +} diff --git a/src/main/java/com/kau/capstone/v2/food/exception/FoodNotFoundExceptionV2.java b/src/main/java/com/kau/capstone/v2/food/exception/FoodNotFoundExceptionV2.java new file mode 100644 index 0000000..f4d79d2 --- /dev/null +++ b/src/main/java/com/kau/capstone/v2/food/exception/FoodNotFoundExceptionV2.java @@ -0,0 +1,12 @@ +package com.kau.capstone.v2.food.exception; + +import com.kau.capstone._core.exception.ApiException; +import org.springframework.http.HttpStatus; + +public class FoodNotFoundExceptionV2 extends ApiException { + private static final String message = "해당 사료를 찾을 수 없습니다."; + + public FoodNotFoundExceptionV2() { + super(HttpStatus.NOT_FOUND, message); + } +} diff --git a/src/main/java/com/kau/capstone/v2/food/service/FoodServiceV2.java b/src/main/java/com/kau/capstone/v2/food/service/FoodServiceV2.java new file mode 100644 index 0000000..3e98be4 --- /dev/null +++ b/src/main/java/com/kau/capstone/v2/food/service/FoodServiceV2.java @@ -0,0 +1,71 @@ +package com.kau.capstone.v2.food.service; + +import com.kau.capstone.entity.alarm.Alarm; +import com.kau.capstone.entity.alarm.AlarmDetail; +import com.kau.capstone.entity.alarm.repository.AlarmRepository; +import com.kau.capstone.entity.food.Food; +import com.kau.capstone.entity.food.repository.FoodRepository; +import com.kau.capstone.entity.member.Member; +import com.kau.capstone.entity.member.repository.MemberRepository; +import com.kau.capstone.entity.point.History; +import com.kau.capstone.entity.point.Point; +import com.kau.capstone.entity.point.repository.HistoryRepository; +import com.kau.capstone.entity.reward.Reward; +import com.kau.capstone.entity.reward.RewardDetail; +import com.kau.capstone.entity.reward.repository.RewardRepository; +import com.kau.capstone.v2.food.dto.response.FoodsResponseV2; +import com.kau.capstone.v2.point.exception.PointNotEnoughExceptionV2; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; + +@Service +@Transactional +@RequiredArgsConstructor +public class FoodServiceV2 { + + private final FoodRepository foodRepository; + private final MemberRepository memberRepository; + private final RewardRepository rewardRepository; + private final AlarmRepository alarmRepository; + private final HistoryRepository historyRepository; + + public FoodsResponseV2 getFoodsInfo() { + List foods = foodRepository.findAll(); + + return FoodsResponseV2.of(foods); + } + + public void payFoodWithPoints(Long memberId, Long foodId, Long deliveryFee) { + Member member = memberRepository.getById(memberId); + Point point = member.getPoint(); + + Food food = foodRepository.getById(foodId); + long totalPrice = food.getPrice() + deliveryFee; + + checkAmount(point.getAmount(), totalPrice); + + point.payment(totalPrice); + History history = History.of(point, -totalPrice, food.getName()); + historyRepository.save(history); + + Reward reward = rewardRepository.findRewardByMemberAndType(member, RewardDetail.THREE.type()); + if (!Objects.isNull(reward) && !reward.getIsAchieved()) { + reward.achievedSuccess(); + } + + Alarm alarm = alarmRepository.findAlarmByMemberAndType(member, AlarmDetail.ONE.type()); + if (!Objects.isNull(alarm) && alarm.getIsVisible()) { + alarm.doNotVisible(); + } + } + + private void checkAmount(long amount, long point){ + if (amount < point) { + throw new PointNotEnoughExceptionV2(); + } + } +} diff --git a/src/test/java/com/kau/capstone/domain/food/controller/FoodControllerTest.java b/src/test/java/com/kau/capstone/domain/food/controller/FoodControllerTest.java index 4e49913..7aa7dd4 100644 --- a/src/test/java/com/kau/capstone/domain/food/controller/FoodControllerTest.java +++ b/src/test/java/com/kau/capstone/domain/food/controller/FoodControllerTest.java @@ -1,6 +1,6 @@ //package com.kau.capstone.domain.food.controller; // -//import com.kau.capstone.v1.food.dto.FoodsResponse; +//import com.kau.capstone.v1.food.dto.FoodsResponseV2; //import com.kau.capstone.entity.food.Food; //import com.kau.capstone.entity.member.Member; //import com.kau.capstone.v1.point.dto.DeliveryFeeRequest; @@ -51,7 +51,7 @@ // .get("/api/v1/foods") // .then() // .extract(); -// FoodsResponse response = res.jsonPath().getObject("", FoodsResponse.class); +// FoodsResponseV2 response = res.jsonPath().getObject("", FoodsResponseV2.class); // // // then // assertSoftly(soft -> {