TIF_E41253310/Backend/app/schemas/alumni.py

177 lines
6.5 KiB
Python

from pydantic import BaseModel, EmailStr, Field, ConfigDict, field_validator, model_validator
from datetime import datetime
from typing import Optional, Any, List, Dict
class AlumniBase(BaseModel):
nim: str = Field(..., description="Nomor Induk Mahasiswa (NIM)")
nama: str = Field(..., min_length=2, description="Nama lengkap alumni")
tahun_lulus: int = Field(..., ge=1900, le=2100, description="Tahun lulus alumni")
status_kerja: Optional[str] = Field(None, description="Status pekerjaan saat ini")
pekerjaan: Optional[str] = Field(None, description="Nama pekerjaan/posisi jika bekerja")
instansi: Optional[str] = Field(None, description="Nama instansi/perusahaan tempat bekerja")
no_hp: Optional[str] = Field(None, description="Nomor handphone/WhatsApp aktif")
email: Optional[str] = Field(None, description="Email aktif alumni")
kode_prodi: Optional[str] = Field(None, description="Kode program studi")
class AlumniCreate(AlumniBase):
pass
class AlumniUpdate(BaseModel):
nim: Optional[str] = None
nama: Optional[str] = None
tahun_lulus: Optional[int] = None
status_kerja: Optional[str] = None
pekerjaan: Optional[str] = None
instansi: Optional[str] = None
no_hp: Optional[str] = None
email: Optional[str] = None
kode_prodi: Optional[str] = None
class AlumniResponse(AlumniBase):
id: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
@model_validator(mode='before')
@classmethod
def exclude_relationships(cls, data: Any) -> Any:
"""Convert SQLAlchemy objects to dict, excluding relationship attributes"""
if hasattr(data, '__dict__'):
result = {}
for key, value in data.__dict__.items():
if key.startswith('_') or key in ['pekerjaan_detail', 'kompetensi', 'tracer_response', 'clustering_results']:
continue
if hasattr(value, '__tablename__'):
result[key] = None
else:
result[key] = value
return result
return data
class PekerjaanDetail(BaseModel):
id: Optional[int] = None
status_pekerjaan: Optional[str] = None
jenis_perusahaan: Optional[str] = None
nama_perusahaan: Optional[str] = None
jabatan: Optional[str] = None
tingkatan_tempat_kerja: Optional[str] = None
provinsi: Optional[str] = None
kabupaten_kota: Optional[str] = None
teks_pekerjaan: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class KompetensiDetail(BaseModel):
id: Optional[int] = None
etika_lulus: Optional[str] = None
keahlian_lulus: Optional[str] = None
bahasa_inggris_lulus: Optional[str] = None
teknologi_informasi_lulus: Optional[str] = None
komunikasi_lulus: Optional[str] = None
kerja_sama_lulus: Optional[str] = None
pengembangan_diri_lulus: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class ClusteringResultDetail(BaseModel):
id: Optional[int] = None
model_version: Optional[str] = None
k: Optional[int] = None
cluster: Optional[int] = None
kategori: Optional[str] = None
profile_match: Optional[bool] = None
matched_keyword: Optional[str] = None
created_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class AlumniDetailResponse(AlumniBase):
id: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
pekerjaan_detail: Optional[PekerjaanDetail] = None
kompetensi: Optional[KompetensiDetail] = None
tracer_response: Optional[Dict[str, Any]] = None
clustering_results: Optional[List[ClusteringResultDetail]] = None
model_config = ConfigDict(from_attributes=True)
@model_validator(mode='before')
@classmethod
def process_relations(cls, data: Any) -> Any:
if hasattr(data, '__dict__'):
result = {}
for key, value in data.__dict__.items():
if key.startswith('_'):
continue
if key == 'tracer_response' and value is not None and hasattr(value, '__dict__'):
# Convert tracer_response sqlalchemy object to dict
tr_dict = {k: v for k, v in value.__dict__.items() if not k.startswith('_') and not hasattr(v, '__tablename__')}
result[key] = tr_dict
else:
result[key] = value
return result
return data
class AlumniPaginationResponse(BaseModel):
total: int
page: int
limit: int
total_pages: int
data: List[AlumniResponse]
class PublicTracerLookupRequest(BaseModel):
nim: str = Field(..., description="Nomor Induk Mahasiswa (NIM)")
email: Optional[str] = Field(None, description="Email / Gmail untuk verifikasi kepemilikan")
class PublicTracerSubmitRequest(BaseModel):
nim: str = Field(..., description="Nomor Induk Mahasiswa (NIM)")
nama: str = Field(..., min_length=2, description="Nama lengkap alumni")
kode_prodi: str = Field(..., description="Kode prodi (55301, 57401, 56401, dll)")
tahun_lulus: int = Field(..., ge=1990, le=2100, description="Tahun kelulusan")
email: str = Field(..., description="Email / Gmail aktif alumni")
no_hp: Optional[str] = Field(None, description="Nomor WhatsApp / HP aktif")
status_kerja: str = Field(..., description="Status kerja: bekerja, belum_bekerja, wiraswasta, melanjutkan, mencari_kerja")
# Detail Pekerjaan (jika bekerja / wiraswasta)
nama_perusahaan: Optional[str] = None
jabatan: Optional[str] = None
jenis_perusahaan: Optional[str] = None
tingkatan_tempat_kerja: Optional[str] = None
hubungan_studi: Optional[str] = None
# Identitas Extended (Pertanyaan-dan-jawaban.md)
kode_pt: Optional[str] = "005019"
nik: Optional[str] = None
npwp: Optional[str] = None
# Karir & Gaji Extended
bulan_dapat_kerja: Optional[int] = None
rata_pendapatan: Optional[str] = None
provinsi_kerja: Optional[str] = None
kab_kota_kerja: Optional[str] = None
posisi_wiraswasta: Optional[str] = None
# Studi Lanjut
sumber_biaya_studi: Optional[str] = None
pt_studi_lanjut: Optional[str] = None
prodi_studi_lanjut: Optional[str] = None
tanggal_masuk_studi: Optional[str] = None
# Pembiayaan & Kesesuaian
sumber_biaya_kuliah: Optional[str] = None
tingkat_pendidikan_tepat: Optional[str] = None
# Data Ekstra / Detail Kuesioner (Kompetensi, Metode Pembelajaran, Cara Cari Kerja, dll)
data_extra: Optional[dict] = None