HR-ATS-Portal/backend/talent/enums.py

59 lines
1.8 KiB
Python

from enum import Enum
class OutreachStatus(str, Enum):
"""Manual outreach funnel on talent_profiles.outreach_status.
The app never sends messages: a recruiter shortlists a sourced profile,
reaches out on LinkedIn themselves, then marks the profile contacted.
Values are the wire form the Find Talent screen PATCHes; labels are what
the tabs render.
"""
SOURCED = "sourced"
SHORTLISTED = "shortlisted"
CONTACTED = "contacted"
@property
def label(self) -> str:
return _LABELS[self]
@classmethod
def parse(cls, value):
"""Accept the stored value or the UI label. None if neither matches."""
raw = (value or "").strip()
if not raw:
return None
lowered = raw.lower()
for member in cls:
if raw == member.value or lowered == member.value or raw == member.label:
return member
return None
@classmethod
def values(cls) -> tuple[str, ...]:
return tuple(m.value for m in cls)
@classmethod
def as_list(cls) -> list[dict]:
return [{"value": m.value, "label": m.label} for m in cls]
_LABELS = {
OutreachStatus.SOURCED: "Sourced",
OutreachStatus.SHORTLISTED: "Shortlisted",
OutreachStatus.CONTACTED: "Contacted",
}
# One-way funnel with single-step undo. sourced -> contacted is disallowed so
# every contacted row carries shortlist stamps, and contacted -> sourced is
# disallowed so un-shortlisting a contacted profile takes two deliberate steps.
ALLOWED_OUTREACH_TRANSITIONS = {
OutreachStatus.SOURCED.value: {OutreachStatus.SHORTLISTED.value},
OutreachStatus.SHORTLISTED.value: {
OutreachStatus.SOURCED.value,
OutreachStatus.CONTACTED.value,
},
OutreachStatus.CONTACTED.value: {OutreachStatus.SHORTLISTED.value},
}