Add frontend/modules/loyalty with types, API client, design system, feature pages and thin App Router routes under app/loyalty/. BFF proxy at app/api/loyalty/. Include loyalty frontend docs. Co-authored-by: Cursor <cursoragent@cursor.com>
27 lines
903 B
Python
27 lines
903 B
Python
"""Appointment domain policies — Phase 14.1."""
|
|
from __future__ import annotations
|
|
|
|
from app.models.types import AppointmentLifecycleAction, AppointmentStatus
|
|
from app.validators.appointments import (
|
|
ensure_appointment_lifecycle_transition,
|
|
target_status_for,
|
|
validate_reason,
|
|
)
|
|
|
|
|
|
class AppointmentLifecyclePolicy:
|
|
REQUIRES_REASON = frozenset(
|
|
{AppointmentLifecycleAction.CANCEL, AppointmentLifecycleAction.NO_SHOW}
|
|
)
|
|
|
|
def assert_transition(
|
|
self,
|
|
*,
|
|
action: AppointmentLifecycleAction,
|
|
current: AppointmentStatus,
|
|
reason: str | None = None,
|
|
) -> tuple[AppointmentStatus, str | None]:
|
|
ensure_appointment_lifecycle_transition(action=action, current=current)
|
|
cleaned = validate_reason(reason, required=action in self.REQUIRES_REASON)
|
|
return target_status_for(action), cleaned
|