forked from cartsnitch/cartsnitch
Merge commit '4cf6f91e954b770198578bcb8db5d98ac964bfed' as 'common'
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"""Pydantic v2 schemas for inter-service API contracts."""
|
||||
|
||||
from cartsnitch_common.schemas.coupon import CouponCreate, CouponRead
|
||||
from cartsnitch_common.schemas.events import EventEnvelope
|
||||
from cartsnitch_common.schemas.price import PriceHistoryCreate, PriceHistoryRead
|
||||
from cartsnitch_common.schemas.product import NormalizedProductCreate, NormalizedProductRead
|
||||
from cartsnitch_common.schemas.purchase import (
|
||||
PurchaseCreate,
|
||||
PurchaseItemCreate,
|
||||
PurchaseItemRead,
|
||||
PurchaseRead,
|
||||
)
|
||||
from cartsnitch_common.schemas.shrinkflation import ShrinkflationEventCreate, ShrinkflationEventRead
|
||||
from cartsnitch_common.schemas.store import (
|
||||
StoreCreate,
|
||||
StoreLocationCreate,
|
||||
StoreLocationRead,
|
||||
StoreRead,
|
||||
)
|
||||
from cartsnitch_common.schemas.user import (
|
||||
UserCreate,
|
||||
UserRead,
|
||||
UserStoreAccountCreate,
|
||||
UserStoreAccountRead,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"StoreCreate",
|
||||
"StoreRead",
|
||||
"StoreLocationCreate",
|
||||
"StoreLocationRead",
|
||||
"UserCreate",
|
||||
"UserRead",
|
||||
"UserStoreAccountCreate",
|
||||
"UserStoreAccountRead",
|
||||
"PurchaseCreate",
|
||||
"PurchaseRead",
|
||||
"PurchaseItemCreate",
|
||||
"PurchaseItemRead",
|
||||
"NormalizedProductCreate",
|
||||
"NormalizedProductRead",
|
||||
"PriceHistoryCreate",
|
||||
"PriceHistoryRead",
|
||||
"CouponCreate",
|
||||
"CouponRead",
|
||||
"ShrinkflationEventCreate",
|
||||
"ShrinkflationEventRead",
|
||||
"EventEnvelope",
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Coupon Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import DiscountType
|
||||
|
||||
|
||||
class CouponCreate(BaseModel):
|
||||
store_id: uuid.UUID
|
||||
normalized_product_id: uuid.UUID | None = None
|
||||
title: str
|
||||
description: str | None = None
|
||||
discount_type: DiscountType
|
||||
discount_value: Decimal | None = None
|
||||
min_purchase: Decimal | None = None
|
||||
valid_from: date | None = None
|
||||
valid_to: date | None = None
|
||||
requires_clip: bool = False
|
||||
coupon_code: str | None = None
|
||||
source_url: str | None = None
|
||||
|
||||
|
||||
class CouponRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
normalized_product_id: uuid.UUID | None
|
||||
title: str
|
||||
description: str | None
|
||||
discount_type: DiscountType
|
||||
discount_value: Decimal | None
|
||||
min_purchase: Decimal | None
|
||||
valid_from: date | None
|
||||
valid_to: date | None
|
||||
requires_clip: bool
|
||||
coupon_code: str | None
|
||||
source_url: str | None
|
||||
scraped_at: datetime | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,17 @@
|
||||
"""Redis pub/sub event envelope and payload schemas."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import EventType
|
||||
|
||||
|
||||
class EventEnvelope(BaseModel):
|
||||
"""Standard event wrapper for all Redis pub/sub messages."""
|
||||
|
||||
event_type: EventType
|
||||
timestamp: datetime
|
||||
service: str
|
||||
payload: dict[str, Any]
|
||||
@@ -0,0 +1,38 @@
|
||||
"""PriceHistory Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import PriceSource
|
||||
|
||||
|
||||
class PriceHistoryCreate(BaseModel):
|
||||
normalized_product_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
observed_date: date
|
||||
regular_price: Decimal
|
||||
sale_price: Decimal | None = None
|
||||
loyalty_price: Decimal | None = None
|
||||
coupon_price: Decimal | None = None
|
||||
source: PriceSource
|
||||
purchase_item_id: uuid.UUID | None = None
|
||||
|
||||
|
||||
class PriceHistoryRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
normalized_product_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
observed_date: date
|
||||
regular_price: Decimal
|
||||
sale_price: Decimal | None
|
||||
loyalty_price: Decimal | None
|
||||
coupon_price: Decimal | None
|
||||
source: PriceSource
|
||||
purchase_item_id: uuid.UUID | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,33 @@
|
||||
"""NormalizedProduct Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import ProductCategory, SizeUnit
|
||||
|
||||
|
||||
class NormalizedProductCreate(BaseModel):
|
||||
canonical_name: str
|
||||
category: ProductCategory | None = None
|
||||
subcategory: str | None = None
|
||||
brand: str | None = None
|
||||
size: str | None = None
|
||||
size_unit: SizeUnit | None = None
|
||||
upc_variants: list[str] = []
|
||||
|
||||
|
||||
class NormalizedProductRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
canonical_name: str
|
||||
category: ProductCategory | None
|
||||
subcategory: str | None
|
||||
brand: str | None
|
||||
size: str | None
|
||||
size_unit: SizeUnit | None
|
||||
upc_variants: list | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,73 @@
|
||||
"""Purchase and PurchaseItem Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PurchaseItemCreate(BaseModel):
|
||||
product_name_raw: str
|
||||
upc: str | None = None
|
||||
quantity: Decimal = Decimal("1")
|
||||
unit_price: Decimal
|
||||
extended_price: Decimal
|
||||
regular_price: Decimal | None = None
|
||||
sale_price: Decimal | None = None
|
||||
coupon_discount: Decimal | None = None
|
||||
loyalty_discount: Decimal | None = None
|
||||
category_raw: str | None = None
|
||||
normalized_product_id: uuid.UUID | None = None
|
||||
|
||||
|
||||
class PurchaseItemRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
purchase_id: uuid.UUID
|
||||
product_name_raw: str
|
||||
upc: str | None
|
||||
quantity: Decimal
|
||||
unit_price: Decimal
|
||||
extended_price: Decimal
|
||||
regular_price: Decimal | None
|
||||
sale_price: Decimal | None
|
||||
coupon_discount: Decimal | None
|
||||
loyalty_discount: Decimal | None
|
||||
category_raw: str | None
|
||||
normalized_product_id: uuid.UUID | None
|
||||
|
||||
|
||||
class PurchaseCreate(BaseModel):
|
||||
user_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
store_location_id: uuid.UUID | None = None
|
||||
receipt_id: str
|
||||
purchase_date: date
|
||||
total: Decimal
|
||||
subtotal: Decimal | None = None
|
||||
tax: Decimal | None = None
|
||||
savings_total: Decimal | None = None
|
||||
source_url: str | None = None
|
||||
raw_data: dict | None = None
|
||||
items: list[PurchaseItemCreate] = []
|
||||
|
||||
|
||||
class PurchaseRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
user_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
store_location_id: uuid.UUID | None
|
||||
receipt_id: str
|
||||
purchase_date: date
|
||||
total: Decimal
|
||||
subtotal: Decimal | None
|
||||
tax: Decimal | None
|
||||
savings_total: Decimal | None
|
||||
source_url: str | None
|
||||
ingested_at: datetime
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,40 @@
|
||||
"""ShrinkflationEvent Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import SizeUnit
|
||||
|
||||
|
||||
class ShrinkflationEventCreate(BaseModel):
|
||||
normalized_product_id: uuid.UUID
|
||||
detected_date: date
|
||||
old_size: str
|
||||
new_size: str
|
||||
old_unit: SizeUnit
|
||||
new_unit: SizeUnit
|
||||
price_at_old_size: Decimal | None = None
|
||||
price_at_new_size: Decimal | None = None
|
||||
confidence: Decimal = Decimal("1.00")
|
||||
notes: str | None = None
|
||||
|
||||
|
||||
class ShrinkflationEventRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
normalized_product_id: uuid.UUID
|
||||
detected_date: date
|
||||
old_size: str
|
||||
new_size: str
|
||||
old_unit: SizeUnit
|
||||
new_unit: SizeUnit
|
||||
price_at_old_size: Decimal | None
|
||||
price_at_new_size: Decimal | None
|
||||
confidence: Decimal
|
||||
notes: str | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Store and StoreLocation Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from cartsnitch_common.constants import StoreSlug
|
||||
|
||||
|
||||
class StoreCreate(BaseModel):
|
||||
name: str
|
||||
slug: StoreSlug
|
||||
logo_url: str | None = None
|
||||
website_url: str | None = None
|
||||
|
||||
|
||||
class StoreRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
slug: StoreSlug
|
||||
logo_url: str | None
|
||||
website_url: str | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class StoreLocationCreate(BaseModel):
|
||||
store_id: uuid.UUID
|
||||
address: str
|
||||
city: str
|
||||
state: str
|
||||
zip: str
|
||||
lat: float | None = None
|
||||
lng: float | None = None
|
||||
|
||||
|
||||
class StoreLocationRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
address: str
|
||||
city: str
|
||||
state: str
|
||||
zip: str
|
||||
lat: float | None
|
||||
lng: float | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
@@ -0,0 +1,44 @@
|
||||
"""User and UserStoreAccount Pydantic schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
from cartsnitch_common.constants import AccountStatus
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
display_name: str | None = None
|
||||
|
||||
|
||||
class UserRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
email: str
|
||||
display_name: str | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class UserStoreAccountCreate(BaseModel):
|
||||
user_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
session_data: dict | None = None
|
||||
status: AccountStatus = AccountStatus.ACTIVE
|
||||
|
||||
|
||||
class UserStoreAccountRead(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
id: uuid.UUID
|
||||
user_id: uuid.UUID
|
||||
store_id: uuid.UUID
|
||||
status: AccountStatus
|
||||
session_expires_at: datetime | None
|
||||
last_sync_at: datetime | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
Reference in New Issue
Block a user