Ali2206 commited on
Commit
ce0bb8c
·
1 Parent(s): 6ed180c
Files changed (2) hide show
  1. models/entities.py +8 -57
  2. routes/patients.py +49 -170
models/entities.py CHANGED
@@ -3,78 +3,36 @@ from typing import List, Optional
3
  from datetime import datetime
4
 
5
  class Condition(BaseModel):
6
- id: Optional[str] = None
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
- category: Optional[str] = ""
13
 
14
  class Medication(BaseModel):
15
- id: Optional[str] = None
16
  name: str
17
  status: str
18
  prescribed_date: Optional[str] = None
19
  requester: Optional[str] = ""
20
  dosage: Optional[str] = ""
21
- intent: Optional[str] = ""
22
- priority: Optional[str] = ""
23
 
24
  class Encounter(BaseModel):
25
- id: Optional[str] = None
26
  type: str
27
  status: str
28
- period: Optional[dict] = None
29
  service_provider: Optional[str] = ""
30
- class_type: Optional[str] = ""
31
- reason: Optional[str] = ""
32
-
33
- class Observation(BaseModel):
34
- id: Optional[str] = None
35
- code: str
36
- value: Optional[str] = ""
37
- unit: Optional[str] = ""
38
- status: Optional[str] = ""
39
- effective_date: Optional[str] = None
40
- category: Optional[str] = ""
41
-
42
- class Procedure(BaseModel):
43
- id: Optional[str] = None
44
- code: str
45
- status: str
46
- performed_date: Optional[str] = None
47
- performer: Optional[str] = ""
48
- reason: Optional[str] = ""
49
-
50
- class Immunization(BaseModel):
51
- id: Optional[str] = None
52
- vaccine: str
53
- status: str
54
- date: Optional[str] = None
55
- lot_number: Optional[str] = ""
56
- expiration_date: Optional[str] = ""
57
- manufacturer: Optional[str] = ""
58
-
59
- class Allergy(BaseModel):
60
- id: Optional[str] = None
61
- substance: str
62
- status: Optional[str] = ""
63
- severity: Optional[str] = ""
64
- onset_date: Optional[str] = None
65
- reaction: Optional[str] = ""
66
 
67
  class Note(BaseModel):
68
- id: Optional[str] = None
69
- title: Optional[str] = ""
70
- date: Optional[str] = None
71
- author: Optional[str] = "System"
72
- content: str
73
- type: Optional[str] = ""
74
  context: Optional[str] = ""
 
75
 
76
  class PatientCreate(BaseModel):
77
- fhir_id: Optional[str] = None
78
  full_name: str
79
  gender: str
80
  date_of_birth: str
@@ -85,14 +43,7 @@ class PatientCreate(BaseModel):
85
  country: Optional[str] = "US"
86
  marital_status: Optional[str] = "Never Married"
87
  language: Optional[str] = "en"
88
- source: Optional[str] = "appointment_booking"
89
- import_date: Optional[str] = None
90
- last_updated: Optional[str] = None
91
  conditions: Optional[List[Condition]] = []
92
  medications: Optional[List[Medication]] = []
93
  encounters: Optional[List[Encounter]] = []
94
- observations: Optional[List[Observation]] = []
95
- procedures: Optional[List[Procedure]] = []
96
- immunizations: Optional[List[Immunization]] = []
97
- allergies: Optional[List[Allergy]] = []
98
  notes: Optional[List[Note]] = []
 
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
38
  date_of_birth: 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]] = []
routes/patients.py CHANGED
@@ -45,77 +45,6 @@ except PermissionError:
45
  os.makedirs(SYNTHEA_DATA_DIR, exist_ok=True)
46
 
47
  # Pydantic models for update validation
