Spaces:
Running
Running
Update backend/api/views.py
Browse files- backend/api/views.py +26 -78
backend/api/views.py
CHANGED
|
@@ -257,90 +257,38 @@ class AppointmentStatusView(views.APIView):
|
|
| 257 |
permission_classes = [IsAuthenticated]
|
| 258 |
|
| 259 |
def patch(self, request, pk):
|
| 260 |
-
print(f"DEBUG: Update Request Received for Appointment #{pk}")
|
| 261 |
try:
|
| 262 |
appointment = Appointment.objects.get(pk=pk)
|
| 263 |
-
|
| 264 |
# Permission check
|
| 265 |
if request.user.profile != appointment.doctor and request.user.profile != appointment.patient:
|
| 266 |
return response.Response({"error": "Unauthorized"}, status=403)
|
| 267 |
|
| 268 |
-
new_status
|
| 269 |
-
doctor_note
|
| 270 |
-
new_date_time = request.data.get('new_date_time', None)
|
| 271 |
-
|
| 272 |
-
# ---------------------------------------------------------------
|
| 273 |
-
# BUG FIX #1 — Status gate was blocking ALL updates
|
| 274 |
-
# Previously, the entire update block was wrapped inside:
|
| 275 |
-
# if new_status in dict(Appointment.STATUS_CHOICES):
|
| 276 |
-
# So any request that only changed date/note (status=None) returned
|
| 277 |
-
# {"error": "Invalid status"} 400. Now status is validated only when
|
| 278 |
-
# it is actually provided, and each field updates independently.
|
| 279 |
-
# ---------------------------------------------------------------
|
| 280 |
-
valid_statuses = dict(Appointment.STATUS_CHOICES)
|
| 281 |
-
|
| 282 |
-
if new_status is not None and new_status not in valid_statuses:
|
| 283 |
-
return response.Response({"error": f"Invalid status '{new_status}'"}, status=400)
|
| 284 |
-
|
| 285 |
-
# Require at least one field to update
|
| 286 |
-
if new_status is None and not new_date_time and not doctor_note:
|
| 287 |
-
return response.Response(
|
| 288 |
-
{"error": "Nothing to update. Provide status, new_date_time, or doctor_note."},
|
| 289 |
-
status=400
|
| 290 |
-
)
|
| 291 |
-
|
| 292 |
-
# 1. Update Status (only if provided)
|
| 293 |
-
if new_status is not None:
|
| 294 |
-
appointment.status = new_status
|
| 295 |
-
|
| 296 |
-
# 2. Update Note (only if provided)
|
| 297 |
-
if doctor_note:
|
| 298 |
-
appointment.doctor_note = doctor_note
|
| 299 |
-
|
| 300 |
-
# 3. Update Date/Time (only if provided)
|
| 301 |
-
if new_date_time:
|
| 302 |
-
appointment.date_time = new_date_time
|
| 303 |
-
|
| 304 |
-
appointment.save()
|
| 305 |
-
|
| 306 |
-
# ---------------------------------------------------------------
|
| 307 |
-
# BUG FIX #2 — strftime() crashing with 500 Internal Server Error
|
| 308 |
-
# After `appointment.date_time = new_date_time` (a raw string from
|
| 309 |
-
# the request) and calling .save(), the in-memory Python object's
|
| 310 |
-
# date_time attribute is STILL a plain string — Django only converts
|
| 311 |
-
# it to a proper datetime when reading from the database.
|
| 312 |
-
# Calling .strftime() on a string raises AttributeError → 500.
|
| 313 |
-
# refresh_from_db() re-fetches the saved row so date_time is a
|
| 314 |
-
# proper datetime object that strftime() can work with safely.
|
| 315 |
-
# ---------------------------------------------------------------
|
| 316 |
-
appointment.refresh_from_db()
|
| 317 |
-
print("DEBUG: Appointment Saved and Refreshed from Database.")
|
| 318 |
-
|
| 319 |
-
# 4. Trigger Email — use the current (possibly updated) status
|
| 320 |
-
email_status = new_status if new_status is not None else appointment.status
|
| 321 |
-
should_notify = new_status is not None or new_date_time
|
| 322 |
-
|
| 323 |
-
if should_notify and hasattr(appointment.patient.user, 'email') and appointment.patient.user.email:
|
| 324 |
-
print(f"DEBUG: Triggering Email to {appointment.patient.user.email}")
|
| 325 |
-
|
| 326 |
-
formatted_date = appointment.date_time.strftime('%B %d, %Y at %I:%M %p')
|
| 327 |
-
|
| 328 |
-
send_appointment_status_email(
|
| 329 |
-
recipient_email=appointment.patient.user.email,
|
| 330 |
-
patient_name=appointment.patient.full_name or "Patient",
|
| 331 |
-
doctor_name=appointment.doctor.full_name or "Doctor",
|
| 332 |
-
appointment_date=formatted_date,
|
| 333 |
-
status=email_status,
|
| 334 |
-
doctor_note=doctor_note
|
| 335 |
-
)
|
| 336 |
-
else:
|
| 337 |
-
print("DEBUG: No notify condition met or patient has no email. Skipping email.")
|
| 338 |
|
| 339 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
|
|
|
|
|
|
|
|
|
|
| 341 |
except Appointment.DoesNotExist:
|
| 342 |
-
|
| 343 |
-
return response.Response({"error": "Appointment not found"}, status=404)
|
| 344 |
-
except Exception as e:
|
| 345 |
-
print(f"DEBUG: Error in View: {e}")
|
| 346 |
-
return response.Response({"error": str(e)}, status=500)
|
|
|
|
| 257 |
permission_classes = [IsAuthenticated]
|
| 258 |
|
| 259 |
def patch(self, request, pk):
|
|
|
|
| 260 |
try:
|
| 261 |
appointment = Appointment.objects.get(pk=pk)
|
|
|
|
| 262 |
# Permission check
|
| 263 |
if request.user.profile != appointment.doctor and request.user.profile != appointment.patient:
|
| 264 |
return response.Response({"error": "Unauthorized"}, status=403)
|
| 265 |
|
| 266 |
+
new_status = request.data.get('status')
|
| 267 |
+
doctor_note = request.data.get('doctor_note', '')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
|
| 269 |
+
# If user selects "Request Reschedule" (or 'cancelled'), we treat it as cancelled
|
| 270 |
+
# but allow a custom email with the note.
|
| 271 |
+
if new_status in dict(Appointment.STATUS_CHOICES):
|
| 272 |
+
appointment.status = new_status
|
| 273 |
+
appointment.save()
|
| 274 |
+
|
| 275 |
+
# --- TRIGGER EMAIL NOTIFICATION ---
|
| 276 |
+
if appointment.patient.user.email:
|
| 277 |
+
# Determine formatted date
|
| 278 |
+
formatted_date = appointment.date_time.strftime('%B %d, %Y at %I:%M %p')
|
| 279 |
+
|
| 280 |
+
send_appointment_status_email(
|
| 281 |
+
recipient_email=appointment.patient.user.email,
|
| 282 |
+
patient_name=appointment.patient.full_name or "Patient",
|
| 283 |
+
doctor_name=appointment.doctor.full_name or "Doctor",
|
| 284 |
+
appointment_date=formatted_date,
|
| 285 |
+
status=new_status,
|
| 286 |
+
doctor_note=doctor_note
|
| 287 |
+
)
|
| 288 |
+
# ----------------------------------
|
| 289 |
|
| 290 |
+
return response.Response(AppointmentSerializer(appointment).data)
|
| 291 |
+
return response.Response({"error": "Invalid status"}, status=400)
|
| 292 |
+
|
| 293 |
except Appointment.DoesNotExist:
|
| 294 |
+
return response.Response({"error": "Appointment not found"}, status=404)
|
|
|
|
|
|
|
|
|
|
|
|