feat(planning): add GET /v1/week-plans/{planId}/variety-preview endpoint
Returns currentScore, projectedScore, and scoreDelta when a recipe would be added on a given date. Used by C6 desktop day picker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -443,4 +443,62 @@ class PlanningServiceTest {
|
||||
assertThatThrownBy(() -> planningService.createWeekPlan(HOUSEHOLD_ID, WEEK_START))
|
||||
.isInstanceOf(ResourceNotFoundException.class);
|
||||
}
|
||||
|
||||
// ── Variety preview ──
|
||||
|
||||
@Test
|
||||
void getVarietyPreviewShouldReturnScoreDelta() {
|
||||
var household = testHousehold();
|
||||
var plan = testWeekPlan(household);
|
||||
var planId = plan.getId();
|
||||
|
||||
// Plan already has one slot (Mon)
|
||||
var existingRecipe = testRecipe(household, "Spaghetti");
|
||||
var slot = new WeekPlanSlot(plan, existingRecipe, WEEK_START);
|
||||
setId(slot, WeekPlanSlot.class, UUID.randomUUID());
|
||||
plan.getSlots().add(slot);
|
||||
|
||||
var candidate = testRecipe(household, "Lachsfilet");
|
||||
var candidateId = candidate.getId();
|
||||
|
||||
when(weekPlanRepository.findById(planId)).thenReturn(Optional.of(plan));
|
||||
when(recipeRepository.findByIdAndHouseholdIdAndDeletedAtIsNull(candidateId, HOUSEHOLD_ID))
|
||||
.thenReturn(Optional.of(candidate));
|
||||
when(varietyScoreConfigRepository.findByHouseholdId(HOUSEHOLD_ID))
|
||||
.thenReturn(Optional.empty());
|
||||
when(cookingLogRepository.findByHouseholdIdAndCookedOnAfter(eq(HOUSEHOLD_ID), any()))
|
||||
.thenReturn(List.of());
|
||||
|
||||
var result = planningService.getVarietyPreview(HOUSEHOLD_ID, planId, candidateId, WEEK_START.plusDays(1));
|
||||
|
||||
// With no penalties, projected score should be 10.0; current (1 slot, no conflicts) is also 10.0
|
||||
assertThat(result.projectedScore()).isBetween(0.0, 10.0);
|
||||
assertThat(result.scoreDelta()).isEqualTo(result.projectedScore() - result.currentScore());
|
||||
assertThat(result.currentScore()).isBetween(0.0, 10.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getVarietyPreviewShouldThrowWhenPlanNotFound() {
|
||||
var planId = UUID.randomUUID();
|
||||
when(weekPlanRepository.findById(planId)).thenReturn(Optional.empty());
|
||||
|
||||
assertThatThrownBy(() -> planningService.getVarietyPreview(
|
||||
HOUSEHOLD_ID, planId, UUID.randomUUID(), WEEK_START))
|
||||
.isInstanceOf(ResourceNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getVarietyPreviewShouldThrowWhenRecipeNotFound() {
|
||||
var household = testHousehold();
|
||||
var plan = testWeekPlan(household);
|
||||
var recipeId = UUID.randomUUID();
|
||||
|
||||
when(weekPlanRepository.findById(plan.getId())).thenReturn(Optional.of(plan));
|
||||
when(recipeRepository.findByIdAndHouseholdIdAndDeletedAtIsNull(recipeId, HOUSEHOLD_ID))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
assertThatThrownBy(() -> planningService.getVarietyPreview(
|
||||
HOUSEHOLD_ID, plan.getId(), recipeId, WEEK_START))
|
||||
.isInstanceOf(ResourceNotFoundException.class);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user