feat(shopping): extend response with generatedAt, filteredStaplesCount, RecipeRef
Shopping list response now includes generatedAt timestamp, count of filtered staples, and recipe names (not just UUIDs) in source references. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,9 @@ import com.recipeapp.household.HouseholdRepository;
|
||||
import com.recipeapp.planning.WeekPlanRepository;
|
||||
import com.recipeapp.planning.entity.WeekPlan;
|
||||
import com.recipeapp.recipe.IngredientRepository;
|
||||
import com.recipeapp.recipe.RecipeRepository;
|
||||
import com.recipeapp.recipe.entity.Ingredient;
|
||||
import com.recipeapp.recipe.entity.Recipe;
|
||||
import com.recipeapp.recipe.entity.RecipeIngredient;
|
||||
import com.recipeapp.shopping.dto.*;
|
||||
import com.recipeapp.shopping.entity.ShoppingList;
|
||||
@@ -18,6 +20,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@@ -29,19 +33,22 @@ public class ShoppingService {
|
||||
private final HouseholdRepository householdRepository;
|
||||
private final IngredientRepository ingredientRepository;
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
private final RecipeRepository recipeRepository;
|
||||
|
||||
public ShoppingService(ShoppingListRepository shoppingListRepository,
|
||||
ShoppingListItemRepository shoppingListItemRepository,
|
||||
WeekPlanRepository weekPlanRepository,
|
||||
HouseholdRepository householdRepository,
|
||||
IngredientRepository ingredientRepository,
|
||||
UserAccountRepository userAccountRepository) {
|
||||
UserAccountRepository userAccountRepository,
|
||||
RecipeRepository recipeRepository) {
|
||||
this.shoppingListRepository = shoppingListRepository;
|
||||
this.shoppingListItemRepository = shoppingListItemRepository;
|
||||
this.weekPlanRepository = weekPlanRepository;
|
||||
this.householdRepository = householdRepository;
|
||||
this.ingredientRepository = ingredientRepository;
|
||||
this.userAccountRepository = userAccountRepository;
|
||||
this.recipeRepository = recipeRepository;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +128,7 @@ public class ShoppingService {
|
||||
}
|
||||
|
||||
shoppingListItemRepository.save(item);
|
||||
return toItemResponse(item);
|
||||
return toItemResponseWithNames(item);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +153,7 @@ public class ShoppingService {
|
||||
item = shoppingListItemRepository.save(item);
|
||||
list.getItems().add(item);
|
||||
|
||||
return toItemResponse(item);
|
||||
return toItemResponseWithNames(item);
|
||||
}
|
||||
|
||||
|
||||
@@ -178,18 +185,53 @@ public class ShoppingService {
|
||||
}
|
||||
|
||||
private ShoppingListResponse toResponse(ShoppingList list) {
|
||||
// Batch-fetch recipe names for source references
|
||||
Set<UUID> allRecipeIds = list.getItems().stream()
|
||||
.filter(i -> i.getSourceRecipes() != null)
|
||||
.flatMap(i -> Arrays.stream(i.getSourceRecipes()))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<UUID, String> recipeNames = allRecipeIds.isEmpty()
|
||||
? Map.of()
|
||||
: recipeRepository.findAllById(allRecipeIds).stream()
|
||||
.collect(Collectors.toMap(Recipe::getId, Recipe::getName));
|
||||
|
||||
List<ShoppingListItemResponse> items = list.getItems().stream()
|
||||
.map(this::toItemResponse)
|
||||
.map(item -> toItemResponse(item, recipeNames))
|
||||
.toList();
|
||||
|
||||
// Count filtered staples from the week plan
|
||||
int filteredStaplesCount = countFilteredStaples(list.getWeekPlan());
|
||||
|
||||
return new ShoppingListResponse(
|
||||
list.getId(),
|
||||
list.getWeekPlan().getId(),
|
||||
list.getGeneratedAt(),
|
||||
filteredStaplesCount,
|
||||
items
|
||||
);
|
||||
}
|
||||
|
||||
private ShoppingListItemResponse toItemResponse(ShoppingListItem item) {
|
||||
private int countFilteredStaples(WeekPlan weekPlan) {
|
||||
return (int) weekPlan.getSlots().stream()
|
||||
.flatMap(slot -> slot.getRecipe().getIngredients().stream())
|
||||
.map(RecipeIngredient::getIngredient)
|
||||
.filter(Ingredient::isStaple)
|
||||
.map(Ingredient::getId)
|
||||
.distinct()
|
||||
.count();
|
||||
}
|
||||
|
||||
private ShoppingListItemResponse toItemResponseWithNames(ShoppingListItem item) {
|
||||
Map<UUID, String> recipeNames = Map.of();
|
||||
if (item.getSourceRecipes() != null && item.getSourceRecipes().length > 0) {
|
||||
recipeNames = recipeRepository.findAllById(Arrays.asList(item.getSourceRecipes())).stream()
|
||||
.collect(Collectors.toMap(Recipe::getId, Recipe::getName));
|
||||
}
|
||||
return toItemResponse(item, recipeNames);
|
||||
}
|
||||
|
||||
private ShoppingListItemResponse toItemResponse(ShoppingListItem item, Map<UUID, String> recipeNames) {
|
||||
String name;
|
||||
ShoppingListItemResponse.CategoryRef categoryRef = null;
|
||||
UUID ingredientId = null;
|
||||
@@ -207,6 +249,14 @@ public class ShoppingService {
|
||||
name = item.getCustomName();
|
||||
}
|
||||
|
||||
List<ShoppingListItemResponse.RecipeRef> sourceRefs = item.getSourceRecipes() != null
|
||||
? Arrays.stream(item.getSourceRecipes())
|
||||
.distinct()
|
||||
.filter(recipeNames::containsKey)
|
||||
.map(id -> new ShoppingListItemResponse.RecipeRef(id, recipeNames.get(id)))
|
||||
.toList()
|
||||
: List.of();
|
||||
|
||||
return new ShoppingListItemResponse(
|
||||
item.getId(),
|
||||
ingredientId,
|
||||
@@ -216,7 +266,7 @@ public class ShoppingService {
|
||||
item.getUnit(),
|
||||
item.isChecked(),
|
||||
item.getCheckedBy() != null ? item.getCheckedBy().getId() : null,
|
||||
item.getSourceRecipes() != null ? Arrays.asList(item.getSourceRecipes()) : List.of()
|
||||
sourceRefs
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ public record ShoppingListItemResponse(
|
||||
String unit,
|
||||
boolean isChecked,
|
||||
UUID checkedBy,
|
||||
List<UUID> sourceRecipes
|
||||
List<RecipeRef> sourceRecipes
|
||||
) {
|
||||
public record CategoryRef(UUID id, String name) {}
|
||||
public record RecipeRef(UUID id, String name) {}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.recipeapp.shopping.dto;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record ShoppingListResponse(
|
||||
UUID id,
|
||||
UUID weekPlanId,
|
||||
Instant generatedAt,
|
||||
int filteredStaplesCount,
|
||||
List<ShoppingListItemResponse> items
|
||||
) {}
|
||||
|
||||
Reference in New Issue
Block a user