Add structured quantities + units to shopping list items

Mirrors the Phase 2 work on RecipeIngredient: ShoppingListItem grows
Quantity (decimal), UnitOfMeasureId / FamilyUnitOfMeasureId, IsApproximate,
and QuantityNote. The recipe-to-list copy now carries structured fields
verbatim instead of folding them into the free-form Name, and the
unit-in-use guard now also blocks deleting a family unit that's referenced
by a shopping list item.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Josh Rogers
2026-05-13 21:18:26 -05:00
parent c7f9c31952
commit fb1bc2b7e1
11 changed files with 1606 additions and 64 deletions
@@ -514,6 +514,12 @@ namespace YesChef.Api.Migrations
b.Property<int?>("FamilyProductId")
.HasColumnType("integer");
b.Property<int?>("FamilyUnitOfMeasureId")
.HasColumnType("integer");
b.Property<bool>("IsApproximate")
.HasColumnType("boolean");
b.Property<bool>("IsChecked")
.HasColumnType("boolean");
@@ -525,6 +531,14 @@ namespace YesChef.Api.Migrations
b.Property<int?>("ProductId")
.HasColumnType("integer");
b.Property<decimal?>("Quantity")
.HasPrecision(12, 4)
.HasColumnType("numeric(12,4)");
b.Property<string>("QuantityNote")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<int?>("RecipeId")
.HasColumnType("integer");
@@ -543,6 +557,9 @@ namespace YesChef.Api.Migrations
b.Property<int>("SortOrder")
.HasColumnType("integer");
b.Property<int?>("UnitOfMeasureId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CheckedByUserId");
@@ -551,6 +568,8 @@ namespace YesChef.Api.Migrations
b.HasIndex("FamilyProductId");
b.HasIndex("FamilyUnitOfMeasureId");
b.HasIndex("ProductId");
b.HasIndex("RecipeId");
@@ -561,6 +580,8 @@ namespace YesChef.Api.Migrations
b.HasIndex("ShoppingListId");
b.HasIndex("UnitOfMeasureId");
b.ToTable("ShoppingListItems");
});
@@ -965,6 +986,11 @@ namespace YesChef.Api.Migrations
.HasForeignKey("FamilyProductId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("YesChef.Api.Entities.FamilyUnitOfMeasure", "FamilyUnitOfMeasure")
.WithMany()
.HasForeignKey("FamilyUnitOfMeasureId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("YesChef.Api.Entities.Product", "Product")
.WithMany()
.HasForeignKey("ProductId")
@@ -991,12 +1017,19 @@ namespace YesChef.Api.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YesChef.Api.Entities.UnitOfMeasure", "UnitOfMeasure")
.WithMany()
.HasForeignKey("UnitOfMeasureId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("CheckedByUser");
b.Navigation("Family");
b.Navigation("FamilyProduct");
b.Navigation("FamilyUnitOfMeasure");
b.Navigation("Product");
b.Navigation("Recipe");
@@ -1006,6 +1039,8 @@ namespace YesChef.Api.Migrations
b.Navigation("Section");
b.Navigation("ShoppingList");
b.Navigation("UnitOfMeasure");
});
modelBuilder.Entity("YesChef.Api.Entities.Store", b =>