189 lines
8.0 KiB
Python
189 lines
8.0 KiB
Python
from inbox.models import Inbox
|
|
from typing import Any,List,Dict
|
|
|
|
from job.candidate.plugins import documents_from_message, source_from_message_to
|
|
from job.interviews.serializers import serialize_interview
|
|
from job.activity.serializers import serialize_activity
|
|
from job.feedback.serializers import serialize_feedback
|
|
from job.job_post.serializers import serialize_job_post
|
|
|
|
def serialize_candidate(row) -> dict:
|
|
return {
|
|
"id": str(row.id),
|
|
"job_id": str(row.job_id),
|
|
"source": row.source,
|
|
"filename": row.filename,
|
|
"file_path": row.file_path,
|
|
"content_sha256": row.content_sha256,
|
|
"candidate_email": row.candidate_email,
|
|
"candidate_name": row.candidate_name,
|
|
"job_title": row.job_title,
|
|
"current_company": row.current_company,
|
|
"years_experience": row.years_experience,
|
|
"match_score": row.match_score,
|
|
"matched_keywords": list(row.matched_keywords or []),
|
|
"missing_keywords": list(row.missing_keywords or []),
|
|
"summary_critique": row.summary_critique,
|
|
"status": row.status,
|
|
"error_code": row.error_code,
|
|
"error_message": row.error_message,
|
|
"model": row.model,
|
|
"created_by": str(row.created_by),
|
|
"created_at": row.created_at.isoformat() if row.created_at else None,
|
|
"updated_at": row.updated_at.isoformat() if row.updated_at else None,
|
|
}
|
|
|
|
|
|
def serialize_manual_upload_candidate(row) -> Dict[str,Any]:
|
|
return {
|
|
"id":str(row.id) if row.id else None,
|
|
"candidate_email":row.candidate_email,
|
|
"candidate_name":row.candidate_name,
|
|
"candidate_phone":row.candidate_phone,
|
|
"job_post_id":str(row.job_post_id) if row.job_post_id else None,
|
|
"full_text":row.full_text,
|
|
"current_company":row.current_company,
|
|
"current_position":row.current_position,
|
|
"apply_via":row.apply_via,
|
|
"user_id":str(row.user_id) if row.user_id else None,
|
|
"platform":row.platform,
|
|
"created_by":str(row.created_by) if row.created_by else None,
|
|
"experience":row.experience,
|
|
"status":row.status,
|
|
"referral_by":row.referral_by,
|
|
"file_name":row.file_name,
|
|
"file_path":row.file_path,
|
|
"created_at":row.created_at.isoformat() if row.created_at else None,
|
|
"updated_at":row.updated_at.isoformat() if row.updated_at else None,
|
|
}
|
|
|
|
|
|
def serialize_candidate_profile(
|
|
link:Inbox|List[Inbox]|Dict[str,Any]|List[Dict[str,Any]],
|
|
*,
|
|
detail:bool=False,
|
|
) -> Dict[str,Any]|List[Dict[str,Any]]:
|
|
if isinstance(link,list):
|
|
return [serialize_candidate_profile(item,detail=detail) for item in link]
|
|
if isinstance(link,dict):
|
|
return link
|
|
|
|
user = link.user
|
|
message = link.messages
|
|
payload = {
|
|
"inbox_id": link.id,
|
|
"manual_upload_candidate_id": None,
|
|
"user_id": str(link.user_id) if link.user_id else None,
|
|
"candidate_id": None,
|
|
"name": user.name if user else None,
|
|
"email": user.email if user else None,
|
|
"is_active": user.is_active if user else None,
|
|
"message_id": str(link.message_id) if link.message_id else None,
|
|
"created_at": link.created_at.isoformat() if link.created_at else None,
|
|
"application_status": message.application_status if message else None,
|
|
"experience": message.experience if message else None,
|
|
"current_employment": message.current_employment if message else None,
|
|
"current_title": message.current_title if message else None,
|
|
"resume_text": message.resume_text if message else None,
|
|
"suggested_job_post_ids": list(message.suggested_job_post_ids or []) if message else [],
|
|
"assigned_job_post_id": str(message.assigned_job_post_id) if message and message.assigned_job_post_id else None,
|
|
"match_summary": message.match_summary if message else None,
|
|
"match_reasoning": message.match_reasoning if message else None,
|
|
"match_status": message.match_status if message else None,
|
|
"match_error": message.match_error if message else None,
|
|
"matched_at": message.matched_at.isoformat() if message and message.matched_at else None,
|
|
"job_posts": [],
|
|
}
|
|
if not detail:
|
|
return payload
|
|
|
|
payload.update({
|
|
"favorite": link.favorite,
|
|
"rating": link.rating,
|
|
"phone": message.candidate_phone_number if message else None,
|
|
"education": message.candidate_education if message else None,
|
|
"currentCompany": message.current_employment if message else None,
|
|
"current_title": message.current_title if message else None,
|
|
"stage": message.application_status if message else None,
|
|
"source": source_from_message_to(message.message_to if message else None),
|
|
"applied": message.message_received_time if message else None,
|
|
"documents": documents_from_message(
|
|
message.file_name if message else None,
|
|
message.file_path if message else None,
|
|
),
|
|
"recruiter": None,
|
|
"recruiter_id": None,
|
|
"job_title": None,
|
|
"ai_score": None,
|
|
"recommendation": None,
|
|
"sub_scores": None,
|
|
"interviews": [serialize_interview(r) for r in (link.interviews or [])],
|
|
"activity": [serialize_activity(r) for r in (link.activity or [])],
|
|
"feedback": [serialize_feedback(r) for r in (link.feedback or [])],
|
|
"notes": [],
|
|
})
|
|
return payload
|
|
|
|
|
|
def serialize_manual_candidate_profile(row, user, job_post) -> Dict[str, Any]:
|
|
"""Same key vocabulary as serialize_candidate_profile(detail=True).
|
|
|
|
Manual uploads never go through inbox, so current_position maps onto
|
|
current_title here and the agent/ATS fields stay empty.
|
|
"""
|
|
job_payload = serialize_job_post(job_post) if job_post else None
|
|
created = row.created_at.isoformat() if row.created_at else None
|
|
file_name = (row.file_name or "").strip() or None
|
|
file_path = (row.file_path or "").strip() or None
|
|
documents = [{"name": file_name or "", "path": file_path or ""}] if (file_name or file_path) else []
|
|
company = (row.current_company or "").strip() or None
|
|
position = (row.current_position or "").strip() or None
|
|
return {
|
|
"inbox_id": None,
|
|
"manual_upload_candidate_id": str(row.id),
|
|
"user_id": str(user.id) if user else (str(row.user_id) if row.user_id else None),
|
|
"candidate_id": None,
|
|
"name": (user.name if user else None) or row.candidate_name or None,
|
|
"email": (user.email if user else None) or row.candidate_email or None,
|
|
"is_active": user.is_active if user else None,
|
|
"message_id": None,
|
|
"created_at": created,
|
|
"application_status": row.status or None,
|
|
"experience": (row.experience or "").strip() or None,
|
|
"current_employment": company,
|
|
"current_title": position,
|
|
"resume_text": row.full_text or None,
|
|
"suggested_job_post_ids": [],
|
|
"assigned_job_post_id": str(row.job_post_id) if row.job_post_id else None,
|
|
"match_summary": None,
|
|
"match_reasoning": None,
|
|
"match_status": None,
|
|
"match_error": None,
|
|
"matched_at": None,
|
|
"job_posts": [job_payload] if job_payload else [],
|
|
"favorite": None,
|
|
"rating": None,
|
|
"phone": (row.candidate_phone or "").strip() or None,
|
|
"education": None,
|
|
"currentCompany": company,
|
|
"stage": row.status or None,
|
|
"source": (row.platform or "").strip() or None,
|
|
"applied": created,
|
|
"documents": documents,
|
|
"recruiter": job_payload.get("created_by_name") if job_payload else None,
|
|
"recruiter_id": job_payload.get("created_by") if job_payload else None,
|
|
"job_title": job_payload.get("title") if job_payload else None,
|
|
"ai_score": None,
|
|
"recommendation": None,
|
|
"sub_scores": None,
|
|
"interviews": [],
|
|
"activity": [],
|
|
"feedback": [],
|
|
"notes": [],
|
|
"assigned_job_post": job_payload,
|
|
"matched_keywords": [],
|
|
"missing_keywords": [],
|
|
"summary_critique": None,
|
|
"scored_at": None,
|
|
}
|