Ali2206 commited on
Commit
be490cc
·
1 Parent(s): ce0bb8c
Files changed (3) hide show
  1. api/routes/patients.py +20 -91
  2. models/entities.py +19 -36
  3. routes/patients.py +28 -83
api/routes/patients.py CHANGED
@@ -3,7 +3,7 @@ from db.mongo import patients_collection, db # Added db import
3
  from core.security import get_current_user
4
  from utils.db import create_indexes
5
  from utils.helpers import calculate_age, standardize_language
6
- from models.entities import Note, PatientCreate
7
  from models.schemas import PatientListResponse # Fixed import
8
  from api.services.fhir_integration import HAPIFHIRIntegrationService
9
  from api.services.synthea_integration import SyntheaIntegrationService
@@ -58,36 +58,6 @@ def get_synthea_data_dir():
58
  SYNTHEA_DATA_DIR = get_synthea_data_dir()
59
 
60
  # Pydantic models for update validation
61
- class ConditionUpdate(BaseModel):
62
- id: Optional[str] = None
63
- code: Optional[str] = None
64
- status: Optional[str] = None
65
- onset_date: Optional[str] = None
66
- recorded_date: Optional[str] = None
67
- verification_status: Optional[str] = None
68
- notes: Optional[str] = None
69
-
70
- class MedicationUpdate(BaseModel):
71
- id: Optional[str] = None
72
- name: Optional[str] = None
73
- status: Optional[str] = None
74
- prescribed_date: Optional[str] = None
75
- requester: Optional[str] = None
76
- dosage: Optional[str] = None
77
-
78
- class EncounterUpdate(BaseModel):
79
- id: Optional[str] = None
80
- type: Optional[str] = None
81
- status: Optional[str] = None
82
- period: Optional[Dict[str, str]] = None
83
- service_provider: Optional[str] = None
84
-
85
- class NoteUpdate(BaseModel):
86
- id: Optional[str] = None
87
- title: Optional[str] = None
88
- date: Optional[str] = None
89
- author: Optional[str] = None
90
- content: Optional[str] = None
91
 
92
  class PatientUpdate(BaseModel):
93
  full_name: Optional[str] = None
@@ -98,12 +68,24 @@ class PatientUpdate(BaseModel):
98
  state: Optional[str] = None
99
  postal_code: Optional[str] = None
100
  country: Optional[str] = None
101
- marital_status: Optional[str] = None
102
- language: Optional[str] = None
103
- conditions: Optional[List[ConditionUpdate]] = None
104
- medications: Optional[List[MedicationUpdate]] = None
105
- encounters: Optional[List[EncounterUpdate]] = None
106
- notes: Optional[List[NoteUpdate]] = None
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  @router.get("/debug/count")
109
  async def debug_patient_count():
@@ -958,60 +940,7 @@ async def get_patient(patient_id: str):
958
  detail=f"Failed to retrieve patient: {str(e)}"
959
  )
960
 
961
- @router.post("/{patient_id}/notes", status_code=status.HTTP_201_CREATED)
962
- async def add_note(
963
- patient_id: str,
964
- note: Note,
965
- current_user: dict = Depends(get_current_user)
966
- ):
967
- logger.info(f"Adding note for patient {patient_id} by user {current_user.get('email')}")
968
- if not any(role in current_user.get('roles', []) for role in ['doctor', 'admin']):
969
- logger.warning(f"Unauthorized note addition attempt by {current_user.get('email')}")
970
- raise HTTPException(
971
- status_code=status.HTTP_403_FORBIDDEN,
972
- detail="Only clinicians can add notes"
973
- )
974
-
975
- try:
976
- note_data = note.dict()
977
- note_data.update({
978
- "author": current_user.get('full_name', 'System'),
979
- "timestamp": datetime.utcnow().isoformat()
980
- })
981
-
982
- result = await patients_collection.update_one(
983
- {"$or": [
984
- {"_id": ObjectId(patient_id)},
985
- {"fhir_id": patient_id}
986
- ]},
987
- {
988
- "$push": {"notes": note_data},
989
- "$set": {"last_updated": datetime.utcnow().isoformat()}
990
- }
991
- )
992
-
993
- if result.modified_count == 0:
994
- logger.warning(f"Patient not found for note addition: {patient_id}")
995
- raise HTTPException(
996
- status_code=status.HTTP_404_NOT_FOUND,
997
- detail="Patient not found"
998
- )
999
-
1000
- logger.info(f"Note added successfully for patient {patient_id}")
1001
- return {"status": "success", "message": "Note added"}
1002
-
1003
- except ValueError as ve:
1004
- logger.error(f"Invalid patient ID format: {patient_id}, error: {str(ve)}")
1005
- raise HTTPException(
1006
- status_code=status.HTTP_400_BAD_REQUEST,
1007
- detail="Invalid patient ID format"
1008
- )
1009
- except Exception as e:
1010
- logger.error(f"Failed to add note for patient {patient_id}: {str(e)}")
1011
- raise HTTPException(
1012
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
1013
- detail=f"Failed to add note: {str(e)}"
1014
- )
1015
 