48
- class ConditionUpdate(BaseModel):
49
- id: Optional[str] = None
50
- code: Optional[str] = None
51
- status: Optional[str] = None
52
- onset_date: Optional[str] = None
53
- recorded_date: Optional[str] = None
54
- verification_status: Optional[str] = None
55
- category: Optional[str] = None
56
-
57
- class MedicationUpdate(BaseModel):
58
- id: Optional[str] = None
59
- name: Optional[str] = None
60
- status: Optional[str] = None
61
- prescribed_date: Optional[str] = None
62
- requester: Optional[str] = None
63
- dosage: Optional[str] = None
64
- intent: Optional[str] = None
65
- priority: Optional[str] = None
66
-
67
- class EncounterUpdate(BaseModel):
68
- id: Optional[str] = None
69
- type: Optional[str] = None
70
- status: Optional[str] = None
71
- period: Optional[Dict[str, str]] = None
72
- service_provider: Optional[str] = None
73
- class_type: Optional[str] = None
74
- reason: Optional[str] = None
75
-
76
- class ObservationUpdate(BaseModel):
77
- id: Optional[str] = None
78
- code: Optional[str] = None
79
- value: Optional[str] = None
80
- unit: Optional[str] = None
81
- status: Optional[str] = None
82
- effective_date: Optional[str] = None
83
- category: Optional[str] = None
84
-
85
- class ProcedureUpdate(BaseModel):
86
- id: Optional[str] = None
87
- code: Optional[str] = None
88
- status: Optional[str] = None
89
- performed_date: Optional[str] = None
90
- performer: Optional[str] = None
91
- reason: Optional[str] = None
92
-
93
- class ImmunizationUpdate(BaseModel):
94
- id: Optional[str] = None
95
- vaccine: Optional[str] = None
96
- status: Optional[str] = None
97
- date: Optional[str] = None
98
- lot_number: Optional[str] = None
99
- expiration_date: Optional[str] = None
100
- manufacturer: Optional[str] = None
101
-
102
- class AllergyUpdate(BaseModel):
103
- id: Optional[str] = None
104
- substance: Optional[str] = None
105
- status: Optional[str] = None
106
- severity: Optional[str] = None
107
- onset_date: Optional[str] = None
108
- reaction: Optional[str] = None
109
-
110
- class NoteUpdate(BaseModel):
111
- id: Optional[str] = None
112
- title: Optional[str] = None
113
- date: Optional[str] = None
114
- author: Optional[str] = None
115
- content: Optional[str] = None
116
- type: Optional[str] = None
117
- context: Optional[str] = None
118
-
119
  class PatientUpdate(BaseModel):
120
  full_name: Optional[str] = None
121
  gender: Optional[str] = None
@@ -125,16 +54,21 @@ class PatientUpdate(BaseModel):
125
  state: Optional[str] = None
126
  postal_code: Optional[str] = None
127
  country: Optional[str] = None
128
- marital_status: Optional[str] = None
129
- language: Optional[str] = None
130
- conditions: Optional[List[ConditionUpdate]] = None
131
- medications: Optional[List[MedicationUpdate]] = None
132
- encounters: Optional[List[EncounterUpdate]] = None
133
- observations: Optional[List[ObservationUpdate]] = None
134
- procedures: Optional[List[ProcedureUpdate]] = None
135
- immunizations: Optional[List[ImmunizationUpdate]] = None
136
- allergies: Optional[List[AllergyUpdate]] = None
137
- notes: Optional[List[NoteUpdate]] = None
 
 
 
 
 
138
 
139
  @router.get("/debug/count")
140
  async def debug_patient_count():
