feat: Move "on hand" and "last made" to household (#4616)

Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
Michael Genson
2025-01-13 10:19:49 -06:00
committed by GitHub
parent e565b919df
commit e9892aba89
53 changed files with 1618 additions and 400 deletions

View File

@@ -1,10 +1,15 @@
from uuid import UUID
from pydantic import UUID4
from mealie.core import exceptions
from mealie.repos.all_repositories import get_repositories
from mealie.repos.repository_factory import AllRepositories
from mealie.schema.household.household import HouseholdCreate
from mealie.schema.household import HouseholdCreate, HouseholdRecipeSummary
from mealie.schema.household.household import HouseholdRecipeCreate, HouseholdRecipeUpdate
from mealie.schema.household.household_preferences import CreateHouseholdPreferences, SaveHouseholdPreferences
from mealie.schema.household.household_statistics import HouseholdStatistics
from mealie.schema.recipe.recipe import Recipe
from mealie.services._base_service import BaseService
@@ -15,6 +20,19 @@ class HouseholdService(BaseService):
self.repos = repos
super().__init__()
def _get_recipe(self, recipe_slug: str | UUID) -> Recipe | None:
key = "id"
if not isinstance(recipe_slug, UUID):
try:
UUID(recipe_slug)
except ValueError:
key = "slug"
cross_household_recipes = get_repositories(
self.repos.session, group_id=self.group_id, household_id=None
).recipes
return cross_household_recipes.get_one(recipe_slug, key)
@staticmethod
def create_household(
repos: AllRepositories, h_base: HouseholdCreate, prefs: CreateHouseholdPreferences | None = None
@@ -48,3 +66,34 @@ class HouseholdService(BaseService):
household_id = household_id or self.household_id
return self.repos.households.statistics(group_id, household_id)
def get_household_recipe(self, recipe_slug: str) -> HouseholdRecipeSummary | None:
"""Returns recipe data for the current household"""
recipe = self._get_recipe(recipe_slug)
if not recipe:
return None
household_recipe_out = self.repos.household_recipes.get_by_recipe(recipe.id)
if household_recipe_out:
return household_recipe_out.cast(HouseholdRecipeSummary)
else:
return HouseholdRecipeSummary(recipe_id=recipe.id)
def set_household_recipe(self, recipe_slug: str | UUID, data: HouseholdRecipeUpdate) -> HouseholdRecipeSummary:
"""Sets the household's recipe data"""
recipe = self._get_recipe(recipe_slug)
if not recipe:
raise exceptions.NoEntryFound("Recipe not found.")
existing_household_recipe = self.repos.household_recipes.get_by_recipe(recipe.id)
if existing_household_recipe:
updated_data = existing_household_recipe.cast(HouseholdRecipeUpdate, **data.model_dump())
household_recipe_out = self.repos.household_recipes.patch(existing_household_recipe.id, updated_data)
else:
create_data = HouseholdRecipeCreate(
household_id=self.household_id, recipe_id=recipe.id, **data.model_dump()
)
household_recipe_out = self.repos.household_recipes.create(create_data)
return household_recipe_out.cast(HouseholdRecipeSummary)

View File

@@ -19,7 +19,7 @@ from mealie.pkgs import cache
from mealie.repos.all_repositories import get_repositories
from mealie.repos.repository_factory import AllRepositories
from mealie.repos.repository_generic import RepositoryGeneric
from mealie.schema.household.household import HouseholdInDB
from mealie.schema.household.household import HouseholdInDB, HouseholdRecipeUpdate
from mealie.schema.openai.recipe import OpenAIRecipe
from mealie.schema.recipe.recipe import CreateRecipe, Recipe
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient
@@ -30,6 +30,7 @@ from mealie.schema.recipe.recipe_timeline_events import RecipeTimelineEventCreat
from mealie.schema.recipe.request_helpers import RecipeDuplicate
from mealie.schema.user.user import PrivateUser, UserRatingCreate
from mealie.services._base_service import BaseService
from mealie.services.household_services.household_service import HouseholdService
from mealie.services.openai import OpenAIDataInjection, OpenAILocalImage, OpenAIService
from mealie.services.recipe.recipe_data_service import RecipeDataService
from mealie.services.scraper import cleaner
@@ -173,6 +174,7 @@ class RecipeService(RecipeServiceBase):
data.settings = RecipeSettings()
rating_input = data.rating
data.last_made = None
new_recipe = self.repos.recipes.create(data)
# convert rating into user rating
@@ -342,6 +344,7 @@ class RecipeService(RecipeServiceBase):
if old_recipe.recipe_ingredient is None
else list(map(copy_recipe_ingredient, old_recipe.recipe_ingredient))
)
new_recipe.last_made = None
new_recipe = self._recipe_creation_factory(new_name, additional_attrs=new_recipe.model_dump())
@@ -413,8 +416,11 @@ class RecipeService(RecipeServiceBase):
def update_last_made(self, slug_or_id: str | UUID, timestamp: datetime) -> Recipe:
# we bypass the pre update check since any user can update a recipe's last made date, even if it's locked,
# or if the user belongs to a different household
recipe = self.get_one(slug_or_id)
return self.group_recipes.patch(recipe.slug, {"last_made": timestamp})
household_service = HouseholdService(self.user.group_id, self.user.household_id, self.repos)
household_service.set_household_recipe(slug_or_id, HouseholdRecipeUpdate(last_made=timestamp))
return self.get_one(slug_or_id)
def delete_one(self, slug_or_id: str | UUID) -> Recipe:
recipe = self.get_one(slug_or_id)

View File

@@ -6,6 +6,7 @@ from sqlalchemy.orm import Session
from mealie.db.db_setup import session_context
from mealie.repos.all_repositories import get_repositories
from mealie.schema.household.household import HouseholdRecipeUpdate
from mealie.schema.meal_plan.new_meal import PlanEntryType
from mealie.schema.recipe.recipe import RecipeSummary
from mealie.schema.recipe.recipe_timeline_events import RecipeTimelineEventCreate, TimelineEventType
@@ -18,12 +19,14 @@ from mealie.services.event_bus_service.event_types import (
EventRecipeTimelineEventData,
EventTypes,
)
from mealie.services.household_services.household_service import HouseholdService
def _create_mealplan_timeline_events_for_household(
event_time: datetime, session: Session, group_id: UUID4, household_id: UUID4
) -> None:
repos = get_repositories(session, group_id=group_id, household_id=household_id)
household_service = HouseholdService(group_id, household_id, repos)
event_bus_service = EventBusService(session=session)
timeline_events_to_create: list[RecipeTimelineEventCreate] = []
@@ -64,7 +67,8 @@ def _create_mealplan_timeline_events_for_household(
continue
# bump up the last made date
last_made = mealplan.recipe.last_made
household_to_recipe = household_service.get_household_recipe(mealplan.recipe.slug)
last_made = household_to_recipe.last_made if household_to_recipe else None
if (not last_made or last_made.date() < event_time.date()) and mealplan.recipe_id not in recipes_to_update:
recipes_to_update[mealplan.recipe_id] = mealplan.recipe
@@ -99,6 +103,7 @@ def _create_mealplan_timeline_events_for_household(
)
for recipe in recipes_to_update.values():
household_service.set_household_recipe(recipe.slug, HouseholdRecipeUpdate(last_made=event_time))
repos.recipes.patch(recipe.slug, {"last_made": event_time})
event_bus_service.dispatch(
integration_id=DEFAULT_INTEGRATION_ID,