1016
  @router.put("/patients/{patient_id}", status_code=status.HTTP_200_OK)
1017
  async def update_patient(
 
3
  from core.security import get_current_user
4
  from utils.db import create_indexes
5
  from utils.helpers import calculate_age, standardize_language
6
+ from models.entities import PatientCreate
7
  from models.schemas import PatientListResponse # Fixed import
8
  from api.services.fhir_integration import HAPIFHIRIntegrationService
9
  from api.services.synthea_integration import SyntheaIntegrationService
 
58
  SYNTHEA_DATA_DIR = get_synthea_data_dir()
59
 
60
  # Pydantic models for update validation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  class PatientUpdate(BaseModel):
63
  full_name: Optional[str] = None
 
68
  state: Optional[str] = None
69
  postal_code: Optional[str] = None
70
  country: Optional[str] = None
71
+ national_id: Optional[str] = None
72
+ blood_type: Optional[str] = None
73
+ allergies: Optional[List[str]] = None
74
+ chronic_conditions: Optional[List[str]] = None
75
+ medications: Optional[List[str]] = None
76
+ emergency_contact_name: Optional[str] = None
77
+ emergency_contact_phone: Optional[str] = None
78
+ insurance_provider: Optional[str] = None
79
+ insurance_policy_number: Optional[str] = None
80
+ medical_notes: Optional[str] = None
81
+ symptoms: Optional[List[str]] = None
82
+ vital_signs: Optional[dict] = None
83
+ source: Optional[str] = None
84
+ status: Optional[str] = None
85
+ assigned_doctor_id: Optional[str] = None
86
+ registration_date: Optional[str] = None
87
+ created_at: Optional[datetime] = None
88
+ updated_at: Optional[datetime] = None
89
 
90
  @router.get("/debug/count")
91
  async def debug_patient_count():
 
940
  detail=f"Failed to retrieve patient: {str(e)}"
941
  )
942
 
943
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
 
945
  @router.put("/patients/{patient_id}", status_code=status.HTTP_200_OK)
