diff --git a/backend/src/main/java/com/example/todoapp/config/InitTables.java b/backend/src/main/java/com/example/todoapp/config/InitTables.java new file mode 100644 index 0000000..413f9f2 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/config/InitTables.java @@ -0,0 +1,133 @@ +//-------------------------------- +// InitTables.java +// +// 更新履歴:2025/06/10 新規作成 +// Copyright(c) 2025 IVIS All rights reserved. +// +// Tobuys, Stocks, Stuffs, Recipes, RecipeStuffsを起動時に初期化するクラス +// +//-------------------------------------------- + +package com.example.todoapp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import jakarta.annotation.PostConstruct; + +import com.example.todoapp.model.ToBuys; +import com.example.todoapp.repository.ToBuysRepository; +import com.example.todoapp.model.Stocks; +import com.example.todoapp.repository.StocksRepository; +import com.example.todoapp.model.Recipes; +import com.example.todoapp.repository.RecipesRepository; +import com.example.todoapp.model.RecipeStuffs; +import com.example.todoapp.repository.RecipeStuffsRepository; +import com.example.todoapp.model.Stuffs; +import com.example.todoapp.repository.StuffsRepository; + +@Configuration +public class InitTables { + + @Autowired + private ToBuysRepository tobuysRepository; + @Autowired + private StocksRepository stocksRepository; + @Autowired + private RecipesRepository recipesRepository; + @Autowired + private RecipeStuffsRepository recipeStuffsRepository; + @Autowired + private StuffsRepository stuffsRepository; + + @PostConstruct + public void initTables() { + + // tobuysRepository.deleteAll(); //データを残す場合はコメントアウト + // stocksRepository.deleteAll(); //データを残す場合はコメントアウト + // recipeStuffsRepository.deleteAll(); //データを残す場合はコメントアウト + // recipesRepository.deleteAll(); //データを残す場合はコメントアウト + // stuffsRepository.deleteAll(); //データを残す場合はコメントアウト + + if (stuffsRepository.count() > 0) { + return; // すでにデータが存在する場合は何もしない + + } else { + setNewStuff(1L, "牛乳", null, "乳製品"); + setNewStuff(2L, "ヨーグルト", null, "乳製品"); + setNewStuff(3L, "チーズ", null, "乳製品"); + setNewStuff(4L, "バター", null, "乳製品"); + setNewStuff(5L, "生クリーム", null, "乳製品"); + + setNewStuff(6L, "鮭", null, "魚・肉"); + setNewStuff(7L, "鶏むね肉", null, "魚・肉"); + setNewStuff(8L, "豚バラ肉", null, "魚・肉"); + setNewStuff(9L, "牛ひき肉", null, "魚・肉"); + setNewStuff(10L, "まぐろ", null, "魚・肉"); + + setNewStuff(11L, "にんじん", null, "野菜"); + setNewStuff(12L, "キャベツ", null, "野菜"); + setNewStuff(13L, "ほうれん草", null, "野菜"); + setNewStuff(14L, "玉ねぎ", null, "野菜"); + setNewStuff(15L, "ピーマン", null, "野菜"); + setNewStuff(16L, "じゃがいも", null, "野菜"); + + + setNewStuff(17L, "醤油", null, "調味料"); + setNewStuff(18L, "味噌", null, "調味料"); + setNewStuff(19L, "塩", null, "調味料"); + setNewStuff(20L, "砂糖", null, "調味料"); + setNewStuff(21L, "酢", null, "調味料"); + + setNewStuff(22L, "米", null, "その他"); + setNewStuff(23L, "パスタ", null, "その他"); + setNewStuff(24L, "小麦粉", null, "その他"); + setNewStuff(25L, "卵", null, "その他"); + setNewStuff(26L, "豆腐", null, "その他"); + } + + if (stuffsRepository.count() > 0) { + return; // すでにデータが存在する場合は何もしない + } else { + setNewRecipe(1L, "鮭のムニエル", "鮭を小麦粉で焼いた料理"); + setNewRecipe(2L, "カレー", "野菜と肉を煮込んだカレー"); + } + + if (recipesRepository.count() > 0) { + return; // すでにデータが存在する場合は何もしない + } else { + setNewRecipeStuffs(1L, recipesRepository.findById(1L).orElse(null), 6L, 1); // 鮭 + setNewRecipeStuffs(3L, recipesRepository.findById(1L).orElse(null), 17L, 10); // 醤油 + setNewRecipeStuffs(2L, recipesRepository.findById(1L).orElse(null), 24L, 50); // 小麦粉 + setNewRecipeStuffs(4L, recipesRepository.findById(2L).orElse(null), 11L, 1); // にんじん + setNewRecipeStuffs(5L, recipesRepository.findById(2L).orElse(null), 16L, 1); // じゃがいも + setNewRecipeStuffs(6L, recipesRepository.findById(2L).orElse(null), 9L, 100); // 牛ひき肉 + } + + } + + private void setNewStuff(Long stuffId, String stuffName, String summary, String category) { + Stuffs stuff = new Stuffs(); + stuff.setStuffId(stuffId); + stuff.setStuffName(stuffName); + stuff.setSummary(summary); + stuff.setCategory(category); + stuffsRepository.save(stuff); + } + + private void setNewRecipe(Long recipeId, String recipeName, String summary) { + Recipes recipe = new Recipes(); + recipe.setRecipeId(recipeId); + recipe.setRecipeName(recipeName); + recipe.setSummary(summary); + } + + private void setNewRecipeStuffs(Long recipeStuffsId, Recipes recipe, Long stuffId, int amount) { + RecipeStuffs recipeStuff = new RecipeStuffs(); + recipeStuff.setRecipeStuffsId(recipeStuffsId); + recipeStuff.setRecipes(recipe); + recipeStuff.setRecipeStuffsId(stuffId); + recipeStuff.setAmount(amount); + recipeStuffsRepository.save(recipeStuff); + } +} diff --git a/backend/src/main/java/com/example/todoapp/controller/RecipesController.java b/backend/src/main/java/com/example/todoapp/controller/RecipesController.java new file mode 100644 index 0000000..b2f97ab --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/controller/RecipesController.java @@ -0,0 +1,116 @@ +package com.example.todoapp.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.example.todoapp.dto.RecipeDetailDTO; +import com.example.todoapp.dto.RecipeRequestDTO; +import com.example.todoapp.dto.RecipeResponseDTO; +import com.example.todoapp.model.Recipes; +import com.example.todoapp.service.RecipeService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 料理レシピ管理のコントローラー + *

