""" Transaction Model Tracks all gold transactions for audit and analytics purposes. Includes shop purchases, sales, quest rewards, trades, etc. """ from dataclasses import dataclass, field from datetime import datetime from typing import Dict, Any, Optional from enum import Enum class TransactionType(Enum): """Types of gold transactions.""" SHOP_PURCHASE = "shop_purchase" SHOP_SALE = "shop_sale" QUEST_REWARD = "quest_reward" ENEMY_LOOT = "enemy_loot" PLAYER_TRADE = "player_trade" NPC_GIFT = "npc_gift" SYSTEM_ADJUSTMENT = "system_adjustment" @dataclass class Transaction: """ Represents a gold transaction for audit logging. Attributes: transaction_id: Unique identifier for this transaction transaction_type: Type of transaction (purchase, sale, reward, etc.) character_id: Character involved in the transaction session_id: Game session where transaction occurred (for cleanup on session delete) amount: Gold amount (negative for expenses, positive for income) description: Human-readable description of the transaction timestamp: When the transaction occurred metadata: Additional context-specific data """ transaction_id: str transaction_type: TransactionType character_id: str session_id: Optional[str] = None # Session context for cleanup amount: int = 0 # Negative for expenses, positive for income description: str = "" timestamp: datetime = field(default_factory=datetime.utcnow) metadata: Dict[str, Any] = field(default_factory=dict) def to_dict(self) -> Dict[str, Any]: """ Serialize transaction to dictionary for storage. Returns: Dictionary containing all transaction data """ return { "transaction_id": self.transaction_id, "transaction_type": self.transaction_type.value, "character_id": self.character_id, "session_id": self.session_id, "amount": self.amount, "description": self.description, "timestamp": self.timestamp.isoformat(), "metadata": self.metadata, } @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'Transaction': """ Deserialize transaction from dictionary. Args: data: Dictionary containing transaction data Returns: Transaction instance """ return cls( transaction_id=data["transaction_id"], transaction_type=TransactionType(data["transaction_type"]), character_id=data["character_id"], session_id=data.get("session_id"), amount=data["amount"], description=data["description"], timestamp=datetime.fromisoformat(data["timestamp"]), metadata=data.get("metadata", {}), ) @classmethod def create_purchase( cls, transaction_id: str, character_id: str, shop_id: str, item_id: str, quantity: int, total_cost: int, session_id: Optional[str] = None ) -> 'Transaction': """ Factory method for creating a shop purchase transaction. Args: transaction_id: Unique transaction ID character_id: Character making the purchase shop_id: Shop where purchase was made item_id: Item purchased quantity: Number of items purchased total_cost: Total gold spent session_id: Optional session ID for cleanup tracking Returns: Transaction instance for the purchase """ return cls( transaction_id=transaction_id, transaction_type=TransactionType.SHOP_PURCHASE, character_id=character_id, session_id=session_id, amount=-total_cost, # Negative because spending gold description=f"Purchased {quantity}x {item_id} from {shop_id}", metadata={ "shop_id": shop_id, "item_id": item_id, "quantity": quantity, "unit_price": total_cost // quantity if quantity > 0 else 0, } ) @classmethod def create_sale( cls, transaction_id: str, character_id: str, shop_id: str, item_id: str, item_name: str, quantity: int, total_earned: int, session_id: Optional[str] = None ) -> 'Transaction': """ Factory method for creating a shop sale transaction. Args: transaction_id: Unique transaction ID character_id: Character making the sale shop_id: Shop where sale was made item_id: Item sold item_name: Display name of the item quantity: Number of items sold total_earned: Total gold earned session_id: Optional session ID for cleanup tracking Returns: Transaction instance for the sale """ return cls( transaction_id=transaction_id, transaction_type=TransactionType.SHOP_SALE, character_id=character_id, session_id=session_id, amount=total_earned, # Positive because receiving gold description=f"Sold {quantity}x {item_name} to {shop_id}", metadata={ "shop_id": shop_id, "item_id": item_id, "item_name": item_name, "quantity": quantity, "unit_price": total_earned // quantity if quantity > 0 else 0, } ) def __repr__(self) -> str: """String representation of the transaction.""" sign = "+" if self.amount >= 0 else "" return ( f"Transaction({self.transaction_type.value}, " f"{sign}{self.amount}g, {self.description})" )