946
  async def update_patient(
models/entities.py CHANGED
@@ -2,36 +2,6 @@ from pydantic import BaseModel
2
  from typing import List, Optional
3
  from datetime import datetime
4
 
5
- class Condition(BaseModel):
6
- id: str
7
- code: str
8
- status: Optional[str] = ""
9
- onset_date: Optional[str] = None
10
- recorded_date: Optional[str] = None
11
- verification_status: Optional[str] = ""
12
-
13
- class Medication(BaseModel):
14
- id: str
15
- name: str
16
- status: str
17
- prescribed_date: Optional[str] = None
18
- requester: Optional[str] = ""
19
- dosage: Optional[str] = ""
20
-
21
- class Encounter(BaseModel):
22
- id: str
23
- type: str
24
- status: str
25
- period: dict
26
- service_provider: Optional[str] = ""
27
-
28
- class Note(BaseModel):
29
- date: str
30
- type: str
31
- text: str
32
- context: Optional[str] = ""
33
- author: Optional[str] = "System"
34
-
35
  class PatientCreate(BaseModel):
36
  full_name: str
37
  gender: str
@@ -41,9 +11,22 @@ class PatientCreate(BaseModel):
41
  state: Optional[str] = ""
42
  postal_code: Optional[str] = ""
43
  country: Optional[str] = "US"
44
- marital_status: Optional[str] = "Never Married"
45
- language: Optional[str] = "en"
46
- conditions: Optional[List[Condition]] = []
47
- medications: Optional[List[Medication]] = []
48
- encounters: Optional[List[Encounter]] = []
49
- notes: Optional[List[Note]] = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from typing import List, Optional
3
  from datetime import datetime
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  class PatientCreate(BaseModel):
6
  full_name: str
7
  gender: str
 
11
  state: Optional[str] = ""
12
  postal_code: Optional[str] = ""
13
  country: Optional[str] = "US"
14
+ national_id: Optional[str] = ""
15
+ blood_type: Optional[str] = ""
16
+ allergies: Optional[List[str]] = []
17
+ chronic_conditions: Optional[List[str]] = []
18
+ medications: Optional[List[str]] = []
19
+ emergency_contact_name: Optional[str] = ""
20
+ emergency_contact_phone: Optional[str] = ""
21
+ insurance_provider: Optional[str] = ""
22
+ insurance_policy_number: Optional[str] = ""
23
+ medical_notes: Optional[str] = ""
24
+ symptoms: Optional[List[str]] = []
25
+ vital_signs: Optional[dict] = {
26
+ "blood_pressure": "",
27
+ "temperature": "",
28
+ "heart_rate": "",
29
+ "respiratory_rate": "",
30
+ "weight": "",
31
+ "height": ""
32
+ }
routes/patients.py CHANGED
@@ -3,7 +3,7 @@ from db.mongo import patients_collection, db # Added db import
3
  from core.security import get_current_user
4
  from utils.db import create_indexes
5
  from utils.helpers import calculate_age, standardize_language
6
- from models.entities import Note, PatientCreate
7
  from models.schemas import PatientListResponse # Fixed import
8
  from api.services.fhir_integration import HAPIFHIRIntegrationService
9
  from datetime import datetime
@@ -713,34 +713,32 @@ async def get_patient(patient_id: str):
713
  )
714
 
715
  response = {
716
- "demographics": {
717
- "id": str(patient["_id"]),
718
- "fhir_id": patient.get("fhir_id"),
719
- "full_name": patient.get("full_name"),
720
- "gender": patient.get("gender"),
721
- "date_of_birth": patient.get("date_of_birth"),
722
- "age": calculate_age(patient.get("date_of_birth")),
723
- "address": {
724
- "line": patient.get("address"),
725
- "city": patient.get("city"),
726
- "state": patient.get("state"),
727
- "postal_code": patient.get("postal_code"),
728
- "country": patient.get("country")
729
- },
730
- "marital_status": patient.get("marital_status"),
731
- "language": patient.get("language")
732
- },
733
- "clinical_data": {
734
- "notes": patient.get("notes", []),
735
- "conditions": patient.get("conditions", []),
736
- "medications": patient.get("medications", []),
737
- "encounters": patient.get("encounters", [])
738
- },
739
- "metadata": {
740
- "source": patient.get("source"),
741
- "import_date": patient.get("import_date"),
742
- "last_updated": patient.get("last_updated")
743
- }
744
  }
745
 
746
  logger.info(f"Successfully retrieved patient: {patient_id}")
@@ -759,60 +757,7 @@ async def get_patient(patient_id: str):
759
  detail=f"Failed to retrieve patient: {str(e)}"
760
  )
761
 
