149 lines
5.7 KiB
Python
149 lines
5.7 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",
|
|
"cadre","gross_salary_in_words","subsidized_services","probation_period",
|
|
"notice_period","work_location","work_timings",
|
|
):
|
|
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)
|