873f53b9fc
- Remove PostgreSQL-specific server_default from User.email_inbound_token. The column has a Python-side default (secrets.token_urlsafe) that works for both SQLite and PostgreSQL. The gen_random_bytes() server_default caused sqlite table creation to fail. - Add missing back_populates relationships to stub models so SQLAlchemy mapper configuration succeeds. Purchase.user and Store.user_accounts were missing, causing "has no property" errors during Base.metadata.create_all. - Auto-fix ruff import sorting (I001) across all source and test files. - Manually fix line-too-long (E501) in config.py. Co-Authored-By: Paperclip <noreply@paperclip.ing>
82 lines
3.3 KiB
Python
82 lines
3.3 KiB
Python
"""Stub Purchase and PurchaseItem models.
|
|
|
|
These are minimal stubs of the full cartsnitch-common Purchase/PurchaseItem models.
|
|
They exist solely to satisfy SQLAlchemy relationship resolution for User and
|
|
UserStoreAccount. The canonical definitions live in cartsnitch/common.
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import date, datetime
|
|
from decimal import Decimal
|
|
from typing import TYPE_CHECKING
|
|
|
|
from sqlalchemy import (
|
|
JSON,
|
|
Date,
|
|
DateTime,
|
|
ForeignKey,
|
|
Index,
|
|
Numeric,
|
|
String,
|
|
UniqueConstraint,
|
|
func,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from receiptwitness.shared.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
|
|
|
if TYPE_CHECKING:
|
|
from receiptwitness.shared.models.user import User
|
|
|
|
|
|
class Purchase(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|
"""Stub: a shopping trip/receipt. Full definition in cartsnitch/common."""
|
|
|
|
__tablename__ = "purchases"
|
|
|
|
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("users.id"), nullable=False)
|
|
store_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("stores.id"), nullable=False)
|
|
store_location_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("store_locations.id"))
|
|
receipt_id: Mapped[str] = mapped_column(String(200), nullable=False)
|
|
purchase_date: Mapped[date] = mapped_column(Date, nullable=False)
|
|
total: Mapped[Decimal] = mapped_column(Numeric(10, 2), nullable=False)
|
|
subtotal: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
tax: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
savings_total: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
source_url: Mapped[str | None] = mapped_column(String(500))
|
|
raw_data: Mapped[dict | None] = mapped_column(JSON)
|
|
ingested_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
server_default=func.now(),
|
|
nullable=False,
|
|
)
|
|
|
|
# Relationships (stubs — canonical definitions in cartsnitch/common)
|
|
user: Mapped["User"] = relationship(back_populates="purchases")
|
|
|
|
__table_args__ = (
|
|
Index("ix_purchases_user_store", "user_id", "store_id"),
|
|
UniqueConstraint("user_id", "store_id", "receipt_id", name="uq_purchase_receipt"),
|
|
)
|
|
|
|
|
|
class PurchaseItem(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|
"""Stub: a line item on a receipt. Full definition in cartsnitch/common."""
|
|
|
|
__tablename__ = "purchase_items"
|
|
|
|
purchase_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("purchases.id"), nullable=False)
|
|
product_name_raw: Mapped[str] = mapped_column(String(300), nullable=False)
|
|
upc: Mapped[str | None] = mapped_column(String(20))
|
|
quantity: Mapped[Decimal] = mapped_column(Numeric(10, 3), nullable=False, default=1)
|
|
unit_price: Mapped[Decimal] = mapped_column(Numeric(10, 2), nullable=False)
|
|
extended_price: Mapped[Decimal] = mapped_column(Numeric(10, 2), nullable=False)
|
|
regular_price: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
sale_price: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
coupon_discount: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
loyalty_discount: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
category_raw: Mapped[str | None] = mapped_column(String(100))
|
|
normalized_product_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
ForeignKey("normalized_products.id")
|
|
)
|