762
- @router.post("/{patient_id}/notes", status_code=status.HTTP_201_CREATED)
763
- async def add_note(
764
- patient_id: str,
765
- note: Note,
766
- current_user: dict = Depends(get_current_user)
767
- ):
768
- logger.info(f"Adding note for patient {patient_id} by user {current_user.get('email')}")
769
- if current_user.get('role') not in ['doctor', 'admin']:
770
- logger.warning(f"Unauthorized note addition attempt by {current_user.get('email')}")
771
- raise HTTPException(
772
- status_code=status.HTTP_403_FORBIDDEN,
773
- detail="Only clinicians can add notes"
774
- )
775
-
776
- try:
777
- note_data = note.dict()
778
- note_data.update({
779
- "author": current_user.get('full_name', 'System'),
780
- "timestamp": datetime.utcnow().isoformat()
781
- })
782
-
783
- result = await patients_collection.update_one(
784
- {"$or": [
785
- {"_id": ObjectId(patient_id)},
786
- {"fhir_id": patient_id}
787
- ]},
788
- {
789
- "$push": {"notes": note_data},
790
- "$set": {"last_updated": datetime.utcnow().isoformat()}
791
- }
792
- )
793
-
794
- if result.modified_count == 0:
795
- logger.warning(f"Patient not found for note addition: {patient_id}")
796
- raise HTTPException(
797
- status_code=status.HTTP_404_NOT_FOUND,
798
- detail="Patient not found"
799
- )
800
-
801
- logger.info(f"Note added successfully for patient {patient_id}")
802
- return {"status": "success", "message": "Note added"}
803
-
804
- except ValueError as ve:
805
- logger.error(f"Invalid patient ID format: {patient_id}, error: {str(ve)}")
806
- raise HTTPException(
807
- status_code=status.HTTP_400_BAD_REQUEST,
808
- detail="Invalid patient ID format"
809
- )
810
- except Exception as e:
811
- logger.error(f"Failed to add note for patient {patient_id}: {str(e)}")
812
- raise HTTPException(
813
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
814
- detail=f"Failed to add note: {str(e)}"
815
- )
816
 
817
  @router.put("/patients/{patient_id}", status_code=status.HTTP_200_OK)
818
  async def update_patient(
 
3
  from core.security import get_current_user
4
  from utils.db import create_indexes
5
  from utils.helpers import calculate_age, standardize_language
6
+ from models.entities import PatientCreate
7
  from models.schemas import PatientListResponse # Fixed import
8
  from api.services.fhir_integration import HAPIFHIRIntegrationService
9
  from datetime import datetime
 
713
  )
714
 
715
  response = {
716
+ "id": str(patient["_id"]),
717
+ "full_name": patient.get("full_name"),
718
+ "gender": patient.get("gender"),
719
+ "date_of_birth": patient.get("date_of_birth"),
720
+ "address": patient.get("address"),
721
+ "city": patient.get("city"),
722
+ "state": patient.get("state"),
723
+ "postal_code": patient.get("postal_code"),
724
+ "country": patient.get("country"),
725
+ "national_id": patient.get("national_id"),
726
+ "blood_type": patient.get("blood_type"),
727
+ "allergies": patient.get("allergies", []),
728
+ "chronic_conditions": patient.get("chronic_conditions", []),
729
+ "medications": patient.get("medications", []),
730
+ "emergency_contact_name": patient.get("emergency_contact_name"),
731
+ "emergency_contact_phone": patient.get("emergency_contact_phone"),
732
+ "insurance_provider": patient.get("insurance_provider"),
733
+ "insurance_policy_number": patient.get("insurance_policy_number"),
734
+ "medical_notes": patient.get("medical_notes"),
735
+ "symptoms": patient.get("symptoms", []),
736
+ "vital_signs": patient.get("vital_signs", {}),
737
+ "source": patient.get("source"),
738
+ "status": patient.get("status"),
739
+ "assigned_doctor_id": patient.get("assigned_doctor_id"),
740
+ "created_at": patient.get("created_at"),
741
+ "updated_at": patient.get("updated_at")
 
 
742
  }
743
 
744
  logger.info(f"Successfully retrieved patient: {patient_id}")
 
757
  detail=f"Failed to retrieve patient: {str(e)}"
758
  )
759
 
760
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
 
762
  @router.put("/patients/{patient_id}", status_code=status.HTTP_200_OK)
763
  async def update_patient(