Add shop
This commit is contained in:
199
backend/app/schemas/shop.py
Normal file
199
backend/app/schemas/shop.py
Normal file
@@ -0,0 +1,199 @@
|
||||
"""
|
||||
Pydantic schemas for Shop system
|
||||
"""
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Any
|
||||
|
||||
|
||||
# === Shop Items ===
|
||||
|
||||
class ShopItemBase(BaseModel):
|
||||
"""Base schema for shop items"""
|
||||
item_type: str
|
||||
code: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
price: int
|
||||
rarity: str = "common"
|
||||
asset_data: dict | None = None
|
||||
|
||||
|
||||
class ShopItemCreate(ShopItemBase):
|
||||
"""Schema for creating a shop item (admin)"""
|
||||
is_active: bool = True
|
||||
available_from: datetime | None = None
|
||||
available_until: datetime | None = None
|
||||
stock_limit: int | None = None
|
||||
|
||||
|
||||
class ShopItemUpdate(BaseModel):
|
||||
"""Schema for updating a shop item (admin)"""
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
price: int | None = Field(None, ge=1)
|
||||
rarity: str | None = None
|
||||
asset_data: dict | None = None
|
||||
is_active: bool | None = None
|
||||
available_from: datetime | None = None
|
||||
available_until: datetime | None = None
|
||||
stock_limit: int | None = None
|
||||
|
||||
|
||||
class ShopItemResponse(ShopItemBase):
|
||||
"""Schema for shop item response"""
|
||||
id: int
|
||||
is_active: bool
|
||||
available_from: datetime | None
|
||||
available_until: datetime | None
|
||||
stock_limit: int | None
|
||||
stock_remaining: int | None
|
||||
created_at: datetime
|
||||
is_available: bool # Computed property
|
||||
is_owned: bool = False # Set by API based on user
|
||||
is_equipped: bool = False # Set by API based on user
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# === Inventory ===
|
||||
|
||||
class InventoryItemResponse(BaseModel):
|
||||
"""Schema for user inventory item"""
|
||||
id: int
|
||||
item: ShopItemResponse
|
||||
quantity: int
|
||||
equipped: bool
|
||||
purchased_at: datetime
|
||||
expires_at: datetime | None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# === Purchases ===
|
||||
|
||||
class PurchaseRequest(BaseModel):
|
||||
"""Schema for purchase request"""
|
||||
item_id: int
|
||||
quantity: int = Field(default=1, ge=1, le=10)
|
||||
|
||||
|
||||
class PurchaseResponse(BaseModel):
|
||||
"""Schema for purchase response"""
|
||||
success: bool
|
||||
item: ShopItemResponse
|
||||
quantity: int
|
||||
total_cost: int
|
||||
new_balance: int
|
||||
message: str
|
||||
|
||||
|
||||
# === Consumables ===
|
||||
|
||||
class UseConsumableRequest(BaseModel):
|
||||
"""Schema for using a consumable"""
|
||||
item_code: str # 'skip', 'shield', 'boost', 'reroll'
|
||||
marathon_id: int
|
||||
assignment_id: int | None = None # Required for skip and reroll
|
||||
|
||||
|
||||
class UseConsumableResponse(BaseModel):
|
||||
"""Schema for consumable use response"""
|
||||
success: bool
|
||||
item_code: str
|
||||
remaining_quantity: int
|
||||
effect_description: str
|
||||
effect_data: dict | None = None
|
||||
|
||||
|
||||
# === Equipment ===
|
||||
|
||||
class EquipItemRequest(BaseModel):
|
||||
"""Schema for equipping an item"""
|
||||
inventory_id: int
|
||||
|
||||
|
||||
class EquipItemResponse(BaseModel):
|
||||
"""Schema for equip response"""
|
||||
success: bool
|
||||
item_type: str
|
||||
equipped_item: ShopItemResponse | None
|
||||
message: str
|
||||
|
||||
|
||||
# === Coins ===
|
||||
|
||||
class CoinTransactionResponse(BaseModel):
|
||||
"""Schema for coin transaction"""
|
||||
id: int
|
||||
amount: int
|
||||
transaction_type: str
|
||||
description: str | None
|
||||
reference_type: str | None
|
||||
reference_id: int | None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CoinsBalanceResponse(BaseModel):
|
||||
"""Schema for coins balance with recent transactions"""
|
||||
balance: int
|
||||
recent_transactions: list[CoinTransactionResponse]
|
||||
|
||||
|
||||
class AdminCoinsRequest(BaseModel):
|
||||
"""Schema for admin coin operations"""
|
||||
amount: int = Field(..., ge=1)
|
||||
reason: str = Field(..., min_length=1, max_length=500)
|
||||
|
||||
|
||||
# === User Cosmetics ===
|
||||
|
||||
class UserCosmeticsResponse(BaseModel):
|
||||
"""Schema for user's equipped cosmetics"""
|
||||
frame: ShopItemResponse | None = None
|
||||
title: ShopItemResponse | None = None
|
||||
name_color: ShopItemResponse | None = None
|
||||
background: ShopItemResponse | None = None
|
||||
|
||||
|
||||
# === Certification ===
|
||||
|
||||
class CertificationRequestSchema(BaseModel):
|
||||
"""Schema for requesting marathon certification"""
|
||||
pass # No fields needed for now
|
||||
|
||||
|
||||
class CertificationReviewRequest(BaseModel):
|
||||
"""Schema for admin reviewing certification"""
|
||||
approve: bool
|
||||
rejection_reason: str | None = Field(None, max_length=1000)
|
||||
|
||||
|
||||
class CertificationStatusResponse(BaseModel):
|
||||
"""Schema for certification status"""
|
||||
marathon_id: int
|
||||
certification_status: str
|
||||
is_certified: bool
|
||||
certification_requested_at: datetime | None
|
||||
certified_at: datetime | None
|
||||
certified_by_nickname: str | None = None
|
||||
rejection_reason: str | None = None
|
||||
|
||||
|
||||
# === Consumables Status ===
|
||||
|
||||
class ConsumablesStatusResponse(BaseModel):
|
||||
"""Schema for participant's consumables status in a marathon"""
|
||||
skips_available: int # From inventory
|
||||
skips_used: int # In this marathon
|
||||
skips_remaining: int | None # Based on marathon limit
|
||||
has_shield: bool
|
||||
has_active_boost: bool
|
||||
boost_multiplier: float | None
|
||||
boost_expires_at: datetime | None
|
||||
rerolls_available: int # From inventory
|
||||
Reference in New Issue
Block a user