This commit is contained in:
2026-01-05 07:15:50 +07:00
parent 65b2512d8c
commit 6a7717a474
44 changed files with 5678 additions and 183 deletions

View File

@@ -0,0 +1,81 @@
from datetime import datetime
from enum import Enum
from sqlalchemy import String, Text, DateTime, Integer, Boolean, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from typing import TYPE_CHECKING
from app.core.database import Base
if TYPE_CHECKING:
from app.models.inventory import UserInventory
class ShopItemType(str, Enum):
FRAME = "frame"
TITLE = "title"
NAME_COLOR = "name_color"
BACKGROUND = "background"
CONSUMABLE = "consumable"
class ItemRarity(str, Enum):
COMMON = "common"
UNCOMMON = "uncommon"
RARE = "rare"
EPIC = "epic"
LEGENDARY = "legendary"
class ConsumableType(str, Enum):
SKIP = "skip"
SHIELD = "shield"
BOOST = "boost"
REROLL = "reroll"
class ShopItem(Base):
__tablename__ = "shop_items"
id: Mapped[int] = mapped_column(primary_key=True)
item_type: Mapped[str] = mapped_column(String(30), nullable=False, index=True)
code: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
name: Mapped[str] = mapped_column(String(100), nullable=False)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
price: Mapped[int] = mapped_column(Integer, nullable=False)
rarity: Mapped[str] = mapped_column(String(20), default=ItemRarity.COMMON.value)
asset_data: Mapped[dict | None] = mapped_column(JSON, nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
available_from: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
available_until: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
stock_limit: Mapped[int | None] = mapped_column(Integer, nullable=True)
stock_remaining: Mapped[int | None] = mapped_column(Integer, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Relationships
inventory_items: Mapped[list["UserInventory"]] = relationship(
"UserInventory",
back_populates="item"
)
@property
def is_available(self) -> bool:
"""Check if item is currently available for purchase"""
if not self.is_active:
return False
now = datetime.utcnow()
if self.available_from and self.available_from > now:
return False
if self.available_until and self.available_until < now:
return False
if self.stock_remaining is not None and self.stock_remaining <= 0:
return False
return True
@property
def is_consumable(self) -> bool:
return self.item_type == ShopItemType.CONSUMABLE.value