96 lines
3.2 KiB
Python
96 lines
3.2 KiB
Python
"""Wallet Engine validators — Phase 7.6."""
|
|
from __future__ import annotations
|
|
|
|
from shared.exceptions import AppError
|
|
|
|
from app.models.types import WalletAccountStatus, WalletLedgerEntryType
|
|
|
|
|
|
def validate_wallet_account_status(
|
|
status: WalletAccountStatus | str,
|
|
) -> WalletAccountStatus:
|
|
if isinstance(status, WalletAccountStatus):
|
|
return status
|
|
try:
|
|
return WalletAccountStatus(status)
|
|
except ValueError as exc:
|
|
raise AppError(
|
|
"وضعیت کیف پول نامعتبر است",
|
|
status_code=422,
|
|
error_code="invalid_wallet_account_status",
|
|
) from exc
|
|
|
|
|
|
def ensure_wallet_open(status: WalletAccountStatus) -> None:
|
|
if status == WalletAccountStatus.CLOSED:
|
|
raise AppError(
|
|
"کیف پول بسته است",
|
|
status_code=409,
|
|
error_code="wallet_account_closed",
|
|
)
|
|
if status == WalletAccountStatus.FROZEN:
|
|
raise AppError(
|
|
"کیف پول مسدود است",
|
|
status_code=409,
|
|
error_code="wallet_account_frozen",
|
|
)
|
|
|
|
|
|
def validate_positive_amount(amount: int, *, field: str = "amount") -> int:
|
|
if amount is None or amount <= 0:
|
|
raise AppError(
|
|
f"{field} باید بزرگتر از صفر باشد",
|
|
status_code=422,
|
|
error_code="invalid_wallet_amount",
|
|
details={"field": field},
|
|
)
|
|
return amount
|
|
|
|
|
|
def validate_adjust_amount(amount: int) -> int:
|
|
if amount == 0:
|
|
raise AppError(
|
|
"مقدار تعدیل نمیتواند صفر باشد",
|
|
status_code=422,
|
|
error_code="invalid_wallet_adjust_amount",
|
|
)
|
|
return amount
|
|
|
|
|
|
def signed_amount(entry_type: WalletLedgerEntryType, amount: int) -> int:
|
|
if entry_type in {WalletLedgerEntryType.CREDIT, WalletLedgerEntryType.TRANSFER_IN}:
|
|
return abs(amount)
|
|
if entry_type in {WalletLedgerEntryType.DEBIT, WalletLedgerEntryType.TRANSFER_OUT}:
|
|
return -abs(amount)
|
|
# ADJUST: caller supplies signed amount
|
|
return amount
|
|
|
|
|
|
def ensure_sufficient_funds(balance: int, new_balance: int, *, requested: int) -> None:
|
|
if new_balance < 0:
|
|
raise AppError(
|
|
"موجودی کیف پول کافی نیست",
|
|
status_code=409,
|
|
error_code="wallet_insufficient_funds",
|
|
details={"balance": balance, "requested": requested},
|
|
)
|
|
|
|
|
|
def ensure_same_currency(source_currency: str, target_currency: str) -> None:
|
|
if source_currency != target_currency:
|
|
raise AppError(
|
|
"انتقال بین ارزهای متفاوت مجاز نیست",
|
|
status_code=422,
|
|
error_code="wallet_currency_mismatch",
|
|
details={"source": source_currency, "target": target_currency},
|
|
)
|
|
|
|
|
|
def ensure_not_same_account(source_id, target_id) -> None:
|
|
if source_id == target_id:
|
|
raise AppError(
|
|
"انتقال به همان کیف پول مجاز نیست",
|
|
status_code=422,
|
|
error_code="wallet_transfer_same_account",
|
|
)
|