NPC shop implimented
This commit is contained in:
181
api/app/models/transaction.py
Normal file
181
api/app/models/transaction.py
Normal file
@@ -0,0 +1,181 @@
|
||||
"""
|
||||
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})"
|
||||
)
|
||||
Reference in New Issue
Block a user