diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index 98c169a9e6563d9858910d3e17b00fa6422ba798..4adab0a0359062730e5d801833ce0a2ddae4fe3d 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import User from web.models import Location, AppointmentType, Subject, Worker, Visit, Appointment from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL -from web.views import get_today_midnight_date +from web.views.notifications import get_today_midnight_date def create_location(name="test"): diff --git a/smash/web/tests/test_view_functions.py b/smash/web/tests/test_view_functions.py index b43d3c33b6064ce5b4d29bca4b49c2e07ae3240a..db206b6b31194cdfbe5a955e6973d872a0edf87f 100644 --- a/smash/web/tests/test_view_functions.py +++ b/smash/web/tests/test_view_functions.py @@ -1,7 +1,7 @@ from django.test import TestCase from functions import create_location, create_user, create_worker, get_test_location -from web.views import get_filter_locations +from web.views.notifications import get_filter_locations class ViewFunctionsTests(TestCase): diff --git a/smash/web/tests/test_view_kit_request.py b/smash/web/tests/test_view_kit_request.py index 19883898505928742ed2d051fb1bef542826ae10..556308fd0066b8449868cf91215fc6ca154fba10 100644 --- a/smash/web/tests/test_view_kit_request.py +++ b/smash/web/tests/test_view_kit_request.py @@ -3,9 +3,10 @@ import datetime from django.test import TestCase, RequestFactory from django.urls import reverse -from functions import create_user, create_appointment_type, create_appointment, create_location +from functions import create_user, create_appointment_type, create_appointment from web.models import Item, Appointment -from web.views import kit_requests, get_today_midnight_date +from web.views.kit import kit_requests +from web.views.notifications import get_today_midnight_date class ViewFunctionsTests(TestCase): diff --git a/smash/web/tests/test_view_notifications.py b/smash/web/tests/test_view_notifications.py index 60095c78547145cc621cfd586fc0233db88a60b5..cf193787194089fdb78612a2ef2c5962bb97aa44 100644 --- a/smash/web/tests/test_view_notifications.py +++ b/smash/web/tests/test_view_notifications.py @@ -7,10 +7,11 @@ from functions import create_appointment, create_location, create_worker, create from functions import create_subject from functions import create_visit from web.models import Appointment, Location -from web.views import get_exceeded_visit_notifications_count, get_approaching_visits_without_appointments_count, \ - get_today_midnight_date, get_subject_with_no_visit_notifications_count, get_unfinished_appointments_count, \ +from web.views.notifications import get_exceeded_visit_notifications_count, \ + get_approaching_visits_without_appointments_count, \ + get_subject_with_no_visit_notifications_count, get_unfinished_appointments_count, \ get_approaching_visits_for_mail_contact_count, get_subjects_with_reminder_count, \ - get_visits_without_appointments_count + get_visits_without_appointments_count, get_today_midnight_date class NotificationViewTests(TestCase): diff --git a/smash/web/tests/test_view_visit.py b/smash/web/tests/test_view_visit.py index da9d39fccd4ed4be075fd468ff2c4e3ff9f2a21c..e1979cea43307c6793cc2685ee0f99146170264b 100644 --- a/smash/web/tests/test_view_visit.py +++ b/smash/web/tests/test_view_visit.py @@ -3,7 +3,7 @@ from django.test import TestCase, RequestFactory from django.urls import reverse from functions import create_subject, create_visit, create_appointment -from web.views import visit_details +from web.views.visit import visit_details class VisitViewTests(TestCase): diff --git a/smash/web/urls.py b/smash/web/urls.py index 6cbc1fcefde1c3ad82ea887069b1d56693b3dee1..0d0d0b6356aa8491e0119076ce6637bde3693adf 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -20,64 +20,68 @@ from django.conf.urls import url from web import views urlpatterns = [ - url(r'^appointments$', views.appointments, name='web.views.appointments'), - url(r'^appointments/unfinished$', views.unfinished_appointments, name='web.views.unfinished_appointments'), - url(r'^appointments/details/(?P<id>\d+)$', views.appointment_details, name='web.views.appointment_details'), - url(r'^appointments/add/(?P<id>\d+)$', views.appointment_add, name='web.views.appointment_add'), - url(r'^appointments/edit/(?P<id>\d+)$', views.appointment_edit, name='web.views.appointment_edit'), - url(r'^appointments/edit_datetime/(?P<id>\d+)$', views.appointment_edit_datetime, + url(r'^appointments$', views.appointment.appointments, name='web.views.appointments'), + url(r'^appointments/unfinished$', views.appointment.unfinished_appointments, + name='web.views.unfinished_appointments'), + url(r'^appointments/details/(?P<id>\d+)$', views.appointment.appointment_details, + name='web.views.appointment_details'), + url(r'^appointments/add/(?P<id>\d+)$', views.appointment.appointment_add, name='web.views.appointment_add'), + url(r'^appointments/edit/(?P<id>\d+)$', views.appointment.appointment_edit, name='web.views.appointment_edit'), + url(r'^appointments/edit_datetime/(?P<id>\d+)$', views.appointment.appointment_edit_datetime, name='web.views.appointment_edit_datetime'), - url(r'^appointments/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.appointment_mark, + url(r'^appointments/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.appointment.appointment_mark, name='web.views.appointment_mark'), - url(r'^visits$', views.visits, name='web.views.visits'), - url(r'^visits/exceeded$', views.exceeded_visits, name='web.views.exceeded_visits'), - url(r'^visits/unfinished$', views.unfinished_visits, name='web.views.unfinished_visits'), - url(r'^visits/approaching$', views.approaching_visits_without_appointments, + url(r'^visits$', views.visit.visits, name='web.views.visits'), + url(r'^visits/exceeded$', views.visit.exceeded_visits, name='web.views.exceeded_visits'), + url(r'^visits/unfinished$', views.visit.unfinished_visits, name='web.views.unfinished_visits'), + url(r'^visits/approaching$', views.visit.approaching_visits_without_appointments, name='web.views.approaching_visits_without_appointments'), - url(r'^visits/approaching_post_mail$', views.approaching_visits_for_mail_contact, + url(r'^visits/approaching_post_mail$', views.visit.approaching_visits_for_mail_contact, name='web.views.approaching_visits_for_mail_contact'), - url(r'^visits/missing_appointments$', views.visits_with_missing_appointments, + url(r'^visits/missing_appointments$', views.visit.visits_with_missing_appointments, name='web.views.visits_with_missing_appointments'), - url(r'^visits/details/(?P<id>\d+)$', views.visit_details, name='web.views.visit_details'), - url(r'^visits/add$', views.visit_add, name='web.views.visit_add'), - url(r'^visits/add/(?P<subject_id>\d+)$', views.visit_add, name='web.views.visit_add'), - url(r'^visit/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.visit_mark, name='web.views.visit_mark'), + url(r'^visits/details/(?P<id>\d+)$', views.visit.visit_details, name='web.views.visit_details'), + url(r'^visits/add$', views.visit.visit_add, name='web.views.visit_add'), + url(r'^visits/add/(?P<subject_id>\d+)$', views.visit.visit_add, name='web.views.visit_add'), + url(r'^visit/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.visit.visit_mark, name='web.views.visit_mark'), - url(r'^subjects$', views.subjects, name='web.views.subjects'), - url(r'^subjects/no_visit$', views.subject_no_visits, name='web.views.subject_no_visits'), - url(r'^subjects/equire_contact$', views.subject_require_contact, name='web.views.subject_require_contact'), - url(r'^subjects/add$', views.subject_add, name='web.views.subject_add'), - url(r'^subjects/subject_visit_details/(?P<id>\d+)$', views.subject_visit_details, + url(r'^subjects$', views.subject.subjects, name='web.views.subjects'), + url(r'^subjects/no_visit$', views.subject.subject_no_visits, name='web.views.subject_no_visits'), + url(r'^subjects/equire_contact$', views.subject.subject_require_contact, name='web.views.subject_require_contact'), + url(r'^subjects/add$', views.subject.subject_add, name='web.views.subject_add'), + url(r'^subjects/subject_visit_details/(?P<id>\d+)$', views.subject.subject_visit_details, name='web.views.subject_visit_details'), - url(r'^subjects/edit/(?P<id>\d+)$', views.subject_edit, name='web.views.subject_edit'), - url(r'^subjects/delete/(?P<id>\d+)$', views.subject_delete, name='web.views.subject_delete'), - url(r'^subjects/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.subject_mark, name='web.views.subject_mark'), + url(r'^subjects/edit/(?P<id>\d+)$', views.subject.subject_edit, name='web.views.subject_edit'), + url(r'^subjects/delete/(?P<id>\d+)$', views.subject.subject_delete, name='web.views.subject_delete'), + url(r'^subjects/mark/(?P<id>\d+)/(?P<as_what>[A-z]+)$', views.subject.subject_mark, name='web.views.subject_mark'), - url(r'^doctors$', views.doctors, name='web.views.doctors'), - url(r'^doctors/add$', views.doctor_add, name='web.views.doctor_add'), - url(r'^doctors/details/(?P<doctor_id>\d+)$', views.doctor_details, name='web.views.doctor_details'), - url(r'^doctors/edit/(?P<doctor_id>\d+)$', views.doctor_edit, name='web.views.doctor_edit'), - url(r'^doctors/availability/(?P<doctor_id>\d+)$', views.doctor_availability, name='web.views.doctor_availability'), - url(r'^doctors/availability/(?P<doctor_id>\d+)/delete/(?P<availability_id>\d+)$', views.doctor_availability_delete, + url(r'^doctors$', views.doctor.doctors, name='web.views.doctors'), + url(r'^doctors/add$', views.doctor.doctor_add, name='web.views.doctor_add'), + url(r'^doctors/details/(?P<doctor_id>\d+)$', views.doctor.doctor_details, name='web.views.doctor_details'), + url(r'^doctors/edit/(?P<doctor_id>\d+)$', views.doctor.doctor_edit, name='web.views.doctor_edit'), + url(r'^doctors/availability/(?P<doctor_id>\d+)$', views.doctor.doctor_availability, + name='web.views.doctor_availability'), + url(r'^doctors/availability/(?P<doctor_id>\d+)/delete/(?P<availability_id>\d+)$', + views.doctor.doctor_availability_delete, name='web.views.doctor_availability_delete'), - url(r'^equipment_and_rooms$', views.equipment_and_rooms, name='web.views.equipment_and_rooms'), - url(r'^equipment_and_rooms/eqdef$', views.equipment_def, name='web.views.equipment_def'), - url(r'^equipment_and_rooms/kit_requests$', views.kit_requests, name='web.views.kit_requests'), - url(r'^equipment_and_rooms/kit_requests/(?P<start_date>[\w-]+)/$', views.kit_requests_send_mail, + url(r'^equipment_and_rooms$', views.equipment.equipment_and_rooms, name='web.views.equipment_and_rooms'), + url(r'^equipment_and_rooms/eqdef$', views.equipment.equipment_def, name='web.views.equipment_def'), + url(r'^equipment_and_rooms/kit_requests$', views.kit.kit_requests, name='web.views.kit_requests'), + url(r'^equipment_and_rooms/kit_requests/(?P<start_date>[\w-]+)/$', views.kit.kit_requests_send_mail, name='web.views.kit_requests_send_mail'), url(r'^equipment_and_rooms/kit_requests/(?P<start_date>[\w-]+)/(?P<end_date>[\w-]+)/$', - views.kit_requests_send_mail, name='web.views.kit_requests_send_mail'), + views.kit.kit_requests_send_mail, name='web.views.kit_requests_send_mail'), - url(r'^mail_templates$', views.mail_templates, name='web.views.mail_templates'), - url(r'^statistics$', views.statistics, name='web.views.statistics'), + url(r'^mail_templates$', views.mails.mail_templates, name='web.views.mail_templates'), + url(r'^statistics$', views.statistics.statistics, name='web.views.statistics'), - url(r'^export$', views.export, name='web.views.export'), - url(r'^export/(?P<type>[A-z]+)$', views.export_to_csv2, name='web.views.export_to_csv2'), + url(r'^export$', views.export.export, name='web.views.export'), + url(r'^export/(?P<type>[A-z]+)$', views.export.export_to_csv2, name='web.views.export_to_csv2'), - url(r'^login$', views.login, name='web.views.login'), - url(r'^logout$', views.logout, name='web.views.logout'), + url(r'^login$', views.auth.login, name='web.views.login'), + url(r'^logout$', views.auth.logout, name='web.views.logout'), url(r'^$', views.index, name='web.views.index') ] diff --git a/smash/web/views.py b/smash/web/views.py deleted file mode 100644 index 989dd33c6190687c41bd808cadc8a6ae00fdd7be..0000000000000000000000000000000000000000 --- a/smash/web/views.py +++ /dev/null @@ -1,890 +0,0 @@ -from __future__ import unicode_literals - -import csv -import datetime - -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User, AnonymousUser -from django.db.models import Case -from django.db.models import Count -from django.db.models import When -from django.forms import HiddenInput -from django.http import HttpResponse -from django.shortcuts import redirect, get_object_or_404 -from django.shortcuts import render -from django.utils.dateparse import parse_datetime - -from auth import do_logout, do_login -from forms import SubjectDetailForm, WorkerEditForm, WorkerDetailForm, AppointmentDetailForm, AppointmentAddForm, \ - AppointmentEditForm, KitRequestForm, SubjectEditForm, SubjectAddForm, VisitAddForm, WorkerAddForm, VisitDetailForm, \ - StatisticsForm -from models import Worker, Location, Visit, Subject, Appointment, Avaibility, Item, AppointmentType -from statistics import StatisticsManager -from statistics import get_previous_year_and_month - -handler404 = 'web.views.e404_page_not_found' -handler500 = 'web.views.e500_error' -handler403 = 'web.views.e403_permission_denied' -handler400 = 'web.views.e400_bad_request' - - -def index(request): - if request.user.is_authenticated(): - return redirect(appointments) - return redirect(login) - - -def e404_page_not_found(request, context=None): - return render(request, "errors/404.html", context, status=404) - - -def e500_error(request, context=None): - return render(request, "errors/500.html", context, status=500) - - -def e403_permission_denied(request, context=None): - return render(request, "errors/403.html", context, status=403) - - -def e400_bad_request(request, context=None): - return render(request, "errors/400.html", context, status=400) - - -def login(request): - context = { - 'state': 'initial' - } - if request.GET and request.GET.get('error'): - context['state'] = request.GET.get('error') - - if request.method == "GET" and request.GET: - context['next'] = request.GET.get('next') - - if request.method == "POST" and request.POST: - state, message = do_login(request) - if state: - if request.POST.get('next'): - return redirect(request.POST.get('next')) - else: - return redirect(appointments) - else: - return redirect('/login?error=' + message) - return render(request, "login.html", context) - - -class NotificationCount(object): - title = "" - count = 0 - style = "" - type = '' - - def __init__(self, title="Unknown", count=0, style="fa fa-users text-aqua", type='web.views.appointments'): - self.title = title - self.count = count - self.style = style - self.type = type - - -def get_filter_locations(user): - worker = None - - if isinstance(user, User): - workers = Worker.objects.filter(user=user) - if len(workers) > 0: - worker = workers[0] - elif isinstance(user, Worker): - worker = user - elif isinstance(user, AnonymousUser): - # anonymous user shouldn't see anything - return Location.objects.filter(id=-1) - elif user is not None: - raise TypeError("Unknown class type: " + user.__class__.__name__) - - if worker is None or worker.locations.count() == 0: - return Location.objects.all() - else: - return worker.locations.all() - - -def get_exceeded_visits(user): - return Visit.objects.filter(datetime_end__lt=get_today_midnight_date(), - is_finished=False, - subject__default_location__in=get_filter_locations(user) - ).order_by('datetime_begin') - - -def get_exceeded_visit_notifications_count(user): - notification = NotificationCount( - title="exceeded visit time", - count=get_exceeded_visits(user).count(), - style="fa fa-thermometer-4 text-red", - type='web.views.exceeded_visits') - return notification - - -def get_subjects_with_no_visit(user): - result = Subject.objects.annotate(my_count=Count(Case(When(visit__is_finished=False, then=1)))).filter( - dead=False, - resigned=False, - my_count=0, - default_location__in=get_filter_locations(user), - postponed=False, - datetime_contact_reminder__isnull=True, - ) - return result - - -def get_subjects_with_reminder(user): - tomorrow = get_today_midnight_date() + datetime.timedelta(days=1) - - result = Subject.objects.filter( - dead=False, - resigned=False, - default_location__in=get_filter_locations(user), - datetime_contact_reminder__lt=tomorrow, - ) - return result - - -def get_subjects_with_reminder_count(user): - notification = NotificationCount( - title="subject required contact", - count=get_subjects_with_reminder(user).count(), - style="fa fa-users text-aqua", - type='web.views.subject_require_contact') - return notification - - -def get_subject_with_no_visit_notifications_count(user): - notification = NotificationCount( - title="subject without visit", - count=get_subjects_with_no_visit(user).count(), - style="fa fa-users text-aqua", - type='web.views.subject_no_visits') - return notification - - -def get_visits_without_appointments_count(user): - notification = NotificationCount( - title="unfinished visits ", - count=len(get_unfinished_visits(user)), - style="fa fa-user-times text-yellow", - type='web.views.unfinished_visits') - return notification - - -def get_visits_with_missing_appointments_count(user): - notification = NotificationCount( - title="visits with missing appointments", - count=len(get_active_visits_with_missing_appointments(user)), - style="fa fa-user-times text-yellow", - type='web.views.visits_with_missing_appointments') - return notification - - -def get_active_visits_without_appointments(user): - today = get_today_midnight_date() - return Visit.objects.annotate( - my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( - datetime_begin__lt=today, - datetime_end__gt=today, - is_finished=False, - subject__default_location__in=get_filter_locations(user), - my_count=0) - - -def waiting_for_appointment(visit): - required_types = visit.appointment_types.all() - appointment_types = [] - for appointment in visit.appointment_set.all(): - for type in appointment.appointment_types.all(): - if (appointment.status in [Appointment.APPOINTMENT_STATUS_FINISHED, - Appointment.APPOINTMENT_STATUS_SCHEDULED]) and (not (type in appointment_types)): - appointment_types.append(type) - result = False - for type in required_types: - if not (type in appointment_types): - result = True - return result - - -def get_unfinished_visits(user): - result = [] - for visit in get_active_visits_without_appointments(user): - if not waiting_for_appointment(visit): - result.append(visit) - return result - - -def get_active_visits_with_missing_appointments(user): - result = [] - for visit in get_active_visits_without_appointments(user): - if waiting_for_appointment(visit): - result.append(visit) - return result - - -def get_approaching_visits_without_appointments_count(user): - notification = NotificationCount( - title="approaching visits ", - count=get_approaching_visits_without_appointments(user).count(), - style="fa fa-users text-aqua", - type='web.views.approaching_visits_without_appointments') - return notification - - -def get_approaching_visits_for_mail_contact_count(user): - notification = NotificationCount( - title="post mail for approaching visits", - count=get_approaching_visits_for_mail_contact(user).count(), - style="fa fa-users text-aqua", - type='web.views.approaching_visits_for_mail_contact') - return notification - - -def get_approaching_visits_without_appointments(user): - today = get_today_midnight_date() - today_plus_two_months = today + datetime.timedelta(days=91) - return Visit.objects.annotate( - my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( - datetime_begin__gt=today, - datetime_begin__lt=today_plus_two_months, - is_finished=False, - subject__default_location__in=get_filter_locations(user), - my_count=0) - - -def get_approaching_visits_for_mail_contact(user): - today = get_today_midnight_date() - today_plus_three_months = today + datetime.timedelta(days=91) - today_plus_six_months = today + datetime.timedelta(days=183) - return Visit.objects.annotate( - my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( - datetime_begin__gt=today_plus_three_months, - datetime_begin__lt=today_plus_six_months, - is_finished=False, - post_mail_sent=False, - subject__default_location__in=get_filter_locations(user), - my_count=0) - - -def get_unfinished_appointments_count(user): - return NotificationCount( - title="unfinished appointments ", - count=get_unfinished_appointments(user).count(), - style="fa fa-history text-yellow", - type='web.views.unfinished_appointments') - - -def get_unfinished_appointments(user): - return Appointment.objects.filter( - datetime_when__lt=get_today_midnight_date(), - status=Appointment.APPOINTMENT_STATUS_SCHEDULED, - location__in=get_filter_locations(user), - ) - - -def get_notifications(the_user): - workers = Worker.objects.filter(user=the_user) - notifications = [] - count = 0 - if len(workers) > 0: - person = workers[0] - if person.role == Worker.ROLE_CHOICES_SECRETARY: - notifications.append(get_exceeded_visit_notifications_count(person)) - notifications.append(get_visits_without_appointments_count(person)) - notifications.append(get_approaching_visits_without_appointments_count(person)) - notifications.append(get_unfinished_appointments_count(person)) - notifications.append(get_visits_with_missing_appointments_count(person)) - notifications.append(get_subject_with_no_visit_notifications_count(person)) - notifications.append(get_approaching_visits_for_mail_contact_count(person)) - notifications.append(get_subjects_with_reminder_count(person)) - - for notification in notifications: - count += notification.count - return count, notifications - - -""" -Saturates response with information about logged user -""" - - -@login_required -def wrap_response(request, template, params): - person, role = Worker.get_details(request.user) - - notifications = get_notifications(request.user) - - final_params = params.copy() - final_params.update({ - 'person': person, - 'role': role, - 'notifications': notifications - }) - - return render(request, template, final_params) - - -def logout(request): - state, message = do_logout(request) - return redirect('/login?error=' + message) - - -def visits(request): - visit_list = Visit.objects.order_by('-datetime_begin') - context = { - 'visit_list': visit_list - } - - return wrap_response(request, 'visits/index.html', context) - - -def exceeded_visits(request): - context = { - 'visit_list': get_exceeded_visits(request.user) - } - return wrap_response(request, 'visits/index.html', context) - - -def unfinished_visits(request): - context = { - 'visit_list': get_unfinished_visits(request.user) - } - - return wrap_response(request, 'visits/index.html', context) - - -def visits_with_missing_appointments(request): - context = { - 'visit_list': get_active_visits_with_missing_appointments(request.user) - } - - return wrap_response(request, 'visits/index.html', context) - - -def approaching_visits_without_appointments(request): - context = { - 'visit_list': get_approaching_visits_without_appointments(request.user) - } - return wrap_response(request, 'visits/index.html', context) - - -def approaching_visits_for_mail_contact(request): - context = { - 'visit_list': get_approaching_visits_for_mail_contact(request.user) - } - return wrap_response(request, 'visits/index.html', context) - - -def visit_details(request, id): - displayed_visit = get_object_or_404(Visit, id=id) - if request.method == 'POST': - visit_form = VisitDetailForm(request.POST, request.FILES, instance=displayed_visit) - if visit_form.is_valid(): - visit_form.save() - else: - visit_form = VisitDetailForm(instance=displayed_visit) - - visit_finished = displayed_visit.is_finished - visit_id = displayed_visit.id - displayed_subject = displayed_visit.subject - list_of_appointments = displayed_visit.appointment_set.all() - - can_finish = not waiting_for_appointment(displayed_visit) - - for appointment in list_of_appointments: - if appointment.status == Appointment.APPOINTMENT_STATUS_SCHEDULED: - can_finish = False - - subject_form = SubjectDetailForm(instance=displayed_subject) - - return wrap_response(request, 'visits/details.html', { - 'vform': visit_form, - 'sform': subject_form, - 'loApp': list_of_appointments, - 'visFinished': visit_finished, - 'canFinish': can_finish, - 'vid': visit_id, - 'visit': displayed_visit}) - - -def visit_mark(request, id, as_what): - visit = get_object_or_404(Visit, id=id) - if as_what == 'finished': - visit.mark_as_finished() - - return redirect(visit_details, id=id) - - -def visit_add(request, subject_id=-1): - if request.method == 'POST': - form = VisitAddForm(request.POST, request.FILES) - if form.is_valid(): - visit = form.save() - return redirect(visit_details, visit.id) - else: - subjects = Subject.objects.filter(id=subject_id) - subject = None - if len(subjects) > 0: - subject = subjects[0] - form = VisitAddForm(initial={'subject': subject}) - - return wrap_response(request, 'visits/add.html', {'form': form}) - - -def subjects(request): - subjects_list = Subject.objects.order_by('-last_name') - context = { - 'subjects_list': subjects_list - } - - return wrap_response(request, 'subjects/index.html', context) - - -def subject_add(request): - if request.method == 'POST': - form = SubjectAddForm(request.POST, request.FILES) - if form.is_valid(): - screening_number = form.cleaned_data['screening_number'] - if screening_number == '': - screening_number = get_new_screening_number() # FIXME: method doesn't exist - form.save() - return redirect(subjects) - else: - form = SubjectAddForm() - - return wrap_response(request, 'subjects/add.html', {'form': form}) - - -def subject_no_visits(request): - subjects_list = get_subjects_with_no_visit(request.user).order_by('-last_name') - context = { - 'subjects_list': subjects_list - } - - return wrap_response(request, 'subjects/index.html', context) - - -def subject_require_contact(request): - subjects_list = get_subjects_with_reminder(request.user).order_by('-last_name') - context = { - 'subjects_list': subjects_list - } - - return wrap_response(request, 'subjects/index.html', context) - - -def subject_edit(request, id): - the_subject = get_object_or_404(Subject, id=id) - if request.method == 'POST': - form = SubjectEditForm(request.POST, request.FILES, instance=the_subject) - if form.is_valid(): - form.save() - return redirect(subjects) - else: - form = SubjectEditForm(instance=the_subject) - return wrap_response(request, 'subjects/edit.html', { - 'form': form, - 'subject': the_subject - }) - - -def subject_delete(request, id): - the_subject = get_object_or_404(Subject, id=id) - if request.method == 'POST': - the_subject.delete() - return redirect(subjects) - else: - form = SubjectEditForm(instance=the_subject) - return wrap_response(request, 'subjects/delete.html', {'form': form}) - - -def subject_mark(request, id, as_what): - who = get_object_or_404(Subject, id=id) - if as_what == 'dead': - who.mark_as_dead() - elif as_what == 'rejected': - who.mark_as_rejected() - return redirect(subject_edit, id=id) - - -def appointment_mark(request, id, as_what): - appointment = get_object_or_404(Appointment, id=id) - if as_what == 'finished': - appointment.mark_as_finished() - elif as_what == 'cancelled': - appointment.mark_as_cancelled() - elif as_what == 'no_show': - appointment.mark_as_no_show() - else: - return e500_error(request) - return redirect(visit_details, id=appointment.visit.id) - - -def subject_visit_details(request, id): - locsubject = get_object_or_404(Subject, id=id) - visits = locsubject.visit_set.all() - endlist = [] - for vis in visits: - assign = vis.appointment_set.all() - finished = vis.is_finished - visid = vis.id - visit_title = vis.follow_up_title() - visform = VisitDetailForm(instance=vis) - endlist.append((visform, assign, finished, visid, visit_title)) - - return wrap_response(request, 'subjects/visitdetails.html', {'display': endlist, "id": id}) - - -def doctors(request): - doctors_list = Worker.objects.order_by('-last_name') - context = { - 'doctors_list': doctors_list - } - - return wrap_response(request, "doctors/index.html", context) - - -def doctor_add(request): - if request.method == 'POST': - form = WorkerAddForm(request.POST, request.FILES) - if form.is_valid(): - form.save() - return redirect(doctors) - else: - form = WorkerAddForm() - - return wrap_response(request, 'doctors/add.html', {'form': form}) - - -def doctor_edit(request, doctor_id): - the_doctor = get_object_or_404(Worker, id=doctor_id) - if request.method == 'POST': - form = WorkerEditForm(request.POST, request.FILES, instance=the_doctor) - if form.is_valid(): - form.save() - return redirect(doctors) - else: - form = WorkerEditForm(instance=the_doctor) - return wrap_response(request, 'doctors/edit.html', {'form': form}) - - -def doctor_details(request, doctor_id): - the_doctor = get_object_or_404(Worker, id=doctor_id) - form = WorkerDetailForm(instance=the_doctor) - - return wrap_response(request, 'doctors/details.html', {'form': form}) - - -def doctor_availability(request, doctor_id): - avall = Avaibility.objects.filter(person=doctor_id) - - avmon = avall.filter(day_number=1) - avtue = avall.filter(day_number=2) - avwed = avall.filter(day_number=3) - avthu = avall.filter(day_number=4) - avfri = avall.filter(day_number=5) - avsat = avall.filter(day_number=6) - avsun = avall.filter(day_number=7) - - context = { - 'avmon': avmon, - 'avtue': avtue, - 'avwed': avwed, - 'avthu': avthu, - 'avfri': avfri, - 'avsat': avsat, - 'avsun': avsun, - 'id': doctor_id - } - - return wrap_response(request, "doctors/availability_index.html", context) - - -def doctor_availability_delete(request, doctor_id, availability_id): - availibility = Avaibility.objects.filter(id=availability_id) - if len(availibility) > 0: - availibility.delete() - return redirect(doctoravail, id=doctor_id) # FIXME doctoravail doesn't exist - - -def equipment_def(request): - equipment_list = Item.objects.order_by('-name') - context = { - 'equipment_list': equipment_list - } - - return wrap_response(request, "eqdef/index.html", context) - - -def equipment_and_rooms(request): - return wrap_response(request, "equipment_and_rooms/index.html", {}) - - -def mail_templates(request): - return wrap_response(request, "mail_templates/index.html", {}) - - -""" -# An initial draft of a function that was supposed to suggest date, room and worker for an appointment -def suggest_details(appoint): - avaibleWorkers = Worker.objects.get() - if appoint.appointment_type__required_worker == 'DOCTOR': - avaibleWorkers.filter(role='DOCTOR') - elif appoint.appointment_type__required_worker == 'NURSE': - avaibleWorkers.filter(role__in=['DOCTOR','NURSE']) - elif appoint.appointment_type__required_worker == 'PSYCHOLOGIST': - avaibleWorkers.filter(role__in=['DOCTOR','PSYCHOLOGIST']) - avaibleRooms = Room.objects.get - requireditems = appoint.appointment_type.required_equipment.filter(is_fixed=True) - reduce(operator.and_, (Q(equipment__contains=requireditems) for x in avaibleRooms)) -""" - - -def get_today_midnight_date(): - today = datetime.datetime.now() - today_midnight = datetime.datetime(today.year, today.month, today.day) - return today_midnight - - -def get_calendar_full_appointments(user): - month_ago = get_today_midnight_date() + datetime.timedelta(days=-31) - return Appointment.objects.filter( - datetime_when__gt=month_ago, - location__in=get_filter_locations(user), - ).order_by('datetime_when') - - -def appointments(request): - approaching_list = 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') - - full_list = get_calendar_full_appointments(request.user) - - context = { - 'approaching_list': approaching_list, - 'full_list': full_list - } - - return wrap_response(request, "appointments/index.html", context) - - -def unfinished_appointments(request): - appointments = get_unfinished_appointments(request.user) - context = { - 'appointment_list': appointments, - } - - return wrap_response(request, "appointments/list.html", context) - - -def appointment_details(request, id): - the_appointment = get_object_or_404(Appointment, id=id) - form = AppointmentDetailForm(instance=the_appointment) - return wrap_response(request, 'appointments/details.html', {'form': form}) - - -def appointment_add(request, id): - full_list = get_calendar_full_appointments(request.user) - if request.method == 'POST': - form = AppointmentAddForm(request.POST, request.FILES, user=request.user) - form.fields['visit'].widget = HiddenInput() - if form.is_valid(): - form.save() - return redirect(visit_details, id=id) - else: - form = AppointmentAddForm(initial={'visit': id}, user=request.user) - form.fields['visit'].widget = HiddenInput() - - return wrap_response(request, 'appointments/add.html', - {'form': form, 'visitID': id, 'full_appointment_list': full_list}) - - -def appointment_edit(request, id): - the_appointment = get_object_or_404(Appointment, id=id) - if request.method == 'POST': - appointment_form = AppointmentEditForm(request.POST, - request.FILES, - instance=the_appointment, - user=request.user, - prefix="appointment") - subject_form = SubjectEditForm(request.POST, instance=the_appointment.visit.subject, prefix="subject") - - if appointment_form.is_valid() and subject_form.is_valid(): - appointment_form.save() - subject_form.save() - return redirect(appointments) - else: - appointment_form = AppointmentEditForm(instance=the_appointment, user=request.user, prefix="appointment") - - subject_form = SubjectEditForm(instance=the_appointment.visit.subject, prefix="subject") - - return wrap_response(request, 'appointments/edit.html', { - 'form': appointment_form, - 'subject_form': subject_form, - 'id': id, - 'appointment': the_appointment - }) - - -def appointment_edit_datetime(request, id): - the_appointment = get_object_or_404(Appointment, id=id) - if request.method == 'POST': - form = AppointmentEditForm(request.POST, request.FILES, instance=the_appointment, user=request.user) - if form.is_valid(): - form.save() - return redirect(appointments) - else: - the_appointment.datetime_when = the_appointment.visit.datetime_begin - form = AppointmentEditForm(instance=the_appointment, user=request.user) - return wrap_response(request, 'appointments/edit.html', {'form': form}) - - -# because we don't wrap_response we must force login required -@login_required -def export_to_csv2(request, type="subjects"): - # Create the HttpResponse object with the appropriate CSV header. - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="' + type + '-' + get_today_midnight_date().strftime( - "%Y-%m-%d") + '.csv"' - - writer = csv.writer(response, quotechar=str(u'"'), quoting=csv.QUOTE_ALL) - if type == "subjects": - write_subjects_to_csv(writer) - elif type == "appointments": - write_appointments_to_csv(writer) - else: - return e500_error(request) - return response - - -def write_subjects_to_csv(writer): - subject_fields = [] - for field in Subject._meta.fields: - if field.name != "ID": - subject_fields.append(field) - - field_names = [] - for field in subject_fields: - field_names.append(field.verbose_name) - - writer.writerow(field_names) - - subjects = Subject.objects.order_by('-last_name') - for subject in subjects: - row = [] - for field in subject_fields: - row.append(getattr(subject, field.name)) - writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) - - -def write_appointments_to_csv(writer): - appointments_fields = [] - for field in Appointment._meta.fields: - if field.name != "visit" and field.name != "id" and field.name != "worker_assigned" and field.name != "appointment_types" and field.name != "room" and field.name != "flying_team": - appointments_fields.append(field) - - field_names = ['ND number', 'Family name', 'Name', 'Visit'] - for field in appointments_fields: - field_names.append(field.verbose_name) - - writer.writerow(field_names) - - appointments = Appointment.objects.order_by('-datetime_when') - - for appointment in appointments: - row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name, - appointment.visit.subject.first_name, appointment.visit.follow_up_title()] - for field in appointments_fields: - row.append(getattr(appointment, field.name)) - type_string = "" - for type in appointment.appointment_types.all(): - type_string += type.code + "," - row.append(type_string) - writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) - - -def export(request): - return wrap_response(request, 'export/index.html', {}) - - -def get_kit_requests(user, start_date=None, end_date=None): - if start_date is None: - start_date = get_today_midnight_date() + datetime.timedelta(days=1) - end_date = start_date + datetime.timedelta(days=7) - else: - if isinstance(start_date, str): - start_date = parse_datetime(start_date) - if (end_date is not None) and (isinstance(end_date, str)): - end_date = parse_datetime(end_date) - - appointment_types = AppointmentType.objects.filter(required_equipment__disposable=True) - - appointments = Appointment.objects.filter( - appointment_types__in=appointment_types, - datetime_when__gt=start_date, - location__in=get_filter_locations(user), - status=Appointment.APPOINTMENT_STATUS_SCHEDULED, - ) - if end_date is not None: - appointments = appointments.filter(datetime_when__lt=end_date) - - result = { - 'start_date': start_date, - 'end_date': end_date, - 'appointments': appointments, - } - return result - - -def get_kit_requests_data(request, start_date=None, end_date=None): - form = KitRequestForm() - if request.method == 'POST': - form = KitRequestForm(request.POST) - if form.is_valid(): - form_data = form.cleaned_data - start_date = form_data.get('start_date') - end_date = form_data.get('end_date') - - params = get_kit_requests(request.user, start_date, end_date) - params.update({ - 'form': form - }) - return params - - -def kit_requests(request): - return wrap_response(request, 'equipment_and_rooms/kit_requests.html', get_kit_requests_data(request)) - - -def kit_requests_send_mail(request, start_date, end_date=None): - return wrap_response(request, 'equipment_and_rooms/kit_requests_send_mail.html', - get_kit_requests_data(request, start_date, end_date)) - - -def statistics(request): - statistics_manager = StatisticsManager() - visit_choices = [("-1", "all")] - visit_choices.extend([(rank, rank) for rank in statistics_manager.visits_ranks]) - year_previous_month, previous_month = get_previous_year_and_month() - - form = StatisticsForm(request.GET, visit_choices=visit_choices, month=previous_month, year=year_previous_month) - if not form.is_valid(): - form.is_bound = False - month = form.data.get('month', previous_month) - year = form.data.get('year', year_previous_month) - subject_type = form.data.get('subject_type', "-1") - visit = form.data.get('visit', "-1") - if subject_type == "-1": - subject_type = None - if visit == "-1": - visit = None - monthly_statistics = statistics_manager.get_statistics_for_month(month, year, subject_type, visit) - return wrap_response(request, 'statistics/index.html', { - 'form': form, - 'monthly_statistics': monthly_statistics - }) diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..12bf76cd82f60c4af59f4559463487ae28a0b82a --- /dev/null +++ b/smash/web/views/__init__.py @@ -0,0 +1,63 @@ +# coding=utf-8 + +from django.contrib.auth.decorators import login_required +from django.shortcuts import redirect, render + +from notifications import get_notifications +from ..models import Worker + +__author__ = 'Valentin Grouès' +handler404 = 'web.views.e404_page_not_found' +handler500 = 'web.views.e500_error' +handler403 = 'web.views.e403_permission_denied' +handler400 = 'web.views.e400_bad_request' + + +def index(request): + if request.user.is_authenticated(): + return redirect('web.views.appointments') + return redirect('web.views.login') + + +def e404_page_not_found(request, context=None): + return render(request, "errors/404.html", context, status=404) + + +def e500_error(request, context=None): + return render(request, "errors/500.html", context, status=500) + + +def e403_permission_denied(request, context=None): + return render(request, "errors/403.html", context, status=403) + + +def e400_bad_request(request, context=None): + return render(request, "errors/400.html", context, status=400) + + +@login_required +def wrap_response(request, template, params): + person, role = Worker.get_details(request.user) + + notifications = get_notifications(request.user) + + final_params = params.copy() + final_params.update({ + 'person': person, + 'role': role, + 'notifications': notifications + }) + + return render(request, template, final_params) + + +import auth +import appointment +import visit +import doctor +import subject +import equipment +import kit +import mails +import statistics +import export diff --git a/smash/web/views/appointment.py b/smash/web/views/appointment.py new file mode 100644 index 0000000000000000000000000000000000000000..471f33c293d3feb5a39e46127f18d9e6de7d946d --- /dev/null +++ b/smash/web/views/appointment.py @@ -0,0 +1,112 @@ +# coding=utf-8 +from django.forms import HiddenInput +from django.shortcuts import get_object_or_404, redirect + +from notifications import get_today_midnight_date, get_filter_locations, get_calendar_full_appointments, \ + get_unfinished_appointments +from . import e500_error, wrap_response +from ..forms import AppointmentDetailForm, AppointmentAddForm, AppointmentEditForm, SubjectEditForm +from ..models import Appointment + +__author__ = 'Valentin Grouès' + + +def appointment_mark(request, id, as_what): + appointment = get_object_or_404(Appointment, id=id) + if as_what == 'finished': + appointment.mark_as_finished() + elif as_what == 'cancelled': + appointment.mark_as_cancelled() + elif as_what == 'no_show': + appointment.mark_as_no_show() + else: + return e500_error(request) + return redirect('web.views.visit_details', id=appointment.visit.id) + + +def appointments(request): + approaching_list = 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') + + full_list = get_calendar_full_appointments(request.user) + + context = { + 'approaching_list': approaching_list, + 'full_list': full_list + } + + return wrap_response(request, "appointments/index.html", context) + + +def unfinished_appointments(request): + appointments = get_unfinished_appointments(request.user) + context = { + 'appointment_list': appointments, + } + + return wrap_response(request, "appointments/list.html", context) + + +def appointment_details(request, id): + the_appointment = get_object_or_404(Appointment, id=id) + form = AppointmentDetailForm(instance=the_appointment) + return wrap_response(request, 'appointments/details.html', {'form': form}) + + +def appointment_add(request, id): + full_list = get_calendar_full_appointments(request.user) + if request.method == 'POST': + form = AppointmentAddForm(request.POST, request.FILES, user=request.user) + form.fields['visit'].widget = HiddenInput() + if form.is_valid(): + form.save() + return redirect('web.views.visit_details', id=id) + else: + form = AppointmentAddForm(initial={'visit': id}, user=request.user) + form.fields['visit'].widget = HiddenInput() + + return wrap_response(request, 'appointments/add.html', + {'form': form, 'visitID': id, 'full_appointment_list': full_list}) + + +def appointment_edit(request, id): + the_appointment = get_object_or_404(Appointment, id=id) + if request.method == 'POST': + appointment_form = AppointmentEditForm(request.POST, + request.FILES, + instance=the_appointment, + user=request.user, + prefix="appointment") + subject_form = SubjectEditForm(request.POST, instance=the_appointment.visit.subject, prefix="subject") + + if appointment_form.is_valid() and subject_form.is_valid(): + appointment_form.save() + subject_form.save() + return redirect('web.views.appointments') + else: + appointment_form = AppointmentEditForm(instance=the_appointment, user=request.user, prefix="appointment") + + subject_form = SubjectEditForm(instance=the_appointment.visit.subject, prefix="subject") + + return wrap_response(request, 'appointments/edit.html', { + 'form': appointment_form, + 'subject_form': subject_form, + 'id': id, + 'appointment': the_appointment + }) + + +def appointment_edit_datetime(request, id): + the_appointment = get_object_or_404(Appointment, id=id) + if request.method == 'POST': + form = AppointmentEditForm(request.POST, request.FILES, instance=the_appointment, user=request.user) + if form.is_valid(): + form.save() + return redirect('web.views.appointments') + else: + the_appointment.datetime_when = the_appointment.visit.datetime_begin + form = AppointmentEditForm(instance=the_appointment, user=request.user) + return wrap_response(request, 'appointments/edit.html', {'form': form}) diff --git a/smash/web/views/auth.py b/smash/web/views/auth.py new file mode 100644 index 0000000000000000000000000000000000000000..9ff4730d8e5030c28a1e7fe4159e6c981f93d168 --- /dev/null +++ b/smash/web/views/auth.py @@ -0,0 +1,39 @@ +# coding=utf-8 +from django.shortcuts import redirect, render + +from ..auth import do_login, do_logout + +__author__ = 'Valentin Grouès' + + +def login(request): + context = { + 'state': 'initial' + } + if request.GET and request.GET.get('error'): + context['state'] = request.GET.get('error') + + if request.method == "GET" and request.GET: + context['next'] = request.GET.get('next') + + if request.method == "POST" and request.POST: + state, message = do_login(request) + if state: + if request.POST.get('next'): + return redirect(request.POST.get('next')) + # FIXME: risk of phishing attacks + # see https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet + else: + return redirect('web.views.appointments') + else: + response = redirect('web.views.login') + response['Location'] += "?error={}".format(message) + return response + return render(request, "login.html", context) + + +def logout(request): + state, message = do_logout(request) + response = redirect('web.views.login') + response['Location'] += "?error={}".format(message) + return response diff --git a/smash/web/views/doctor.py b/smash/web/views/doctor.py new file mode 100644 index 0000000000000000000000000000000000000000..a59e322198ccf22db36e2463534dbf9b7445cb13 --- /dev/null +++ b/smash/web/views/doctor.py @@ -0,0 +1,80 @@ +# coding=utf-8 +from django.shortcuts import redirect, get_object_or_404 + +from . import wrap_response +from ..forms import WorkerAddForm, WorkerEditForm, WorkerDetailForm +from ..models import Worker, Avaibility + +__author__ = 'Valentin Grouès' + + +def doctors(request): + doctors_list = Worker.objects.order_by('-last_name') + context = { + 'doctors_list': doctors_list + } + + return wrap_response(request, "doctors/index.html", context) + + +def doctor_add(request): + if request.method == 'POST': + form = WorkerAddForm(request.POST, request.FILES) + if form.is_valid(): + form.save() + return redirect('web.views.doctors') + else: + form = WorkerAddForm() + + return wrap_response(request, 'doctors/add.html', {'form': form}) + + +def doctor_edit(request, doctor_id): + the_doctor = get_object_or_404(Worker, id=doctor_id) + if request.method == 'POST': + form = WorkerEditForm(request.POST, request.FILES, instance=the_doctor) + if form.is_valid(): + form.save() + return redirect('web.views.doctors') + else: + form = WorkerEditForm(instance=the_doctor) + return wrap_response(request, 'doctors/edit.html', {'form': form}) + + +def doctor_details(request, doctor_id): + the_doctor = get_object_or_404(Worker, id=doctor_id) + form = WorkerDetailForm(instance=the_doctor) + + return wrap_response(request, 'doctors/details.html', {'form': form}) + + +def doctor_availability(request, doctor_id): + avall = Avaibility.objects.filter(person=doctor_id) + + avmon = avall.filter(day_number=1) + avtue = avall.filter(day_number=2) + avwed = avall.filter(day_number=3) + avthu = avall.filter(day_number=4) + avfri = avall.filter(day_number=5) + avsat = avall.filter(day_number=6) + avsun = avall.filter(day_number=7) + + context = { + 'avmon': avmon, + 'avtue': avtue, + 'avwed': avwed, + 'avthu': avthu, + 'avfri': avfri, + 'avsat': avsat, + 'avsun': avsun, + 'id': doctor_id + } + + return wrap_response(request, "doctors/availability_index.html", context) + + +def doctor_availability_delete(request, doctor_id, availability_id): + availibility = Avaibility.objects.filter(id=availability_id) + if len(availibility) > 0: + availibility.delete() + return redirect(doctoravail, id=doctor_id) # FIXME doctoravail doesn't exist diff --git a/smash/web/views/equipment.py b/smash/web/views/equipment.py new file mode 100644 index 0000000000000000000000000000000000000000..417b1f7da97263985fee54c31aad127abcadb391 --- /dev/null +++ b/smash/web/views/equipment.py @@ -0,0 +1,18 @@ +# coding=utf-8 +from . import wrap_response +from ..models import Item + +__author__ = 'Valentin Grouès' + + +def equipment_def(request): + equipment_list = Item.objects.order_by('-name') + context = { + 'equipment_list': equipment_list + } + + return wrap_response(request, "eqdef/index.html", context) + + +def equipment_and_rooms(request): + return wrap_response(request, "equipment_and_rooms/index.html", {}) diff --git a/smash/web/views/export.py b/smash/web/views/export.py new file mode 100644 index 0000000000000000000000000000000000000000..8d5182b027ce6e08abfd72ce4390a9a1bd2bfcec --- /dev/null +++ b/smash/web/views/export.py @@ -0,0 +1,78 @@ +# coding=utf-8 +import csv + +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse + +from notifications import get_today_midnight_date +from . import e500_error, wrap_response +from ..models import Subject, Appointment + +__author__ = 'Valentin Grouès' + + +@login_required +def export_to_csv2(request, type="subjects"): + # Create the HttpResponse object with the appropriate CSV header. + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="' + type + '-' + get_today_midnight_date().strftime( + "%Y-%m-%d") + '.csv"' + + writer = csv.writer(response, quotechar=str(u'"'), quoting=csv.QUOTE_ALL) + if type == "subjects": + write_subjects_to_csv(writer) + elif type == "appointments": + write_appointments_to_csv(writer) + else: + return e500_error(request) + return response + + +def write_subjects_to_csv(writer): + subject_fields = [] + for field in Subject._meta.fields: + if field.name != "ID": + subject_fields.append(field) + + field_names = [] + for field in subject_fields: + field_names.append(field.verbose_name) + + writer.writerow(field_names) + + subjects = Subject.objects.order_by('-last_name') + for subject in subjects: + row = [] + for field in subject_fields: + row.append(getattr(subject, field.name)) + writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) + + +def write_appointments_to_csv(writer): + appointments_fields = [] + for field in Appointment._meta.fields: + if field.name != "visit" and field.name != "id" and field.name != "worker_assigned" and field.name != "appointment_types" and field.name != "room" and field.name != "flying_team": + appointments_fields.append(field) + + field_names = ['ND number', 'Family name', 'Name', 'Visit'] + for field in appointments_fields: + field_names.append(field.verbose_name) + + writer.writerow(field_names) + + appointments = Appointment.objects.order_by('-datetime_when') + + for appointment in appointments: + row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name, + appointment.visit.subject.first_name, appointment.visit.follow_up_title()] + for field in appointments_fields: + row.append(getattr(appointment, field.name)) + type_string = "" + for type in appointment.appointment_types.all(): + type_string += type.code + "," + row.append(type_string) + writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row]) + + +def export(request): + return wrap_response(request, 'export/index.html', {}) diff --git a/smash/web/views/kit.py b/smash/web/views/kit.py new file mode 100644 index 0000000000000000000000000000000000000000..36d8e440054732ef5be864f3fe13fc050ff23f4c --- /dev/null +++ b/smash/web/views/kit.py @@ -0,0 +1,65 @@ +# coding=utf-8 +import datetime + +from django.utils.dateparse import parse_datetime + +from notifications import get_filter_locations, get_today_midnight_date +from . import wrap_response +from ..forms import KitRequestForm +from ..models import AppointmentType, Appointment + +__author__ = 'Valentin Grouès' + + +def get_kit_requests(user, start_date=None, end_date=None): + if start_date is None: + start_date = get_today_midnight_date() + datetime.timedelta(days=1) + end_date = start_date + datetime.timedelta(days=7) + else: + if isinstance(start_date, str): + start_date = parse_datetime(start_date) + if (end_date is not None) and (isinstance(end_date, str)): + end_date = parse_datetime(end_date) + + appointment_types = AppointmentType.objects.filter(required_equipment__disposable=True) + + appointments = Appointment.objects.filter( + appointment_types__in=appointment_types, + datetime_when__gt=start_date, + location__in=get_filter_locations(user), + status=Appointment.APPOINTMENT_STATUS_SCHEDULED, + ) + if end_date is not None: + appointments = appointments.filter(datetime_when__lt=end_date) + + result = { + 'start_date': start_date, + 'end_date': end_date, + 'appointments': appointments, + } + return result + + +def get_kit_requests_data(request, start_date=None, end_date=None): + form = KitRequestForm() + if request.method == 'POST': + form = KitRequestForm(request.POST) + if form.is_valid(): + form_data = form.cleaned_data + start_date = form_data.get('start_date') + end_date = form_data.get('end_date') + + params = get_kit_requests(request.user, start_date, end_date) + params.update({ + 'form': form + }) + return params + + +def kit_requests(request): + return wrap_response(request, 'equipment_and_rooms/kit_requests.html', get_kit_requests_data(request)) + + +def kit_requests_send_mail(request, start_date, end_date=None): + return wrap_response(request, 'equipment_and_rooms/kit_requests_send_mail.html', + get_kit_requests_data(request, start_date, end_date)) diff --git a/smash/web/views/mails.py b/smash/web/views/mails.py new file mode 100644 index 0000000000000000000000000000000000000000..e949129f6cae5b3059ffb2cb0a5edf1dc2ac917c --- /dev/null +++ b/smash/web/views/mails.py @@ -0,0 +1,8 @@ +# coding=utf-8 +from . import wrap_response + +__author__ = 'Valentin Grouès' + + +def mail_templates(request): + return wrap_response(request, "mail_templates/index.html", {}) diff --git a/smash/web/views/notifications.py b/smash/web/views/notifications.py new file mode 100644 index 0000000000000000000000000000000000000000..b3b5d5ae97b2bfec6350ca819be5644792f1cb55 --- /dev/null +++ b/smash/web/views/notifications.py @@ -0,0 +1,256 @@ +# coding=utf-8 +import datetime + +from django.contrib.auth.models import User, AnonymousUser +from django.db.models import Count, Case, When + +from ..models import Worker, Subject, Visit, Appointment, Location + +__author__ = 'Valentin Grouès' + + +class NotificationCount(object): + title = "" + count = 0 + style = "" + type = '' + + def __init__(self, title="Unknown", count=0, style="fa fa-users text-aqua", type='web.views.appointments'): + self.title = title + self.count = count + self.style = style + self.type = type + + +def get_exceeded_visit_notifications_count(user): + notification = NotificationCount( + title="exceeded visit time", + count=get_exceeded_visits(user).count(), + style="fa fa-thermometer-4 text-red", + type='web.views.exceeded_visits') + return notification + + +def get_subjects_with_reminder_count(user): + notification = NotificationCount( + title="subject required contact", + count=get_subjects_with_reminder(user).count(), + style="fa fa-users text-aqua", + type='web.views.subject_require_contact') + return notification + + +def get_subject_with_no_visit_notifications_count(user): + notification = NotificationCount( + title="subject without visit", + count=get_subjects_with_no_visit(user).count(), + style="fa fa-users text-aqua", + type='web.views.subject_no_visits') + return notification + + +def get_visits_without_appointments_count(user): + notification = NotificationCount( + title="unfinished visits ", + count=len(get_unfinished_visits(user)), + style="fa fa-user-times text-yellow", + type='web.views.unfinished_visits') + return notification + + +def get_visits_with_missing_appointments_count(user): + notification = NotificationCount( + title="visits with missing appointments", + count=len(get_active_visits_with_missing_appointments(user)), + style="fa fa-user-times text-yellow", + type='web.views.visits_with_missing_appointments') + return notification + + +def get_approaching_visits_without_appointments_count(user): + notification = NotificationCount( + title="approaching visits ", + count=get_approaching_visits_without_appointments(user).count(), + style="fa fa-users text-aqua", + type='web.views.approaching_visits_without_appointments') + return notification + + +def get_approaching_visits_for_mail_contact_count(user): + notification = NotificationCount( + title="post mail for approaching visits", + count=get_approaching_visits_for_mail_contact(user).count(), + style="fa fa-users text-aqua", + type='web.views.approaching_visits_for_mail_contact') + return notification + + +def get_unfinished_appointments_count(user): + return NotificationCount( + title="unfinished appointments ", + count=get_unfinished_appointments(user).count(), + style="fa fa-history text-yellow", + type='web.views.unfinished_appointments') + + +def get_notifications(the_user): + workers = Worker.objects.filter(user=the_user) + notifications = [] + count = 0 + if len(workers) > 0: + person = workers[0] + if person.role == Worker.ROLE_CHOICES_SECRETARY: + notifications.append(get_exceeded_visit_notifications_count(person)) + notifications.append(get_visits_without_appointments_count(person)) + notifications.append(get_approaching_visits_without_appointments_count(person)) + notifications.append(get_unfinished_appointments_count(person)) + notifications.append(get_visits_with_missing_appointments_count(person)) + notifications.append(get_subject_with_no_visit_notifications_count(person)) + notifications.append(get_approaching_visits_for_mail_contact_count(person)) + notifications.append(get_subjects_with_reminder_count(person)) + + for notification in notifications: + count += notification.count + return count, notifications + + +def get_subjects_with_no_visit(user): + result = Subject.objects.annotate(my_count=Count(Case(When(visit__is_finished=False, then=1)))).filter( + dead=False, + resigned=False, + my_count=0, + default_location__in=get_filter_locations(user), + postponed=False, + datetime_contact_reminder__isnull=True, + ) + return result + + +def get_subjects_with_reminder(user): + tomorrow = get_today_midnight_date() + datetime.timedelta(days=1) + + result = Subject.objects.filter( + dead=False, + resigned=False, + default_location__in=get_filter_locations(user), + datetime_contact_reminder__lt=tomorrow, + ) + return result + + +def get_active_visits_with_missing_appointments(user): + result = [] + for visit in get_active_visits_without_appointments(user): + if waiting_for_appointment(visit): + result.append(visit) + return result + + +def get_unfinished_visits(user): + result = [] + for visit in get_active_visits_without_appointments(user): + if not waiting_for_appointment(visit): + result.append(visit) + return result + + +def get_approaching_visits_without_appointments(user): + today = get_today_midnight_date() + today_plus_two_months = today + datetime.timedelta(days=91) + return Visit.objects.annotate( + my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( + datetime_begin__gt=today, + datetime_begin__lt=today_plus_two_months, + is_finished=False, + subject__default_location__in=get_filter_locations(user), + my_count=0) + + +def get_approaching_visits_for_mail_contact(user): + today = get_today_midnight_date() + today_plus_three_months = today + datetime.timedelta(days=91) + today_plus_six_months = today + datetime.timedelta(days=183) + return Visit.objects.annotate( + my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( + datetime_begin__gt=today_plus_three_months, + datetime_begin__lt=today_plus_six_months, + is_finished=False, + post_mail_sent=False, + subject__default_location__in=get_filter_locations(user), + my_count=0) + + +def get_exceeded_visits(user): + return Visit.objects.filter(datetime_end__lt=get_today_midnight_date(), + is_finished=False, + subject__default_location__in=get_filter_locations(user) + ).order_by('datetime_begin') + + +def get_unfinished_appointments(user): + return Appointment.objects.filter( + datetime_when__lt=get_today_midnight_date(), + status=Appointment.APPOINTMENT_STATUS_SCHEDULED, + location__in=get_filter_locations(user), + ) + + +def waiting_for_appointment(visit): + required_types = visit.appointment_types.all() + appointment_types = [] + for appointment in visit.appointment_set.all(): + for type in appointment.appointment_types.all(): + if (appointment.status in [Appointment.APPOINTMENT_STATUS_FINISHED, + Appointment.APPOINTMENT_STATUS_SCHEDULED]) and (not (type in appointment_types)): + appointment_types.append(type) + result = False + for type in required_types: + if not (type in appointment_types): + result = True + return result + + +def get_active_visits_without_appointments(user): + today = get_today_midnight_date() + return Visit.objects.annotate( + my_count=Count(Case(When(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED, then=1)))).filter( + datetime_begin__lt=today, + datetime_end__gt=today, + is_finished=False, + subject__default_location__in=get_filter_locations(user), + my_count=0) + + +def get_filter_locations(user): + worker = None + + if isinstance(user, User): + workers = Worker.objects.filter(user=user) + if len(workers) > 0: + worker = workers[0] + elif isinstance(user, Worker): + worker = user + elif isinstance(user, AnonymousUser): + # anonymous user shouldn't see anything + return Location.objects.filter(id=-1) + elif user is not None: + raise TypeError("Unknown class type: " + user.__class__.__name__) + + if worker is None or worker.locations.count() == 0: + return Location.objects.all() + else: + return worker.locations.all() + + +def get_today_midnight_date(): + today = datetime.datetime.now() + today_midnight = datetime.datetime(today.year, today.month, today.day) + return today_midnight + + +def get_calendar_full_appointments(user): + month_ago = get_today_midnight_date() + datetime.timedelta(days=-31) + return Appointment.objects.filter( + datetime_when__gt=month_ago, + location__in=get_filter_locations(user), + ).order_by('datetime_when') diff --git a/smash/web/views/statistics.py b/smash/web/views/statistics.py new file mode 100644 index 0000000000000000000000000000000000000000..486427f5f6d4ac18de9606b121378b4f24121ce7 --- /dev/null +++ b/smash/web/views/statistics.py @@ -0,0 +1,30 @@ +# coding=utf-8 +from . import wrap_response +from ..forms import StatisticsForm +from ..statistics import StatisticsManager, get_previous_year_and_month + +__author__ = 'Valentin Grouès' + + +def statistics(request): + statistics_manager = StatisticsManager() + visit_choices = [("-1", "all")] + visit_choices.extend([(rank, rank) for rank in statistics_manager.visits_ranks]) + year_previous_month, previous_month = get_previous_year_and_month() + + form = StatisticsForm(request.GET, visit_choices=visit_choices, month=previous_month, year=year_previous_month) + if not form.is_valid(): + form.is_bound = False + month = form.data.get('month', previous_month) + year = form.data.get('year', year_previous_month) + subject_type = form.data.get('subject_type', "-1") + visit = form.data.get('visit', "-1") + if subject_type == "-1": + subject_type = None + if visit == "-1": + visit = None + monthly_statistics = statistics_manager.get_statistics_for_month(month, year, subject_type, visit) + return wrap_response(request, 'statistics/index.html', { + 'form': form, + 'monthly_statistics': monthly_statistics + }) diff --git a/smash/web/views/subject.py b/smash/web/views/subject.py new file mode 100644 index 0000000000000000000000000000000000000000..d8987167f2c7db1be39b577d660853862ace54a1 --- /dev/null +++ b/smash/web/views/subject.py @@ -0,0 +1,101 @@ +# coding=utf-8 + +from django.shortcuts import redirect, get_object_or_404 + +from notifications import get_subjects_with_no_visit, get_subjects_with_reminder +from . import wrap_response +from ..forms import SubjectAddForm, SubjectEditForm, VisitDetailForm +from ..models import Subject + +__author__ = 'Valentin Grouès' + + +def subjects(request): + subjects_list = Subject.objects.order_by('-last_name') + context = { + 'subjects_list': subjects_list + } + + return wrap_response(request, 'subjects/index.html', context) + + +def subject_add(request): + if request.method == 'POST': + form = SubjectAddForm(request.POST, request.FILES) + if form.is_valid(): + screening_number = form.cleaned_data['screening_number'] + if screening_number == '': + screening_number = get_new_screening_number() # FIXME: method doesn't exist + form.save() + return redirect('web.views.subjects') + else: + form = SubjectAddForm() + + return wrap_response(request, 'subjects/add.html', {'form': form}) + + +def subject_no_visits(request): + subjects_list = get_subjects_with_no_visit(request.user).order_by('-last_name') + context = { + 'subjects_list': subjects_list + } + + return wrap_response(request, 'subjects/index.html', context) + + +def subject_require_contact(request): + subjects_list = get_subjects_with_reminder(request.user).order_by('-last_name') + context = { + 'subjects_list': subjects_list + } + + return wrap_response(request, 'subjects/index.html', context) + + +def subject_edit(request, id): + the_subject = get_object_or_404(Subject, id=id) + if request.method == 'POST': + form = SubjectEditForm(request.POST, request.FILES, instance=the_subject) + if form.is_valid(): + form.save() + return redirect('web.views.subjects') + else: + form = SubjectEditForm(instance=the_subject) + return wrap_response(request, 'subjects/edit.html', { + 'form': form, + 'subject': the_subject + }) + + +def subject_delete(request, id): + the_subject = get_object_or_404(Subject, id=id) + if request.method == 'POST': + the_subject.delete() + return redirect('web.views.subjects') + else: + form = SubjectEditForm(instance=the_subject) + return wrap_response(request, 'subjects/delete.html', {'form': form}) + + +def subject_mark(request, id, as_what): + who = get_object_or_404(Subject, id=id) + if as_what == 'dead': + who.mark_as_dead() + elif as_what == 'rejected': + who.mark_as_rejected() + return redirect('web.views.subject_edit', id=id) + + +def subject_visit_details(request, id): + locsubject = get_object_or_404(Subject, id=id) + visits = locsubject.visit_set.all() + endlist = [] + for vis in visits: + assign = vis.appointment_set.all() + finished = vis.is_finished + visid = vis.id + visit_title = vis.follow_up_title() + visform = VisitDetailForm(instance=vis) + endlist.append((visform, assign, finished, visid, visit_title)) + + return wrap_response(request, 'subjects/visitdetails.html', {'display': endlist, "id": id}) diff --git a/smash/web/views/visit.py b/smash/web/views/visit.py new file mode 100644 index 0000000000000000000000000000000000000000..dfce9763c938cc7e0f467320a99c5b48e40d3ab8 --- /dev/null +++ b/smash/web/views/visit.py @@ -0,0 +1,113 @@ +# coding=utf-8 +from django.shortcuts import get_object_or_404, redirect + +from notifications import get_active_visits_with_missing_appointments, get_unfinished_visits, \ + get_approaching_visits_without_appointments, get_approaching_visits_for_mail_contact, get_exceeded_visits, \ + waiting_for_appointment +from . import wrap_response +from ..forms import VisitDetailForm, SubjectDetailForm, VisitAddForm +from ..models import Visit, Appointment, Subject + +__author__ = 'Valentin Grouès' + + +def visits(request): + visit_list = Visit.objects.order_by('-datetime_begin') + context = { + 'visit_list': visit_list + } + + return wrap_response(request, 'visits/index.html', context) + + +def visits_with_missing_appointments(request): + context = { + 'visit_list': get_active_visits_with_missing_appointments(request.user) + } + + return wrap_response(request, 'visits/index.html', context) + + +def approaching_visits_without_appointments(request): + context = { + 'visit_list': get_approaching_visits_without_appointments(request.user) + } + return wrap_response(request, 'visits/index.html', context) + + +def approaching_visits_for_mail_contact(request): + context = { + 'visit_list': get_approaching_visits_for_mail_contact(request.user) + } + return wrap_response(request, 'visits/index.html', context) + + +def visit_details(request, id): + displayed_visit = get_object_or_404(Visit, id=id) + if request.method == 'POST': + visit_form = VisitDetailForm(request.POST, request.FILES, instance=displayed_visit) + if visit_form.is_valid(): + visit_form.save() + else: + visit_form = VisitDetailForm(instance=displayed_visit) + + visit_finished = displayed_visit.is_finished + visit_id = displayed_visit.id + displayed_subject = displayed_visit.subject + list_of_appointments = displayed_visit.appointment_set.all() + + can_finish = not waiting_for_appointment(displayed_visit) + + for appointment in list_of_appointments: + if appointment.status == Appointment.APPOINTMENT_STATUS_SCHEDULED: + can_finish = False + + subject_form = SubjectDetailForm(instance=displayed_subject) + + return wrap_response(request, 'visits/details.html', { + 'vform': visit_form, + 'sform': subject_form, + 'loApp': list_of_appointments, + 'visFinished': visit_finished, + 'canFinish': can_finish, + 'vid': visit_id, + 'visit': displayed_visit}) + + +def visit_mark(request, id, as_what): + visit = get_object_or_404(Visit, id=id) + if as_what == 'finished': + visit.mark_as_finished() + + return redirect('web.views.visit_details', id=id) + + +def visit_add(request, subject_id=-1): + if request.method == 'POST': + form = VisitAddForm(request.POST, request.FILES) + if form.is_valid(): + visit = form.save() + return redirect('web.views.visit_details', visit.id) + else: + subjects = Subject.objects.filter(id=subject_id) + subject = None + if len(subjects) > 0: + subject = subjects[0] + form = VisitAddForm(initial={'subject': subject}) + + return wrap_response(request, 'visits/add.html', {'form': form}) + + +def exceeded_visits(request): + context = { + 'visit_list': get_exceeded_visits(request.user) + } + return wrap_response(request, 'visits/index.html', context) + + +def unfinished_visits(request): + context = { + 'visit_list': get_unfinished_visits(request.user) + } + + return wrap_response(request, 'visits/index.html', context)