126 lines
5.7 KiB
Python
126 lines
5.7 KiB
Python
from fastapi import HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
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):
|
|
return await Feedback.get_feedback_by_id(self.session,record_id)
|
|
|
|
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")
|
|
rows=await Feedback.get_feedback_by_inbox(self.session,int(inbox_id))
|
|
return [serialize_feedback(r) for r in rows]
|
|
|
|
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}
|