TorbatYar/backend/services/experience/app/validators/foundation.py
Mortezakoohjani 0d424c500a feat(platform): complete commercial runtime consolidation
Unify commercial runtime ownership across backend and frontend so platform, experience, and hospitality modules use the shared commercial source of truth.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-29 11:11:53 +03:30

57 lines
1.8 KiB
Python

"""Reusable validators for Experience foundation."""
from __future__ import annotations
import re
from typing import Any
from shared.exceptions import AppError
CODE_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_\-]{1,49}$")
class ValidationError(AppError):
def __init__(self, message: str, details: dict[str, Any] | None = None):
super().__init__(
message=message,
error_code="validation_error",
status_code=422,
details=details or {},
)
def validate_non_empty(value: str | None, field: str) -> str:
if value is None or not str(value).strip():
raise ValidationError(f"{field} الزامی است", {"field": field})
return str(value).strip()
def validate_code(code: str) -> str:
code = validate_non_empty(code, "code")
if not CODE_RE.match(code):
raise ValidationError(
"کد نامعتبر است — فقط لاتین/عدد/_/- و حداقل ۲ کاراکتر "
"(مثال: main-shop یا ws_01). فارسی و فاصله مجاز نیست.",
{"field": "code", "pattern": CODE_RE.pattern},
)
return code
def validate_currency_code(code: str) -> str:
code = validate_non_empty(code, "currency_code").upper()
if len(code) != 3:
raise ValidationError("currency_code باید ۳ حرفی باشد", {"field": "currency_code"})
return code
def ensure_optimistic_version(entity: Any, expected: int) -> None:
current = getattr(entity, "version", None)
if current is None:
return
if current != expected:
raise AppError(
"نسخه موجودیت هم‌خوان نیست",
error_code="version_conflict",
status_code=409,
details={"expected": expected, "actual": current},
)