52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""Point ledger validators — Phase 7.2."""
|
|
from __future__ import annotations
|
|
|
|
from shared.exceptions import AppError
|
|
|
|
from app.models.types import LedgerEntryType, PointAccountStatus
|
|
|
|
|
|
def ensure_account_open(status: PointAccountStatus) -> None:
|
|
if status == PointAccountStatus.CLOSED:
|
|
raise AppError(
|
|
"حساب امتیاز بسته است",
|
|
status_code=409,
|
|
error_code="point_account_closed",
|
|
)
|
|
if status == PointAccountStatus.FROZEN:
|
|
raise AppError(
|
|
"حساب امتیاز مسدود است",
|
|
status_code=409,
|
|
error_code="point_account_frozen",
|
|
)
|
|
|
|
|
|
def validate_positive_points(amount: int, *, field: str = "amount") -> int:
|
|
if amount is None or amount <= 0:
|
|
raise AppError(
|
|
f"{field} باید بزرگتر از صفر باشد",
|
|
status_code=422,
|
|
error_code="invalid_points_amount",
|
|
details={"field": field},
|
|
)
|
|
return amount
|
|
|
|
|
|
def validate_adjust_amount(amount: int) -> int:
|
|
if amount == 0:
|
|
raise AppError(
|
|
"مقدار تعدیل نمیتواند صفر باشد",
|
|
status_code=422,
|
|
error_code="invalid_adjust_amount",
|
|
)
|
|
return amount
|
|
|
|
|
|
def signed_amount(entry_type: LedgerEntryType, amount: int) -> int:
|
|
if entry_type in {LedgerEntryType.EARN}:
|
|
return abs(amount)
|
|
if entry_type in {LedgerEntryType.REDEEM, LedgerEntryType.EXPIRE}:
|
|
return -abs(amount)
|
|
# ADJUST: caller supplies signed amount
|
|
return amount
|