"""Money value object. Money represents a monetary amount with currency. """ from decimal import Decimal from typing import Any, Union class Money: """Money value object. Represents a monetary amount with currency. Immutable and provides monetary operations. Attributes: amount: Decimal amount currency: Currency code (e.g., 'IRR', 'USD') """ def __init__(self, amount: Union[Decimal, int, float, str], currency: str = "IRR"): """Initialize money. Args: amount: Monetary amount currency: Currency code (default: IRR for Iranian Rial) Raises: ValueError: If amount is negative or currency is invalid """ self._amount = Decimal(str(amount)) if self._amount < 0: raise ValueError("Amount cannot be negative") if not currency or len(currency) != 3: raise ValueError(f"Invalid currency code: {currency}") self._currency = currency.upper() @property def amount(self) -> Decimal: """Get amount. Returns: Decimal: Amount """ return self._amount @property def currency(self) -> str: """Get currency. Returns: str: Currency code """ return self._currency def add(self, other: "Money") -> "Money": """Add two money values. Args: other: Other money value Returns: Money: New money object with sum Raises: ValueError: If currencies don't match """ self._check_currency(other) return Money(self._amount + other._amount, self._currency) def subtract(self, other: "Money") -> "Money": """Subtract money value. Args: other: Other money value Returns: Money: New money object with difference Raises: ValueError: If currencies don't match or result is negative """ self._check_currency(other) result = self._amount - other._amount if result < 0: raise ValueError("Result cannot be negative") return Money(result, self._currency) def multiply(self, multiplier: Union[int, float, Decimal]) -> "Money": """Multiply amount by a factor. Args: multiplier: Multiplication factor Returns: Money: New money object """ result = self._amount * Decimal(str(multiplier)) return Money(result, self._currency) def _check_currency(self, other: "Money") -> None: """Check if currencies match. Args: other: Other money value Raises: ValueError: If currencies don't match """ if self._currency != other._currency: raise ValueError( f"Currency mismatch: {self._currency} vs {other._currency}" ) def __str__(self) -> str: """String representation. Returns: str: Formatted money string """ return f"{self._amount:,.2f} {self._currency}" def __repr__(self) -> str: """Developer representation. Returns: str: Money representation """ return f"Money({self._amount}, '{self._currency}')" def __eq__(self, other: Any) -> bool: """Check equality. Args: other: Other object Returns: bool: True if equal """ if not isinstance(other, Money): return False return self._amount == other._amount and self._currency == other._currency def __lt__(self, other: "Money") -> bool: """Less than comparison. Args: other: Other money value Returns: bool: True if less than """ self._check_currency(other) return self._amount < other._amount def __le__(self, other: "Money") -> bool: """Less than or equal comparison. Args: other: Other money value Returns: bool: True if less than or equal """ self._check_currency(other) return self._amount <= other._amount def __gt__(self, other: "Money") -> bool: """Greater than comparison. Args: other: Other money value Returns: bool: True if greater than """ self._check_currency(other) return self._amount > other._amount def __ge__(self, other: "Money") -> bool: """Greater than or equal comparison. Args: other: Other money value Returns: bool: True if greater than or equal """ self._check_currency(other) return self._amount >= other._amount def __hash__(self) -> int: """Hash value. Returns: int: Hash """ return hash((self._amount, self._currency))