import logging from datetime import datetime from django.core.handlers.wsgi import WSGIRequest from django.http import JsonResponse, HttpResponse, HttpResponseNotAllowed from django.urls import reverse from django.utils import timezone from web.api_views.serialization_utils import serialize_datetime, location_to_str, flying_team_to_str, add_column, \ bool_to_yes_no, get_filters_for_data_table_request from web.models import Appointment, Study, SubjectColumns, AppointmentColumns, AppointmentList, StudyColumns from web.models.appointment_list import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_UNFINISHED, \ APPOINTMENT_LIST_APPROACHING from web.models.constants import GLOBAL_STUDY_ID from web.templatetags.filters import display_visit_number from web.views.notifications import get_filter_locations, get_today_midnight_date, get_unfinished_appointments logger = logging.getLogger(__name__) def get_appointment_columns(request, appointment_list_type): study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0] appointment_lists = AppointmentList.objects.filter(study=study, type=appointment_list_type) if len(appointment_lists) > 0: appointment_list = appointment_lists[0] subject_columns = appointment_list.visible_subject_columns subject_study_columns = appointment_list.visible_study_subject_columns appointment_columns = appointment_list.visible_appointment_columns else: subject_columns = SubjectColumns() subject_study_columns = StudyColumns() appointment_columns = AppointmentColumns() result = [] add_column(result, "First name", "first_name", subject_columns, "string_filter") add_column(result, "Last name", "last_name", subject_columns, "string_filter") add_column(result, "Subject number", "nd_number", subject_study_columns, "string_filter") add_column(result, "Type", "type", subject_study_columns, "type_filter") add_column(result, "Info sent", "post_mail_sent", appointment_columns, "yes_no_filter") add_column(result, "Date", "datetime_when", appointment_columns, None) add_column(result, "Appointment types", "appointment_types", appointment_columns, "appointment_type_filter", sortable=False) add_column(result, "Edit", "edit", None, None, sortable=False) return JsonResponse({"columns": result}) def get_appointments(request, appointment_type, min_date, max_date): if appointment_type == APPOINTMENT_LIST_GENERIC: result = Appointment.objects.filter(location__in=get_filter_locations(request.user)) elif appointment_type == APPOINTMENT_LIST_UNFINISHED: result = get_unfinished_appointments(request.user) elif appointment_type == APPOINTMENT_LIST_APPROACHING: result = Appointment.objects.filter( datetime_when__gt=get_today_midnight_date(), location__in=get_filter_locations(request.user), status=Appointment.APPOINTMENT_STATUS_SCHEDULED ).order_by("datetime_when") else: raise TypeError("Unknown query type: " + appointment_type) if min_date is not None: min_date = datetime.strptime(min_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo) result = result.filter(datetime_when__gt=min_date) if max_date is not None: max_date = datetime.strptime(max_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo) result = result.filter(datetime_when__lt=max_date) return result.order_by("datetime_when") def get_appointments_order(appointments_to_be_ordered, order_column: str, order_direction: str): result = appointments_to_be_ordered if order_direction == "asc": order_direction = "" else: order_direction = "-" if order_column == "first_name": result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__subject__first_name') elif order_column == "last_name": result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__subject__last_name') elif order_column == "nd_number": result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__nd_number') elif order_column == "type": result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__type') elif order_column == "location": result = appointments_to_be_ordered.order_by(order_direction + 'location') elif order_column == "flying_team": result = appointments_to_be_ordered.order_by(order_direction + 'flying_team') elif order_column == "post_mail_sent": result = appointments_to_be_ordered.order_by(order_direction + 'post_mail_sent') elif order_column == "datetime_when": result = appointments_to_be_ordered.order_by(order_direction + 'datetime_when') elif order_column == "subject": result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__subject__last_name', order_direction + 'visit__subject__subject__first_name') else: logger.warning("Unknown sort column: %s", str(order_column)) return result def get_appointments_filtered(appointments_to_be_filtered, filters): result = appointments_to_be_filtered for row in filters: column = row[0] value = row[1] if column == "first_name": result = result.filter(visit__subject__subject__first_name__icontains=value) elif column == "last_name": result = result.filter(visit__subject__subject__last_name__icontains=value) elif column == "nd_number": result = result.filter(visit__subject__nd_number__icontains=value) elif column == "type": result = result.filter(visit__subject__type=value) elif column == "location": result = result.filter(location=value) elif column == "flying_team": result = result.filter(flying_team=value) elif column == "appointment_types": result = result.filter(appointment_types=value) else: message = "UNKNOWN filter: " if column is None: message += "[None]" else: message += str(column) logger.warning(message) return result def appointments(request: WSGIRequest, appointment_type: str) -> HttpResponse: # id of the query from dataTable: https://datatables.net/manual/server-side if request.method == "GET": request_data = request.GET elif request.method == "POST": request_data = request.POST else: return HttpResponseNotAllowed(['GET', 'POST']) draw = int(request_data.get("draw", "-1")) start = int(request_data.get("start", "0")) length = int(request_data.get("length", "10")) order = int(request_data.get("order[0][column]", "0")) order_dir = request_data.get("order[0][dir]", "asc") order_column = request_data.get("columns[" + str(order) + "][data]", "last_name") min_date = request_data.get("start_date", None) max_date = request_data.get("end_date", None) filters = get_filters_for_data_table_request(request_data) if min_date is not None: length = 1000000000 all_appointments = get_appointments(request, appointment_type, min_date, max_date) count = all_appointments.count() sorted_appointments = get_appointments_order(all_appointments, order_column, order_dir) filtered_appointments = get_appointments_filtered(sorted_appointments, filters) sliced_appointments = filtered_appointments[start:(start + length)] result_appointments = sliced_appointments count_filtered = all_appointments.count() data = [] for appointment in result_appointments: data.append(serialize_appointment(appointment)) return JsonResponse({ "draw": draw, "recordsTotal": count, "recordsFiltered": count_filtered, "data": data, }) def serialize_appointment(appointment: Appointment): subject_string = "" first_name = "" last_name = "" subject_type = "" nd_number = screening_number = phone_numbers = appointment_type_names = None status = appointment.status if appointment.visit is not None: title = f"Visit {display_visit_number(appointment.visit.visit_number)}" study_subject = appointment.visit.subject subject_string = study_subject.subject.last_name + " " + study_subject.subject.first_name first_name = study_subject.subject.first_name last_name = study_subject.subject.last_name nd_number = study_subject.nd_number screening_number = study_subject.screening_number subject_type = study_subject.type.name phone_numbers = ", ".join([_f for _f in [study_subject.subject.phone_number, study_subject.subject.phone_number_2, study_subject.subject.phone_number_3] if _f]) appointment_type_names = ", ".join( [str(appointment_type_codes) for appointment_type_codes in appointment.appointment_types.all()]) else: title = appointment.comment appointment_type_codes = ", ".join( [appointment_type_codes.code for appointment_type_codes in appointment.appointment_types.all()]) until = serialize_datetime(appointment.datetime_until()) location = location_to_str(appointment.location) flying_team = flying_team_to_str(appointment.flying_team) worker_assigned = None if appointment.worker_assigned is not None: worker_assigned = str(appointment.worker_assigned) result = { "status": status, "subject": subject_string, "title": title, "nd_number": nd_number, "screening_number": screening_number, "type": subject_type, "phone_number": phone_numbers, "appointment_type_names": appointment_type_names, "datetime_until": until, "comment": appointment.comment, "color": appointment.color(), "id": appointment.id, "first_name": first_name, "last_name": last_name, "location": location, "flying_team": flying_team, "worker_assigned": worker_assigned, "post_mail_sent": bool_to_yes_no(appointment.post_mail_sent), "datetime_when": serialize_datetime(appointment.datetime_when), "appointment_types": appointment_type_codes, "url": reverse('web.views.appointment_edit', kwargs={'appointment_id': str(appointment.id)}) } return result