@@ -177,21 +111,18 @@ async def create_patient(
177
  now = datetime.utcnow().isoformat()
178
 
179
  # Add system-generated fields if not provided
180
- if not patient_doc.get('fhir_id'):
181
- patient_doc['fhir_id'] = str(uuid.uuid4())
182
- if not patient_doc.get('import_date'):
183
- patient_doc['import_date'] = now
184
- if not patient_doc.get('last_updated'):
185
- patient_doc['last_updated'] = now
186
  if not patient_doc.get('source'):
187
  patient_doc['source'] = 'appointment_booking'
 
 
188
 
189
  patient_doc['created_by'] = current_user.get('email')
 
 
190
 
191
  # Ensure all array fields exist even if empty
192
  array_fields = [
193
- 'conditions', 'medications', 'encounters', 'observations',
194
- 'procedures', 'immunizations', 'allergies', 'notes'
195
  ]
196
  for field in array_fields:
197
  if field not in patient_doc or patient_doc[field] is None:
@@ -932,86 +863,34 @@ async def update_patient(
932
  "state": update_data.state,
933
  "postal_code": update_data.postal_code,
934
  "country": update_data.country,
935
- "marital_status": update_data.marital_status,
936
- "language": update_data.language
937
  }
938
  for key, value in demographics.items():
939
  if value is not None:
940
  update_ops["$set"][key] = value
941
 
942
- # Handle array updates (all array fields)
 
 
 
 
 
 
 
 
 
 
 
943
  array_fields = {
944
- "conditions": update_data.conditions,
945
- "medications": update_data.medications,
946
- "encounters": update_data.encounters,
947
- "observations": update_data.observations,
948
- "procedures": update_data.procedures,
949
- "immunizations": update_data.immunizations,
950
  "allergies": update_data.allergies,
951
- "notes": update_data.notes
 
952
  }
953
 
954
  for field, items in array_fields.items():
955
  if items is not None:
956
- # Fetch existing items
957
- existing_items = patient.get(field, [])
958
- updated_items = []
959
-
960
- for item in items:
961
- item_dict = item.dict(exclude_unset=True)
962
- if not item_dict:
963
- continue
964
-
965
- # Generate ID for new items
966
- if not item_dict.get("id"):
967
- item_dict["id"] = str(uuid.uuid4())
968
-
969
- # Validate required fields
970
- if field == "conditions" and not item_dict.get("code"):
971
- raise HTTPException(
972
- status_code=status.HTTP_400_BAD_REQUEST,
973
- detail=f"Condition code is required for {field}"
974
- )
975
- if field == "medications" and not item_dict.get("name"):
976
- raise HTTPException(
977
- status_code=status.HTTP_400_BAD_REQUEST,
978
- detail=f"Medication name is required for {field}"
979
- )
980
- if field == "encounters" and not item_dict.get("type"):
981
- raise HTTPException(
982
- status_code=status.HTTP_400_BAD_REQUEST,
983
- detail=f"Encounter type is required for {field}"
984
- )
985
- if field == "observations" and not item_dict.get("code"):
986
- raise HTTPException(
987
- status_code=status.HTTP_400_BAD_REQUEST,
988
- detail=f"Observation code is required for {field}"
989
- )
990
- if field == "procedures" and not item_dict.get("code"):
991
- raise HTTPException(
992
- status_code=status.HTTP_400_BAD_REQUEST,
993
- detail=f"Procedure code is required for {field}"
994
- )
995
- if field == "immunizations" and not item_dict.get("vaccine"):
996
- raise HTTPException(
997
- status_code=status.HTTP_400_BAD_REQUEST,
998
- detail=f"Immunization vaccine is required for {field}"
999
- )
1000
- if field == "allergies" and not item_dict.get("substance"):
1001
- raise HTTPException(
1002
- status_code=status.HTTP_400_BAD_REQUEST,
1003
- detail=f"Allergy substance is required for {field}"
1004
- )
1005
- if field == "notes" and not item_dict.get("content"):
1006
- raise HTTPException(
1007
- status_code=status.HTTP_400_BAD_REQUEST,
1008
- detail=f"Note content is required for {field}"
1009
- )
1010
-
1011
- updated_items.append(item_dict)
1012
-
1013
- # Replace the entire array
1014
- update_ops["$set"][field] = updated_items
1015
 
1016
  # Perform the update
1017
  result = await patients_collection.update_one(query, update_ops)
@@ -1034,7 +913,6 @@ async def update_patient(
1034
 
1035
  response = {
1036
  "id": str(updated_patient["_id"]),
1037
- "fhir_id": updated_patient.get("fhir_id"),
1038
  "full_name": updated_patient.get("full_name"),
1039
  "gender": updated_patient.get("gender"),
1040
  "date_of_birth": updated_patient.get("date_of_birth"),
@@ -1043,19 +921,20 @@ async def update_patient(
1043
  "state": updated_patient.get("state"),
1044
  "postal_code": updated_patient.get("postal_code"),
1045
  "country": updated_patient.get("country"),
1046
- "marital_status": updated_patient.get("marital_status"),
1047
- "language": updated_patient.get("language"),
1048
- "conditions": updated_patient.get("conditions", []),
1049
- "medications": updated_patient.get("medications", []),
1050
- "encounters": updated_patient.get("encounters", []),
1051
- "observations": updated_patient.get("observations", []),
1052
- "procedures": updated_patient.get("procedures", []),
1053
- "immunizations": updated_patient.get("immunizations", []),
1054
  "allergies": updated_patient.get("allergies", []),
1055
- "notes": updated_patient.get("notes", []),
 
 
 
 
 
1056
  "source": updated_patient.get("source"),
1057
- "import_date": updated_patient.get("import_date"),
1058
- "last_updated": updated_patient.get("last_updated")
 
 
1059
  }
1060
 
1061
  logger.info(f"Successfully updated patient {patient_id}")
 
45
  os.makedirs(SYNTHEA_DATA_DIR, exist_ok=True)
46
 
47
  # Pydantic models for update validation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  class PatientUpdate(BaseModel):
49
  full_name: Optional[str] = None
50
  gender: Optional[str] = None
 
54
  state: Optional[str] = None
55
  postal_code: Optional[str] = None
56
  country: Optional[str] = None
57
+ national_id: Optional[str] = None
58
+ blood_type: Optional[str] = None
59
+ allergies: Optional[List[str]] = None
60
+ chronic_conditions: Optional[List[str]] = None
61
+ medications: Optional[List[str]] = None
62
+ emergency_contact_name: Optional[str] = None
63
+ emergency_contact_phone: Optional[str] = None
64
+ insurance_provider: Optional[str] = None
65
+ insurance_policy_number: Optional[str] = None
66
+ source: Optional[str] = None
67
+ status: Optional[str] = None
68
+ assigned_doctor_id: Optional[str] = None
69
+ registration_date: Optional[datetime] = None
70
+ created_at: Optional[datetime] = None
71
+ updated_at: Optional[datetime] = None
72
 
73
  @router.get("/debug/count")
74
  async def debug_patient_count():
 
111
  now = datetime.utcnow().isoformat()
112
 
113
  # Add system-generated fields if not provided
 
 
 
 
 
 
114
  if not patient_doc.get('source'):
115
  patient_doc['source'] = 'appointment_booking'
116
+ if not patient_doc.get('status'):
117
+ patient_doc['status'] = 'active'
118
 
119
  patient_doc['created_by'] = current_user.get('email')
120
+ patient_doc['created_at'] = datetime.utcnow()
121
+ patient_doc['updated_at'] = datetime.utcnow()
122
 
123
  # Ensure all array fields exist even if empty
124
  array_fields = [
125
+ 'allergies', 'chronic_conditions', 'medications'
 
126
  ]
127
  for field in array_fields:
128
  if field not in patient_doc or patient_doc[field] is None:
 
863
  "state": update_data.state,
864
  "postal_code": update_data.postal_code,
865
  "country": update_data.country,
866
+ "national_id": update_data.national_id,
867
+ "blood_type": update_data.blood_type
868
  }
869
  for key, value in demographics.items():
870
  if value is not None:
871
  update_ops["$set"][key] = value
872
 
873
+ # Handle contact and insurance updates
874
+ contact_fields = {
875
+ "emergency_contact_name": update_data.emergency_contact_name,
876
+ "emergency_contact_phone": update_data.emergency_contact_phone,
877
+ "insurance_provider": update_data.insurance_provider,
878
+ "insurance_policy_number": update_data.insurance_policy_number
879
+ }
880
+ for key, value in contact_fields.items():
881
+ if value is not None:
882
+ update_ops["$set"][key] = value
883
+
884
+ # Handle array updates (simple string arrays)
885
  array_fields = {
 
 
 
 
 
 
886
  "allergies": update_data.allergies,
887
+ "chronic_conditions": update_data.chronic_conditions,
888
+ "medications": update_data.medications
889
  }
890
 
891
  for field, items in array_fields.items():
892
  if items is not None:
893
+ update_ops["$set"][field] = items
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
 
895
  # Perform the update
896
  result = await patients_collection.update_one(query, update_ops)
 
913
 
914
  response = {
915
  "id": str(updated_patient["_id"]),
 
916
  "full_name": updated_patient.get("full_name"),
917
  "gender": updated_patient.get("gender"),
918
  "date_of_birth": updated_patient.get("date_of_birth"),
 
921
  "state": updated_patient.get("state"),
922
  "postal_code": updated_patient.get("postal_code"),
923
  "country": updated_patient.get("country"),
924
+ "national_id": updated_patient.get("national_id"),
925
+ "blood_type": updated_patient.get("blood_type"),
 
 
 
 
 
 
926
  "allergies": updated_patient.get("allergies", []),
927
+ "chronic_conditions": updated_patient.get("chronic_conditions", []),
928
+ "medications": updated_patient.get("medications", []),
929
+ "emergency_contact_name": updated_patient.get("emergency_contact_name"),
930
+ "emergency_contact_phone": updated_patient.get("emergency_contact_phone"),
931
+ "insurance_provider": updated_patient.get("insurance_provider"),
932
+ "insurance_policy_number": updated_patient.get("insurance_policy_number"),
933
  "source": updated_patient.get("source"),
934
+ "status": updated_patient.get("status"),
935
+ "assigned_doctor_id": updated_patient.get("assigned_doctor_id"),
936
+ "created_at": updated_patient.get("created_at"),
937
+ "updated_at": updated_patient.get("updated_at")
938
  }
939
 
940
  logger.info(f"Successfully updated patient {patient_id}")