182 lines
5.9 KiB
Python
182 lines
5.9 KiB
Python
"""
|
|
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})"
|
|
)
|