HR-ATS-Portal/backend/offer/views.py

147 lines
5.5 KiB
Python

import uuid
from datetime import datetime,timezone
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from offer.models import Offers,OfferStatusHistory
from offer.serializers import serialize_offer
from offer.plugins import non_validation_values
def _as_uuid(value):
if value in (None,""):
return None
try:
return uuid.UUID(str(value))
except (TypeError,ValueError):
return None
def _user_id(current_user):
if not current_user or not current_user.get("id"):
raise HTTPException(status_code=401,detail="Not authenticated")
uid=_as_uuid(current_user["id"])
if uid is None:
raise HTTPException(status_code=401,detail="Invalid user id")
return uid
class Offer:
def __init__(self,session:AsyncSession):
self.session=session
async def get_offers(self,offer_id=None,status=None,inbox_id=None,top=None,skip=0):
if offer_id is not None:
row=await Offers.get_offer_by_id(self.session,offer_id)
if not row:
raise HTTPException(status_code=404,detail="Offer not found")
return serialize_offer(row),1
rows,total=await Offers.fetch_offers(
self.session,
status=status,
inbox_id=inbox_id,
top=top,
skip=skip or 0,
)
return [serialize_offer(r) for r in rows],total
async def create_offer(self,payload,current_user):
if not payload.get("inbox_id"):
raise HTTPException(status_code=422,detail="inbox_id is required")
job_post_id=_as_uuid(payload.get("job_post_id"))
if job_post_id is None:
raise HTTPException(status_code=422,detail="job_post_id is required")
candidate_user_id=_as_uuid(payload.get("candidate_user_id"))
if candidate_user_id is None:
raise HTTPException(status_code=422,detail="candidate_user_id is required")
created_by=_user_id(current_user)
status=payload.get("status") or "draft"
fields={
"inbox_id": int(payload["inbox_id"]),
"job_post_id": job_post_id,
"candidate_user_id": candidate_user_id,
"created_by": created_by,
"status": status,
}
for key in non_validation_values():
if key in payload and payload[key] is not None:
fields[key]=payload[key]
row=await Offers.insert_offer(self.session,fields)
history_data={
"offer_id": row.id,
"from_status": None,
"to_status": status,
"changed_by": created_by,
"actor_kind": "user",
"change_reason": payload.get("change_reason"),
}
await OfferStatusHistory.insert_history(self.session,history_data)
return serialize_offer(row)
async def update_offer(self,offer_id,payload,current_user):
row=await Offers.get_offer_by_id(self.session,offer_id)
if not row:
raise HTTPException(status_code=404,detail="Offer not found")
changed_by=_user_id(current_user)
fields={}
for key in (
"status","base_salary","currency","salary_period","signing_bonus","annual_bonus_pct",
"equity_units","equity_instrument","start_date","expiry_date","sent_at",
"responded_at","closed_at","issued_by","inbox_id","job_post_id","candidate_user_id",
):
if key not in payload:
continue
value=payload[key]
if key in ("job_post_id","candidate_user_id","issued_by") and value is not None:
value=_as_uuid(value)
if value is None:
raise HTTPException(status_code=422,detail=f"Invalid {key}")
fields[key]=value
if not fields:
raise HTTPException(status_code=400,detail="No fields to update")
new_status=fields.get("status")
if new_status is not None and new_status!=row.status:
await OfferStatusHistory.insert_history(self.session,{
"offer_id": row.id,
"from_status": row.status,
"to_status": new_status,
"changed_by": changed_by,
"actor_kind": "user",
"change_reason": payload.get("change_reason"),
},commit=False)
updated=await Offers.update_offer(self.session,offer_id,fields)
if not updated:
raise HTTPException(status_code=404,detail="Offer not found")
return serialize_offer(updated)
async def issue_offer(self,offer_id,current_user):
row=await Offers.get_offer_by_id(self.session,offer_id)
if not row:
raise HTTPException(status_code=404,detail="Offer not found")
issued_by=_user_id(current_user)
now=datetime.now(timezone.utc)
from_status=row.status
fields={"issued_by": issued_by,"sent_at": now}
to_status=from_status
if from_status=="draft":
fields["status"]="sent"
to_status="sent"
updated=await Offers.update_offer(self.session,offer_id,fields)
if not updated:
raise HTTPException(status_code=404,detail="Offer not found")
history_data={
"offer_id": updated.id,
"from_status": from_status,
"to_status": to_status,
"changed_by": issued_by,
"actor_kind": "user",
"change_reason": "issued",
}
await OfferStatusHistory.insert_history(self.session,history_data)
return serialize_offer(updated)