feat(products): improve replenishment-aware shopping suggestions

Replace product weight and repurchase intent fields with per-package remaining levels and inventory-first restock signals. Enrich shopping suggestions with usage-aware replenishment scoring so the frontend and LLM can prioritize real gaps and near-empty staples more reliably.
This commit is contained in:
Piotr Oleszczyk 2026-03-09 13:37:40 +01:00
parent bb5d402c15
commit d91d06455b
18 changed files with 587 additions and 210 deletions

View file

@ -0,0 +1,69 @@
"""replace product weights with inventory remaining level
Revision ID: 9f3a2c1b4d5e
Revises: 7e6f73d1cc95
Create Date: 2026-03-08 12:00:00.000000
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "9f3a2c1b4d5e"
down_revision: Union[str, Sequence[str], None] = "7e6f73d1cc95"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
bind = op.get_bind()
remaining_level_enum = sa.Enum(
"HIGH",
"MEDIUM",
"LOW",
"NEARLY_EMPTY",
name="remaininglevel",
)
remaining_level_enum.create(bind, checkfirst=True)
op.add_column(
"product_inventory",
sa.Column("remaining_level", remaining_level_enum, nullable=True),
)
op.drop_column("product_inventory", "last_weighed_at")
op.drop_column("product_inventory", "current_weight_g")
op.drop_column("products", "personal_repurchase_intent")
op.drop_column("products", "empty_weight_g")
op.drop_column("products", "full_weight_g")
def downgrade() -> None:
bind = op.get_bind()
remaining_level_enum = sa.Enum(
"HIGH",
"MEDIUM",
"LOW",
"NEARLY_EMPTY",
name="remaininglevel",
)
op.add_column(
"products",
sa.Column("personal_repurchase_intent", sa.Boolean(), nullable=True),
)
op.add_column(
"product_inventory",
sa.Column("current_weight_g", sa.Float(), nullable=True),
)
op.add_column(
"product_inventory",
sa.Column("last_weighed_at", sa.Date(), nullable=True),
)
op.add_column("products", sa.Column("full_weight_g", sa.Float(), nullable=True))
op.add_column("products", sa.Column("empty_weight_g", sa.Float(), nullable=True))
op.drop_column("product_inventory", "remaining_level")
remaining_level_enum.drop(bind, checkfirst=True)