Keep dinner names frozen in Supply archive posts
CI / ci (push) Successful in 8m17s

Freezing a Supply run now records each group's dinner name in
shopping_groups.frozen_dinner_name, in the same transaction as the
freeze. A frozen list and its Supply archive post read that name, so
renaming a dinner after its week is frozen no longer rewrites the
archive; a current list still shows its dinners' names live.
Migration 0018 adds the column and fills it for lists frozen before it.

Task: 22f80eb6-cdee-4377-80ea-9b28f15a866f

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 09:18:54 -04:00
co-authored by Claude Opus 5.5
parent 791b321b71
commit a72ef1cbdd
16 changed files with 234 additions and 38 deletions
+23 -9
View File
@@ -22,7 +22,9 @@ const (
// Freeze moves the Supply run of the week starting weekStart into the
// Supply archive: its status becomes archived and frozen_at is set, after
// which it is read-only (Generate and SetNeeded are ErrFrozen). Freezing a
// which it is read-only (Generate and SetNeeded are ErrFrozen). The list
// keeps the names its dinners have as it is frozen, so its post in the
// Supply archive shows them whatever a dinner is renamed later. Freezing a
// frozen list does nothing and is no error.
//
// The week must have ended in the household's time zone: a week not yet
@@ -79,14 +81,25 @@ func (s *Service) freeze(ctx context.Context, weekStart store.LocalDate, now tim
"week", list.WeekStart, "list", list.ID, "error", err)
}
}
// A list frozen meanwhile is left as it is: the freeze is done.
// A list frozen meanwhile is left as it is, its names as they were
// frozen: the freeze is done.
stamp := store.Now().String()
if _, err := q.FreezeShoppingList(ctx, db.FreezeShoppingListParams{
FrozenAt: sql.NullString{String: stamp, Valid: true}, UpdatedAt: stamp, ID: list.ID,
}); err != nil {
return fmt.Errorf("shopping: freeze %s: %w", weekStart, err)
}
return nil
return s.st.WithTx(ctx, func(tx *sql.Tx) error {
q := db.New(tx)
n, err := q.FreezeShoppingList(ctx, db.FreezeShoppingListParams{
FrozenAt: sql.NullString{String: stamp, Valid: true}, UpdatedAt: stamp, ID: list.ID,
})
if err != nil {
return fmt.Errorf("shopping: freeze %s: %w", weekStart, err)
}
if n == 0 {
return nil
}
if err := q.FreezeShoppingGroupNames(ctx, list.ID); err != nil {
return fmt.Errorf("shopping: freeze %s: keep dinner names: %w", weekStart, err)
}
return nil
})
}
// freezeTitleJob is the title job of list as Generate would enqueue it:
@@ -145,7 +158,8 @@ type Post struct {
Label string
// Title is nil while the list is untitled, when Label stands in.
Title *string
// Dinners are the names of the list's dinners, in day order.
// Dinners are the names of the list's dinners, in day order: as they
// were when the list was frozen, or as they are now while it is not.
Dinners []string
// Items is how many items the list has, and OnHand how many of them
// the household marked "have it".