HR-ATS-Portal/backend/job/feedback/views.py

139 lines
6.1 KiB
Python

from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from sqlmodel import select
from job.candidate.models import Feedback
from job.feedback.models import FeedbackTemplates
from job.feedback.serializers import serialize_feedback, serialize_feedback_template
from job.history.enums import HistoryEvent
from job.history.views import HistoryRecorder
class FeedbackView:
def __init__(self,session:AsyncSession):
self.session=session
async def _load(self,record_id):
uid=Feedback._as_uuid(record_id)
if uid is None:
return None
result=await self.session.execute(
select(Feedback).options(selectinload(Feedback.user)).where(Feedback.id==uid)
)
return result.scalars().first()
async def get_feedback(self,feedback_id=None,inbox_id=None):
if feedback_id:
row=await self._load(feedback_id)
if not row:
raise HTTPException(status_code=404,detail="Feedback not found")
return serialize_feedback(row)
if inbox_id is None:
raise HTTPException(status_code=400,detail="feedback_id or inbox_id is required")
result=await self.session.execute(
select(Feedback)
.options(selectinload(Feedback.user))
.where(Feedback.inbox_id==int(inbox_id))
.order_by(Feedback.created_at.desc())
)
return [serialize_feedback(r) for r in result.scalars().all()]
async def create_feedback(self,payload,current_user):
fields={
"review":payload.get("review") or "",
"financial_status":payload.get("financial_status") or "",
"score":payload.get("score") if payload.get("score") is not None else 0.0,
"note":payload.get("note"),
"inbox_id":payload.get("inbox_id"),
"reviewed_by":payload.get("reviewed_by") or (
current_user.get("id") if isinstance(current_user,dict) else None
),
}
row=await Feedback.insert_feedback(self.session,fields)
desc=row.note or None
await HistoryRecorder(self.session).record(
HistoryEvent.FEEDBACK_CREATED.value,
current_user=current_user,inbox_id=row.inbox_id,
entity_type="feedback",entity_id=row.id,
to_value=row.review or None,description=desc,commit=True,
)
row=await self._load(row.id)
return serialize_feedback(row)
async def update_feedback(self,feedback_id,payload,current_user=None):
allowed=("review","financial_status","score","note","inbox_id","reviewed_by")
fields={k:v for k,v in payload.items() if v is not None and k in allowed}
if not fields:
raise HTTPException(status_code=400,detail="No fields to update")
before=await self._load(feedback_id)
if not before:
raise HTTPException(status_code=404,detail="Feedback not found")
old_review=before.review or ""
old_score=before.score
row=await Feedback.update_feedback(self.session,feedback_id,fields)
if not row:
raise HTTPException(status_code=404,detail="Feedback not found")
desc=row.note
if old_score!=row.score:
desc=f"score {old_score}{row.score}"
await HistoryRecorder(self.session).record(
HistoryEvent.FEEDBACK_UPDATED.value,
current_user=current_user,inbox_id=row.inbox_id,
entity_type="feedback",entity_id=row.id,
from_value=old_review,to_value=row.review or None,
description=desc,commit=True,
)
row=await self._load(row.id)
return serialize_feedback(row)
async def get_templates(self):
rows,total=await FeedbackTemplates.fetch_templates(self.session)
return [serialize_feedback_template(r) for r in rows],total
async def create_template(self,payload,current_user):
name=(payload.get("name") or "").strip()
if not name:
raise HTTPException(status_code=422,detail="name is required")
criteria=payload.get("criteria") or []
if not isinstance(criteria,list) or not all(isinstance(c,str) for c in criteria):
raise HTTPException(status_code=422,detail="criteria must be a list of strings")
fields={
"name":name,
"department":payload.get("department"),
"criteria":[c.strip() for c in criteria if str(c).strip()],
"is_active":payload.get("is_active") if payload.get("is_active") is not None else True,
"created_by":current_user.get("id") if isinstance(current_user,dict) else None,
}
row=await FeedbackTemplates.insert_template(self.session,fields)
return serialize_feedback_template(row)
async def update_template(self,template_id,payload):
allowed=("name","department","criteria","is_active")
fields={}
for key in allowed:
if key not in payload:
continue
value=payload[key]
if key=="name":
value=(value or "").strip()
if not value:
raise HTTPException(status_code=422,detail="name cannot be blank")
elif key=="criteria":
if value is not None and (not isinstance(value,list) or not all(isinstance(c,str) for c in value)):
raise HTTPException(status_code=422,detail="criteria must be a list of strings")
value=[c.strip() for c in (value or []) if str(c).strip()]
fields[key]=value
if not fields:
raise HTTPException(status_code=400,detail="No fields to update")
row=await FeedbackTemplates.update_template(self.session,template_id,fields)
if not row:
raise HTTPException(status_code=404,detail="Template not found")
return serialize_feedback_template(row)
async def delete_template(self,template_id):
row=await FeedbackTemplates.soft_delete_template(self.session,template_id)
if not row:
raise HTTPException(status_code=404,detail="Template not found")
return {"id":str(row.id),"deleted":True}