+ * このコントローラーはレシピの取得、作成、更新、削除などの + * エンドポイントを提供します。すべてのエンドポイントは認証が必要です。 + *

+ */ +@RestController +@RequestMapping("/recipes") +public class RecipesController { + + @Autowired + private RecipeService recipeService; + + /** + * 新しいレシピを作成する + * + * @param dto 作成するレシピの情報 + * @return 作成結果(recipeIdとメッセージを含む) + */ + @PostMapping("/add") + public ResponseEntity> addRecipe(@RequestBody RecipeRequestDTO dto) { + Recipes createAllReipes = recipeService.addRecipe(dto); + + Map response = new HashMap<>(); + response.put("result", true); + response.put("recipeId", createAllReipes.getRecipeId()); + response.put("message", "追加に成功しました"); + + return ResponseEntity.ok(response); + } + + /** + * すべてのレシピを取得する + * + * @param authentication 認証情報 + * @return レシピ情報リスト + */ + @GetMapping("/getAll") + public ResponseEntity> getRecipe(Authentication authentication) { + List recipes = recipeService.getAllRecipes(); + // エンティティからDTOへの変換 + List responseList = recipes.stream() + .map(recipe -> { + RecipeResponseDTO dto = new RecipeResponseDTO(); + dto.setRecipeId(recipe.getRecipeId()); + dto.setRecipeName(recipe.getRecipeName()); + dto.setSummary(recipe.getSummary()); + return dto; + }) + .collect(Collectors.toList()); + return ResponseEntity.ok(responseList); + } + + /** + * 指定されたIDの在庫を取得する + * + * @param authentication 認証情報 + * @param recipeId 在庫ID + * @return 在庫情報 + */ + @GetMapping("/getById") + public ResponseEntity getRecipeById( + Authentication authentication, + @RequestParam Long recipeId) { + recipeService.getRecipeDetailsById(recipeId); + return ResponseEntity.ok(recipeService.getRecipeDetailsById(recipeId)); + } + + /** + * レシピ情報を更新する + * + * @param dto 更新するレシピの詳細情報 + * @return 更新結果(成功/失敗メッセージを含む) + */ + @PutMapping("/update") + public ResponseEntity> updateRecipe(@RequestBody RecipeDetailDTO dto) { + Recipes recipes = recipeService.updateRecipe(dto); + Map response = new HashMap<>(); + + if (recipes != null) { + response.put("result",true ); + response.put("message", "料理リストの編集が完了しました"); + } else { + response.put("result", false); + response.put("message", "編集に失敗しました"); + + } + return ResponseEntity.ok(response); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/controller/StocksController.java b/backend/src/main/java/com/example/todoapp/controller/StocksController.java index cdced2e..932f450 100644 --- a/backend/src/main/java/com/example/todoapp/controller/StocksController.java +++ b/backend/src/main/java/com/example/todoapp/controller/StocksController.java @@ -1,10 +1,13 @@ package com.example.todoapp.controller; import com.example.todoapp.dto.DeleteStockRequest; -import com.example.todoapp.dto.ResponseStockDTO; +import com.example.todoapp.dto.DeleteStockRequestDTO; +import com.example.todoapp.dto.StockResponseDTO; import com.example.todoapp.dto.StockDTO; import com.example.todoapp.dto.UpdateStockRequest; import com.example.todoapp.model.Stocks; +import com.example.todoapp.model.User; +import com.example.todoapp.repository.UserRepository; import com.example.todoapp.service.StocksService; import jakarta.validation.Valid; import lombok.Data; @@ -12,8 +15,8 @@ import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.*; -import lombok.Data; import java.util.HashMap; import java.util.List; @@ -34,6 +37,9 @@ public class StocksController { @Autowired private StocksService stockService; + @Autowired + private UserRepository userRepository; + /** * ログインユーザーのすべての在庫を取得する * @@ -41,11 +47,11 @@ public class StocksController { * @return ユーザーの在庫リスト */ @GetMapping("/get") - public ResponseEntity> getAllStocks(Authentication authentication) { + public ResponseEntity> getAllStocks(Authentication authentication) { List stocks = stockService.getALLStocksByUser(authentication.getName()); // エンティティからDTOへの変換 - List stockDTOs = stocks.stream() - .map(ResponseStockDTO::fromEntity) + List stockDTOs = stocks.stream() + .map(StockResponseDTO::fromEntity) .collect(Collectors.toList()); return ResponseEntity.ok(stockDTOs); } @@ -91,12 +97,21 @@ public class StocksController { @PutMapping("/update") public ResponseEntity> updateStock( Authentication authentication, - @Valid @RequestBody UpdateStockRequest stockDetails) { - - stockService.updateStocks(authentication.getName(), stockDetails); + @Valid @RequestBody UpdateStockRequest updateStockRequest) { + + Stocks updatedStock = stockService.updateStocks(authentication.getName(), updateStockRequest); Map response = new HashMap<>(); - response.put("result", true); + + if (updatedStock == null) { + response.put("result", false); + response.put("message", "指定されたIDの在庫が見つかりませんでした"); + return ResponseEntity.ok(response); + }else { + response.put("result", true); + response.put("message", "变更成功しました"); + } + return ResponseEntity.ok(response); } @@ -108,13 +123,30 @@ public class StocksController { * @return レスポンス */ @DeleteMapping("/delete") - public ResponseEntity> deleteStock( + public ResponseEntity deleteStock( Authentication authentication, - @Valid @RequestBody DeleteStockRequest request) { - stockService.deleteStock(authentication.getName(), request.getStockId()); + @RequestBody DeleteStockRequestDTO request + ) { + + // 認証されたユーザー名を取得 + String username = authentication.getName(); + + // ユーザー情報を取得 + User user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("User not found")); + int deletedCount = stockService.deleteStockById(user.getId(), request.getStockId()); + Map response = new HashMap<>(); - response.put("result", true); + + if (deletedCount > 0) { + response.put("result", true); + response.put("message", "削除成功しました"); + } else { + response.put("result", false); + response.put("message", "指定された在庫が見つかりませんでした"); + } + return ResponseEntity.ok(response); } } \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/controller/ToBuysController.java b/backend/src/main/java/com/example/todoapp/controller/ToBuysController.java index d1ab6f9..1b4b919 100644 --- a/backend/src/main/java/com/example/todoapp/controller/ToBuysController.java +++ b/backend/src/main/java/com/example/todoapp/controller/ToBuysController.java @@ -8,14 +8,13 @@ package com.example.todoapp.controller; import com.example.todoapp.dto.BuyRequestDTO; -import com.example.todoapp.dto.DeleteToBuyRequest; -import com.example.todoapp.dto.ToBuyResponse; +import com.example.todoapp.dto.DeleteToBuyRequestDTO; +import com.example.todoapp.dto.ToBuyResponseDTO; import com.example.todoapp.dto.ToBuysDTO; import com.example.todoapp.model.Stuffs; import com.example.todoapp.model.ToBuys; import com.example.todoapp.model.User; import com.example.todoapp.repository.UserRepository; -import com.example.todoapp.repository.StuffsRepository; import com.example.todoapp.service.ToBuysService; import jakarta.validation.Valid; @@ -23,7 +22,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import java.util.Collections; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -62,7 +60,6 @@ public class ToBuysController { ToBuys createdToBuy = toBuysService.addToBuys(dto, authentication); - // 构建响应体 Map response = new HashMap<>(); response.put("result", true); response.put("tobuyId", createdToBuy.getTobuyId()); @@ -72,6 +69,13 @@ public class ToBuysController { return ResponseEntity.ok(response); } + /** + * 指定されたIDの在庫を更新する + * + * @param authentication 認証情報 + * @param dto 更新内容 + * @return 更新された + */ @PutMapping("/update") public ResponseEntity> updateToBuys( @Valid @RequestBody ToBuysDTO dto, @@ -80,7 +84,6 @@ public class ToBuysController { ToBuys updatedToBuy = toBuysService.updateToBuys(dto, authentication); - Map response = new HashMap<>(); response.put("tobuyId", updatedToBuy.getTobuyId()); response.put("stuffId", updatedToBuy.getStuff().getStuffId()); @@ -109,9 +112,9 @@ public class ToBuysController { List toBuysList = toBuysService.getToBuysByUser(user); // DTO形式に変換して返す - List responseList = toBuysList.stream() + List responseList = toBuysList.stream() .map(toBuy -> { - ToBuyResponse resp = new ToBuyResponse(); + ToBuyResponseDTO resp = new ToBuyResponseDTO(); Stuffs stuff = toBuy.getStuff(); resp.setTobuyId(toBuy.getTobuyId()); resp.setStuffId(stuff.getStuffId()); @@ -136,7 +139,7 @@ public class ToBuysController { */ @DeleteMapping("/delete") public ResponseEntity> deleteToBuy( - @RequestBody DeleteToBuyRequest request, + @RequestBody DeleteToBuyRequestDTO request, Authentication authentication) { int deletedCount = toBuysService.deleteToBuyById(request.getTobuyId()); diff --git a/backend/src/main/java/com/example/todoapp/dto/BuyRequestDTO.java b/backend/src/main/java/com/example/todoapp/dto/BuyRequestDTO.java index 38438f9..f0e2ba5 100644 --- a/backend/src/main/java/com/example/todoapp/dto/BuyRequestDTO.java +++ b/backend/src/main/java/com/example/todoapp/dto/BuyRequestDTO.java @@ -4,11 +4,42 @@ import java.time.LocalDate; import lombok.Data; +/** + * 購入情報更新のデータ転送オブジェクト(DTO) + *

+ * このクラスは既存の購入予定情報を更新するために使用されます。 + * 更新に必要な全情報を含みます。 + *

+ */ @Data public class BuyRequestDTO { + /** + * 購入ID + * 更新対象の購入予定を識別します + */ private Long tobuyId; + + /** + * 価格 + * 実際の購入金額を設定します + */ private int price; + + /** + * 消費期限 + * 食材の消費期限を設定します + */ private LocalDate expDate; + + /** + * 最終更新日 + * レコードの最終更新日時を保持します + */ private LocalDate lastUpdate; + + /** + * 購入日 + * 食材の実際の購入日を設定します + */ private LocalDate buyDate; } \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/DeleteStockRequestDTO.java b/backend/src/main/java/com/example/todoapp/dto/DeleteStockRequestDTO.java new file mode 100644 index 0000000..cede4a2 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/DeleteStockRequestDTO.java @@ -0,0 +1,19 @@ +package com.example.todoapp.dto; + +import lombok.Data; + +/** + * 在庫削除要求のデータ転送オブジェクト(DTO) + *

+ * このクラスは在庫削除操作をサーバーに送信するために使用されます。 + * 削除対象を特定するための情報を含みます。 + *

+ */ +@Data +public class DeleteStockRequestDTO { + /** + * 在庫ID + * 削除対象の在庫を識別するためのID + */ + private Long stockId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequest.java b/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequest.java deleted file mode 100644 index 07b2a37..0000000 --- a/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequest.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.todoapp.dto; - -import lombok.Data; - -@Data -public class DeleteToBuyRequest { - private Long userId; - private Long tobuyId; -} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequestDTO.java b/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequestDTO.java new file mode 100644 index 0000000..8929f08 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/DeleteToBuyRequestDTO.java @@ -0,0 +1,25 @@ +package com.example.todoapp.dto; + +import lombok.Data; + +/** + * 購入予定削除要求のデータ転送オブジェクト(DTO) + *

+ * このクラスは購入予定情報の削除要求をサーバーに送信するために使用されます。 + * 削除対象を特定するための必要情報を含みます。 + *

+ */ +@Data +public class DeleteToBuyRequestDTO { + /** + * ユーザーID + * 操作対象のユーザーを識別するためのID + */ + private Long userId; + + /** + * 購入予定ID + * 削除対象の購入予定情報を識別するためのID + */ + private Long tobuyId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/RecipeDetailDTO.java b/backend/src/main/java/com/example/todoapp/dto/RecipeDetailDTO.java new file mode 100644 index 0000000..9702ebd --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/RecipeDetailDTO.java @@ -0,0 +1,39 @@ +package com.example.todoapp.dto; + +import java.util.List; + +import lombok.Data; + +/** + * レシピ詳細情報のデータ転送オブジェクト(DTO) + *

+ * このクラスはレシピの詳細情報を伝送するために使用されます。 + * レシピ基本情報に加えて関連食材情報を含みます。 + *

+ */ +@Data +public class RecipeDetailDTO { + /** + * レシピID + * ユニークなレシピを識別するためのID + */ + private Long recipeId; + + /** + * レシピ名 + * レシピの名称を表します + */ + private String recipeName; + + /** + * 概要 + * レシピの簡単な説明文 + */ + private String summary; + + /** + * 食材リスト + * このレシピに必要な食材とその数量のリスト + */ + private List stuffs; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/RecipeRequestDTO.java b/backend/src/main/java/com/example/todoapp/dto/RecipeRequestDTO.java new file mode 100644 index 0000000..9cd0a77 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/RecipeRequestDTO.java @@ -0,0 +1,39 @@ +package com.example.todoapp.dto; + +import java.util.List; + +import lombok.Data; + +/** + * レシピ操作要求のデータ転送オブジェクト(DTO) + *

+ * このクラスはレシピ操作要求をサーバーに送信するために使用されます。 + * 新規作成および更新時の情報を含みます。 + *

+ */ +@Data +public class RecipeRequestDTO { + /** + * レシピID + * 新規作成時は未指定、更新時は必須 + */ + private Long recipeId; + + /** + * レシピ名 + * レシピの名称を表します + */ + private String recipeName; + + /** + * 概要 + * レシピの簡単な説明文 + */ + private String summary; + + /** + * 食材と数量リスト + * このレシピに必要な食材とその数量のリスト + */ + private List stuffAndAmountArray; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/RecipeResponseDTO.java b/backend/src/main/java/com/example/todoapp/dto/RecipeResponseDTO.java new file mode 100644 index 0000000..38d69a3 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/RecipeResponseDTO.java @@ -0,0 +1,31 @@ +package com.example.todoapp.dto; + +import lombok.Data; + +/** + * レシピ情報のデータ転送オブジェクト(DTO) + *

+ * このクラスはクライアントとサーバー間で基本的なレシピ情報をやり取りするために使用されます。 + * エンティティとは異なり、必要な情報のみを含みます。 + *

+ */ +@Data +public class RecipeResponseDTO { + /** + * レシピID + * ユニークなレシピを識別するためのID + */ + private Long recipeId; + + /** + * レシピ名 + * レシピの名称を表します + */ + private String recipeName; + + /** + * 概要 + * レシピの簡単な説明文 + */ + private String summary; +} diff --git a/backend/src/main/java/com/example/todoapp/dto/ResponseStockDTO.java b/backend/src/main/java/com/example/todoapp/dto/StockResponseDTO.java similarity index 91% rename from backend/src/main/java/com/example/todoapp/dto/ResponseStockDTO.java rename to backend/src/main/java/com/example/todoapp/dto/StockResponseDTO.java index 1de5012..5098319 100644 --- a/backend/src/main/java/com/example/todoapp/dto/ResponseStockDTO.java +++ b/backend/src/main/java/com/example/todoapp/dto/StockResponseDTO.java @@ -16,7 +16,7 @@ import java.time.LocalDate; */ @Data -public class ResponseStockDTO { +public class StockResponseDTO { private Long stockId; private Long stuffId; private Long userId; @@ -34,8 +34,8 @@ public class ResponseStockDTO { * @param stock 変換元の在庫エンティティ * @return 変換されたStockDTOオブジェクト */ - public static ResponseStockDTO fromEntity(Stocks stock) { - ResponseStockDTO dto = new ResponseStockDTO(); + public static StockResponseDTO fromEntity(Stocks stock) { + StockResponseDTO dto = new StockResponseDTO(); Stuffs stuff = stock.getStuff(); dto.setStockId(stock.getStockId()); diff --git a/backend/src/main/java/com/example/todoapp/dto/StuffDetailDTO.java b/backend/src/main/java/com/example/todoapp/dto/StuffDetailDTO.java new file mode 100644 index 0000000..bf63d6d --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/StuffDetailDTO.java @@ -0,0 +1,30 @@ +package com.example.todoapp.dto; + +import lombok.Data; +/** + * 食材詳細情報のデータ転送オブジェクト(DTO) + *

+ * このクラスはレシピに含まれる個別食材情報を伝送するために使用されます。 + * 必要最小限の食材情報を含みます。 + *

+ */ +@Data +public class StuffDetailDTO { + /** + * 食材ID + * ユニークな食材を識別するためのID + */ + private Long stuffId; + + /** + * 食材名 + * 食材の名称を表します + */ + private String stuffName; + + /** + * 数量 + * レシピに必要な食材の量 + */ + private Integer amount; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/StuffRequestDTO.java b/backend/src/main/java/com/example/todoapp/dto/StuffRequestDTO.java new file mode 100644 index 0000000..65308fc --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/StuffRequestDTO.java @@ -0,0 +1,36 @@ +package com.example.todoapp.dto; +import lombok.Data; + +/** + * 食材操作要求のデータ転送オブジェクト(DTO) + *

+ * このクラスは食材操作要求をサーバーに送信するために使用されます。 + * 新規作成時の必須情報を含みます。 + *

+ */ +@Data +public class StuffRequestDTO { + /** + * 食材ID + * 新規作成時は未指定 + */ + private String stuffId; + + /** + * 食材名 + * 食材の名称を表します + */ + private String stuffName; + + /** + * カテゴリ + * 食材の分類を示します + */ + private String category; + + /** + * 数量 + * 食材の保有量を示します + */ + private String amount; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/ToBuyResponse.java b/backend/src/main/java/com/example/todoapp/dto/ToBuyResponse.java deleted file mode 100644 index 407ae91..0000000 --- a/backend/src/main/java/com/example/todoapp/dto/ToBuyResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.todoapp.dto; - -import lombok.Data; - -@Data -public class ToBuyResponse { - private Long tobuyId; - private Long stuffId; - private String stuffName; - private int amount; - private String shop; -} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/dto/ToBuyResponseDTO.java b/backend/src/main/java/com/example/todoapp/dto/ToBuyResponseDTO.java new file mode 100644 index 0000000..e45eae5 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/dto/ToBuyResponseDTO.java @@ -0,0 +1,44 @@ +package com.example.todoapp.dto; + +import lombok.Data; + +/** + * 購入予定情報のデータ転送オブジェクト(DTO) + *

+ * このクラスは購入予定食材情報をクライアントとサーバー間でやり取りするために使用されます。 + * 必要な情報を含み、関連エンティティへの参照ではなくIDのみを保持します。 + *

+ */ +@Data +public class ToBuyResponseDTO { + + /** + * 購入ID + * 購入予定を識別するためのID + */ + private Long tobuyId; + + /** + * 食材ID + * 関連する食材のID + */ + private Long stuffId; + + /** + * 食材名 + * 購入予定の食材名称 + */ + private String stuffName; + + /** + * 数量 + * 購入予定数量 + */ + private int amount; + + /** + * 購入先 + * 購入を予定している店舗名 + */ + private String shop; +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/model/RecipeStuffs.java b/backend/src/main/java/com/example/todoapp/model/RecipeStuffs.java index 74d5738..c21eb9a 100644 --- a/backend/src/main/java/com/example/todoapp/model/RecipeStuffs.java +++ b/backend/src/main/java/com/example/todoapp/model/RecipeStuffs.java @@ -1,5 +1,5 @@ //-------------------------------- -// RecipiesStuffs.java +// RecipesStuffs.java // // 分類:社員管理システムV2・ビジネスロジック層 // @@ -18,7 +18,7 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.NoArgsConstructor; @@ -43,7 +43,7 @@ public class RecipeStuffs { /** * 料理の一意識別子 FK */ - @NotBlank + @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( name = "recipeId", @@ -56,7 +56,7 @@ public class RecipeStuffs { /** * 材料の一意識別子 FK */ - @NotBlank + @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( name = "stuffId", @@ -68,8 +68,8 @@ public class RecipeStuffs { /** * 材料の数量(デフォルト1) */ - @NotBlank + @NotNull @Column(nullable = false) - private int amount = 1; + private Integer amount = 1; } diff --git a/backend/src/main/java/com/example/todoapp/model/Recipes.java b/backend/src/main/java/com/example/todoapp/model/Recipes.java index c4a986d..35a9b36 100644 --- a/backend/src/main/java/com/example/todoapp/model/Recipes.java +++ b/backend/src/main/java/com/example/todoapp/model/Recipes.java @@ -43,7 +43,7 @@ public class Recipes { */ @NotNull @Column(name="recipeName", unique = true, length = 255, nullable = false) - private String recipieName; + private String recipeName; /** * カテゴリ diff --git a/backend/src/main/java/com/example/todoapp/model/Stocks.java b/backend/src/main/java/com/example/todoapp/model/Stocks.java index 1b8ede7..c9c47b2 100644 --- a/backend/src/main/java/com/example/todoapp/model/Stocks.java +++ b/backend/src/main/java/com/example/todoapp/model/Stocks.java @@ -54,20 +54,7 @@ public class Stocks { ) private Stuffs stuff; - - // /** - // * ユーザーテーブル参照用の外部キー - // */ - // @NotNull - // @ManyToOne(fetch = FetchType.LAZY) - // @JoinColumn( - // name = "userId", - // referencedColumnName = "id", - // nullable = false - // ) - // private User user; - - /** + /** * タスクの所有者(ユーザー) * 多対一の関係で、遅延ロードを使用 */ diff --git a/backend/src/main/java/com/example/todoapp/repository/RecipeStuffsRepository.java b/backend/src/main/java/com/example/todoapp/repository/RecipeStuffsRepository.java new file mode 100644 index 0000000..a660f21 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/repository/RecipeStuffsRepository.java @@ -0,0 +1,33 @@ +//-------------------------------- +// RecipeStuffsRepository.java +// +// +// 更新履歴:2025/06/10 新規作成 +// Copyright(c) 2025 IVIS All rights reserved. +//-------------------------------------------- +package com.example.todoapp.repository; + +import com.example.todoapp.model.RecipeStuffs; + +import jakarta.transaction.Transactional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * 料理-材料エンティティのリポジトリインターフェース + *

+ * このインターフェースは料理-材料データへのアクセスと操作を提供します。 + * Spring Data JPAによって自動的に実装されます。 + *

+ */ + +@Repository +public interface RecipeStuffsRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/repository/RecipesRepository.java b/backend/src/main/java/com/example/todoapp/repository/RecipesRepository.java new file mode 100644 index 0000000..f1a039c --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/repository/RecipesRepository.java @@ -0,0 +1,14 @@ +package com.example.todoapp.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.example.todoapp.model.Recipes; + +/** + * レシピエンティティのリポジトリインターフェース + *

+ * このインターフェースはレシピデータへのアクセスと操作を提供します。 + * Spring Data JPAによって自動的に実装されます。 + *

+ */ +public interface RecipesRepository extends JpaRepository {} diff --git a/backend/src/main/java/com/example/todoapp/repository/RecipesStuffsRepository.java b/backend/src/main/java/com/example/todoapp/repository/RecipesStuffsRepository.java new file mode 100644 index 0000000..729b825 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/repository/RecipesStuffsRepository.java @@ -0,0 +1,37 @@ +package com.example.todoapp.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.example.todoapp.model.RecipeStuffs; + +/** + * レシピ食材関連データのリポジトリインターフェース + *

+ * このインターフェースはレシピと食材の関連データへのアクセスを提供します。 + * Spring Data JPAによって自動的に実装されます。 + *

+ */ +public interface RecipesStuffsRepository extends JpaRepository { + /** + * レシピIDで食材情報を検索する + * + * @param recipeId 検索するレシピID + * @return 関連する食材情報リスト + */ + List findByRecipesRecipeId(Long recipeId); + + /** + * レシピIDと食材IDで関連情報を検索する + * + * @param recipeId 検索するレシピID + * @param stuffId 検索する食材ID + * @return 関連情報(存在する場合) + */ + Optional findByRecipesRecipeIdAndStuffStuffId(Long recipeId, Long stuffId); +} + + + diff --git a/backend/src/main/java/com/example/todoapp/repository/StocksRepository.java b/backend/src/main/java/com/example/todoapp/repository/StocksRepository.java index 6e1cb5a..3a069d4 100644 --- a/backend/src/main/java/com/example/todoapp/repository/StocksRepository.java +++ b/backend/src/main/java/com/example/todoapp/repository/StocksRepository.java @@ -58,5 +58,10 @@ public interface StocksRepository extends JpaRepository { * @param stockId 削除する在庫 * @param userId 削除するユーザー */ - void deleteStocksByStockIdAndUserId(Long stockId, Long userId); + // void deleteStocksByStockIdAndUserId(Long stockId, Long userId); + + @Modifying + @Transactional + @Query("DELETE FROM Stocks t WHERE t.user.id = :userId AND t.stockId = :stockId") + int deleteByUserIdAndStockId(@Param("userId") Long userId, @Param("stockId") Long stockId); } \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/service/RecipeService.java b/backend/src/main/java/com/example/todoapp/service/RecipeService.java new file mode 100644 index 0000000..2eab2b8 --- /dev/null +++ b/backend/src/main/java/com/example/todoapp/service/RecipeService.java @@ -0,0 +1,210 @@ +//-------------------------------- +// RecipeService.java +// +// +// 更新履歴:2025/06/05 新規作成 +// Copyright(c) 2025 IVIS All rights reserved. +//-------------------------------------------- +package com.example.todoapp.service; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.example.todoapp.dto.RecipeDetailDTO; +import com.example.todoapp.dto.RecipeRequestDTO; +import com.example.todoapp.dto.StuffDetailDTO; +import com.example.todoapp.dto.StuffRequestDTO; +import com.example.todoapp.model.RecipeStuffs; +import com.example.todoapp.model.Recipes; +import com.example.todoapp.model.Stuffs; +import com.example.todoapp.repository.RecipesStuffsRepository; +import com.example.todoapp.repository.RecipesRepository; +import com.example.todoapp.repository.StuffsRepository; + +import jakarta.transaction.Transactional; + +/** + * レシピ管理サービスクラス + *

+ * このクラスは、レシピの登録処理を提供します。 + * 材料の存在確認・新規作成・数量管理などの機能を含みます。 + *

+ */ +@Service +public class RecipeService { + + @Autowired + private RecipesRepository recipesRepository; + + @Autowired + private StuffsRepository stuffsRepository; + + @Autowired + private RecipesStuffsRepository recipeStuffsRepository; + + /** + * レシピを新規登録する + * + * @param dto レシピ登録情報(レシピ名、概要、材料情報含む) + * @return レシピ登録結果(成功/失敗、レシピID含む) + */ + @Transactional // トランザクション管理を実施 + public Recipes addRecipe(RecipeRequestDTO dto) { + Recipes recipe = new Recipes(); + recipe.setRecipeName(dto.getRecipeName()); + recipe.setSummary(dto.getSummary()); + recipe = recipesRepository.save(recipe); + + List recipeStuffsList = new ArrayList<>(); + for (StuffRequestDTO stuffDTO : dto.getStuffAndAmountArray()) { + Stuffs stuff; + if (stuffDTO.getStuffId() != null && !stuffDTO.getStuffId().isEmpty()) { + // stuffIdが存在する + stuff = stuffsRepository.findById(Long.valueOf(stuffDTO.getStuffId())) + .orElseThrow(() -> new RuntimeException("材料がありません")); + } else { + // stuffIdが存在しない + stuff = new Stuffs(); + stuff.setStuffName(stuffDTO.getStuffName()); + stuff.setCategory(stuffDTO.getCategory()); + stuff = stuffsRepository.save(stuff); + } + + RecipeStuffs recipeStuffs = new RecipeStuffs(); + recipeStuffs.setRecipes(recipe); // 関連レシピ設定 + recipeStuffs.setStuff(stuff); // 関連材料設定 + + // 数量設定、defaultは1 + if (stuffDTO.getAmount() == null || stuffDTO.getAmount().isEmpty()) { + stuffDTO.setAmount("1"); + } + recipeStuffs.setAmount(Integer.parseInt(stuffDTO.getAmount())); + recipeStuffsList.add(recipeStuffs); + } + + recipeStuffsRepository.saveAll(recipeStuffsList); + return recipe; + } + + /** + * すべてのレシピ情報を取得する + * + * @return 登録済みレシピ情報リスト + */ + public List getAllRecipes() { + return recipesRepository.findAll(); + } + + /** + * 指定されたIDのレシピ詳細情報を取得する + * + * @param recipeId 検索するレシピID + * @return レシピ詳細情報(レシピ基本情報と関連食材情報) + * @throws RuntimeException レシピが見つからない場合 + */ + public RecipeDetailDTO getRecipeDetailsById(Long recipeId) { + Recipes recipe = recipesRepository.findById(recipeId) + .orElseThrow(() -> new RuntimeException("レシピが見つかりません")); + + List recipeStuffsList = recipeStuffsRepository.findByRecipesRecipeId(recipeId); + + List stuffList = recipeStuffsList.stream() + .map(rs -> { + StuffDetailDTO stuffDTO = new StuffDetailDTO(); + stuffDTO.setStuffId(rs.getStuff().getStuffId()); + stuffDTO.setStuffName(rs.getStuff().getStuffName()); + stuffDTO.setAmount(rs.getAmount()); + return stuffDTO; + }) + .collect(Collectors.toList()); + + RecipeDetailDTO dto = new RecipeDetailDTO(); + dto.setRecipeId(recipe.getRecipeId()); + dto.setRecipeName(recipe.getRecipeName()); + dto.setSummary(recipe.getSummary()); + dto.setStuffs(stuffList); + + return dto; + } + + /** + * レシピ情報を更新する + * + * @param dto 更新するレシピ詳細情報 + * @return 更新されたレシピエンティティ + * @throws RuntimeException レシピまたは材料情報が見つからない場合 + */ + @Transactional + public Recipes updateRecipe(RecipeDetailDTO dto) { + // IDでレシピを検索し、見つからない場合は例外をスロー + Recipes recipe = recipesRepository.findById(dto.getRecipeId()) + .orElseThrow(() -> new RuntimeException("レシピが見つかりません")); + + // レシピ名と概要を更新 + recipe.setRecipeName(dto.getRecipeName()); + recipe.setSummary(dto.getSummary()); + recipesRepository.save(recipe); + + Set incomingStuffIds = new HashSet<>(); + + // 提供された材料の詳細を繰り返し処理 + for (StuffDetailDTO stuffDTO : dto.getStuffs()) { + if (stuffDTO.getStuffId() == null) { + // 材料IDがnullの場合、新しい材料を作成 + Stuffs newStuff = new Stuffs(); + newStuff.setStuffName(stuffDTO.getStuffName()); + newStuff.setCategory("その他"); + newStuff = stuffsRepository.save(newStuff); + + // 新しいRecipeStuffsエントリを作成 + RecipeStuffs rs = new RecipeStuffs(); + rs.setRecipes(recipe); + rs.setStuff(newStuff); + rs.setAmount(stuffDTO.getAmount()); + recipeStuffsRepository.save(rs); + + incomingStuffIds.add(newStuff.getStuffId()); + } else { + // 材料IDが提供されている場合、既存のRecipeStuffsエントリを検索 + Optional optionalRs = recipeStuffsRepository + .findByRecipesRecipeIdAndStuffStuffId(dto.getRecipeId(), stuffDTO.getStuffId()); + + if (optionalRs.isPresent()) { + // RecipeStuffsエントリが存在する場合、数量を更新 + RecipeStuffs rs = optionalRs.get(); + rs.setAmount(stuffDTO.getAmount()); + recipeStuffsRepository.save(rs); + incomingStuffIds.add(rs.getStuff().getStuffId()); + } else { + // オプション:見つからない場合、新しいRecipeStuffsエントリを作成 + Stuffs existingStuff = stuffsRepository.findById(stuffDTO.getStuffId()) + .orElseThrow(() -> new RuntimeException("材料が見つかりません")); + + RecipeStuffs rs = new RecipeStuffs(); + rs.setRecipes(recipe); + rs.setStuff(existingStuff); + rs.setAmount(stuffDTO.getAmount()); + recipeStuffsRepository.save(rs); + incomingStuffIds.add(existingStuff.getStuffId()); + } + } + } + + // 入ってきたリストにないRecipeStuffsエントリを削除 + List existingStuffs = recipeStuffsRepository.findByRecipesRecipeId(dto.getRecipeId()); + for (RecipeStuffs rs : existingStuffs) { + if (!incomingStuffIds.contains(rs.getStuff().getStuffId())) { + recipeStuffsRepository.delete(rs); + } + } + + return recipe; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/todoapp/service/StocksService.java b/backend/src/main/java/com/example/todoapp/service/StocksService.java index 20a3386..faeef4b 100644 --- a/backend/src/main/java/com/example/todoapp/service/StocksService.java +++ b/backend/src/main/java/com/example/todoapp/service/StocksService.java @@ -89,12 +89,11 @@ public class StocksService { /** * 指定された在庫を削除する * - * @param username ユーザー名 - * @param taskId 削除する在庫のID + * @param userId ユーザー名 + * @param stockId 削除する在庫のID */ - public void deleteStock(String username, Long stockId) { - Stocks stock = getStockById(username, stockId); - stocksRepository.delete(stock); + public int deleteStockById(Long userId, Long stockId) { + return stocksRepository.deleteByUserIdAndStockId(userId, stockId); }