diff --git a/smash/web/api_urls.py b/smash/web/api_urls.py index 5f8a865ff9c2e8dfe6a47ceedad30ac40421f246..6776cbcef22c105d28233688b1ff58581f153aa1 100644 --- a/smash/web/api_urls.py +++ b/smash/web/api_urls.py @@ -15,15 +15,25 @@ Including another URLconf """ from django.conf.urls import url -from web import api_views +from web.api_views import worker, location, subject, appointment_type, appointment urlpatterns = [ - url(r'^cities$', api_views.cities, name='web.api.cities'), - url(r'^countries$', api_views.countries, name='web.api.countries'), - url(r'^specializations$', api_views.specializations, name='web.api.specializations'), - url(r'^units$', api_views.units, name='web.api.units'), - url(r'^locations$', api_views.locations, name='web.api.locations'), - url(r'^referrals$', api_views.referrals, name='web.api.referrals'), - url(r'^appointment_types$', api_views.appointment_types, name='web.api.appointment_types'), - url(r'^subjects/(?P<type>[A-z]+)$', api_views.subjects, name='web.api.subjects'), + # appointments + url(r'^appointments/(?P<type>[A-z]+)$', appointment.appointments, name='web.api.appointments'), + + # appointment types + url(r'^appointment_types$', appointment_type.appointment_types, name='web.api.appointment_types'), + + # subjects data + url(r'^cities$', subject.cities, name='web.api.cities'), + url(r'^countries$', subject.countries, name='web.api.countries'), + url(r'^referrals$', subject.referrals, name='web.api.referrals'), + url(r'^subjects/(?P<type>[A-z]+)$', subject.subjects, name='web.api.subjects'), + + # locations + url(r'^locations$', location.locations, name='web.api.locations'), + + # worker data + url(r'^specializations$', worker.specializations, name='web.api.specializations'), + url(r'^units$', worker.units, name='web.api.units'), ] diff --git a/smash/web/api_views/__init__.py b/smash/web/api_views/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e23cf4209db9249f6a3c07942770e0f89fee5a1c --- /dev/null +++ b/smash/web/api_views/__init__.py @@ -0,0 +1,6 @@ +# coding=utf-8 + +import appointment_type +import location +import subject +import worker diff --git a/smash/web/api_views/appointment.py b/smash/web/api_views/appointment.py new file mode 100644 index 0000000000000000000000000000000000000000..a31bb9f13dc84481e4c782a0d7c57f518e4cdeac --- /dev/null +++ b/smash/web/api_views/appointment.py @@ -0,0 +1,109 @@ +import traceback + +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse +from django.urls import reverse + +from web.models import Appointment +from web.views import e500_error +from web.views.appointment import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_UNFINISHED, APPOINTMENT_LIST_APPROACHING +from web.views.notifications import get_filter_locations, \ + get_today_midnight_date, \ + get_unfinished_appointments + + +@login_required +def get_appointments(request, type, min_date, max_date): + if type == APPOINTMENT_LIST_GENERIC: + result = Appointment.objects.filter(location__in=get_filter_locations(request.user), + ) + elif type == APPOINTMENT_LIST_UNFINISHED: + result = get_unfinished_appointments(request.user) + elif 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: " + type) + + if min_date is not None: + result = result.filter(datetime_when__gt=min_date) + + if max_date is not None: + result = result.filter(datetime_when__lt=max_date) + return result.order_by("datetime_when") + + +@login_required +def appointments(request, type): + try: + # id of the query from dataTable: https://datatables.net/manual/server-side + draw = int(request.GET.get("draw", "-1")) + + start = int(request.GET.get("start", "0")) + length = int(request.GET.get("length", "10")) + + min_date = request.GET.get("start_date", None) + max_date = request.GET.get("end_date", None) + + if min_date is not None: + length = 1000000000 + + all_appointments = get_appointments(request, type, min_date, max_date) + + count = all_appointments.count() + + sliced_subjects = all_appointments[start:(start + length)] + + appointments = sliced_subjects + + count_filtered = sliced_subjects.count() + + data = [] + for appointment in appointments: + data.append(serialize_appointment(appointment)) + + return JsonResponse({ + "draw": draw, + "recordsTotal": count, + "recordsFiltered": count_filtered, + "data": data, + }) + except: + traceback.print_exc() + return e500_error(request) + + +def serialize_appointment(appointment): + subject = "" + if appointment.visit is not None: + title = appointment.visit.follow_up_title() + subject = appointment.visit.subject.first_name + " " + appointment.visit.subject.last_name + " (" + appointment.visit.subject.nd_number + ")" + else: + title = appointment.comment + + type = "" + for appointment_type in appointment.appointment_types.all(): + type += appointment_type.code + ", " + time = "" + if appointment.datetime_when is not None: + time = appointment.datetime_when.strftime('%Y-%m-%d %H:%M') + # time = appointment.datetime_when.strftime('%Y-%m-%d %H:%M:%S.%f %Z%z') + until = "" + if appointment.datetime_when is not None: + until = appointment.datetime_until().strftime('%Y-%m-%d %H:%M') + + result = { + "subject": subject, + "title": title, + "type": type, + "datetime_when": time, + "datetime_until": until, + "comment": appointment.comment, + "color": appointment.color(), + "id": appointment.id, + "url": reverse('web.views.appointment_edit', kwargs={'id': str(appointment.id)}) + } + return result diff --git a/smash/web/api_views/appointment_type.py b/smash/web/api_views/appointment_type.py new file mode 100644 index 0000000000000000000000000000000000000000..66f9af836adc5cd2f17cbd1a35cbd974fc6fa840 --- /dev/null +++ b/smash/web/api_views/appointment_type.py @@ -0,0 +1,20 @@ +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse + +from web.models import AppointmentType + + +@login_required +def appointment_types(request): + appointments = AppointmentType.objects.filter().all() + result = [] + for appointment in appointments: + result.append({ + "id": appointment.id, + "type": appointment.code, + "default_duration": appointment.default_duration, + "can_be_parallelized": appointment.can_be_parallelized, + }) + return JsonResponse({ + "appointment_types": result + }) diff --git a/smash/web/api_views/location.py b/smash/web/api_views/location.py new file mode 100644 index 0000000000000000000000000000000000000000..d5da64abfea495e4340409fb87012254bcf46e99 --- /dev/null +++ b/smash/web/api_views/location.py @@ -0,0 +1,15 @@ +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse + +from web.models import Location + + +@login_required +def locations(request): + locations = Location.objects.all() + data = [] + for location in locations: + data.append({"id": location.id, "name": location.name}) + return JsonResponse({ + "locations": data + }) diff --git a/smash/web/api_views.py b/smash/web/api_views/subject.py similarity index 79% rename from smash/web/api_views.py rename to smash/web/api_views/subject.py index 1d56a1fd720ecab3f7bc55077119bc6ce9490291..9368d26c2cfbdd89c16876695b29501fc8e26469 100644 --- a/smash/web/api_views.py +++ b/smash/web/api_views/subject.py @@ -1,10 +1,10 @@ from django.contrib.auth.decorators import login_required from django.http import JsonResponse -from models import Subject, Worker, AppointmentType, Location -from views import e500_error -from views.subject import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT -from views.notifications import get_subjects_with_no_visit, get_subjects_with_reminder +from web.models import Subject +from web.views import e500_error +from web.views.notifications import get_subjects_with_no_visit, get_subjects_with_reminder +from web.views.subject import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT @login_required @@ -15,17 +15,6 @@ def cities(request): }) -@login_required -def locations(request): - locations = Location.objects.all() - data = [] - for location in locations: - data.append({"id": location.id, "name": location.name}) - return JsonResponse({ - "locations": data - }) - - @login_required def countries(request): X = Subject.objects.filter(country__isnull=False).values_list('country').distinct() @@ -42,22 +31,6 @@ def referrals(request): }) -@login_required -def specializations(request): - X = Worker.objects.filter(specialization__isnull=False).values_list('specialization').distinct() - return JsonResponse({ - "specializations": [x[0] for x in X] - }) - - -@login_required -def units(request): - X = Worker.objects.filter(unit__isnull=False).values_list('unit').distinct() - return JsonResponse({ - "units": [x[0] for x in X] - }) - - @login_required def get_subjects(request, type): if type == SUBJECT_LIST_GENERIC: @@ -170,6 +143,7 @@ def subjects(request, type): except: return e500_error(request) + def get_yes_no(val): if val: return "YES" @@ -194,19 +168,3 @@ def serialize_subject(subject): "id": subject.id, } return result - - -@login_required -def appointment_types(request): - appointments = AppointmentType.objects.filter().all() - result = [] - for appointment in appointments: - result.append({ - "id": appointment.id, - "type": appointment.code, - "default_duration": appointment.default_duration, - "can_be_parallelized": appointment.can_be_parallelized, - }) - return JsonResponse({ - "appointment_types": result - }) diff --git a/smash/web/api_views/worker.py b/smash/web/api_views/worker.py new file mode 100644 index 0000000000000000000000000000000000000000..3c141e25dd9e32e08d8a2523b4804a2e03f726a7 --- /dev/null +++ b/smash/web/api_views/worker.py @@ -0,0 +1,20 @@ +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse + +from web.models import Worker + + +@login_required +def specializations(request): + X = Worker.objects.filter(specialization__isnull=False).values_list('specialization').distinct() + return JsonResponse({ + "specializations": [x[0] for x in X] + }) + + +@login_required +def units(request): + X = Worker.objects.filter(unit__isnull=False).values_list('unit').distinct() + return JsonResponse({ + "units": [x[0] for x in X] + }) diff --git a/smash/web/static/js/appointment.js b/smash/web/static/js/appointment.js index 845958ae381dbe6e03f75ad2146e14af3bdf1b22..852d14ca57b1b6fd8f66c4a7afb4bdbf52fe34bf 100644 --- a/smash/web/static/js/appointment.js +++ b/smash/web/static/js/appointment.js @@ -88,5 +88,43 @@ function appointment_type_behaviour(checkboxes, outObject, api_call) { } }); - } + +function get_calendar_events_function(source, allow_url_redirection) { + if (allow_url_redirection === undefined) { + allow_url_redirection = false; + } + return function (start, end, timezone, callback) { + $.ajax({ + data: { + // our hypothetical feed requires UNIX timestamps + start_date: start.format(), + end_date: end.format() + }, + url: source, + success: function (doc) { + var events = []; + for (var i = 0; i < doc.data.length; i++) { + var title = doc.data[i].subject; + if (title != "") { + title += "; type: " + doc.data[i].type; + } else { + title = doc.data[i].title + } + var event = { + title: title, + start: doc.data[i].datetime_when, + end: doc.data[i].datetime_until, + id: doc.data[i].id, + color: doc.data[i].color, + }; + if (allow_url_redirection) { + event["url"] = doc.data[i].url; + } + events.push(event) + } + callback(events); + } + }); + } +} \ No newline at end of file diff --git a/smash/web/templates/appointments/add.html b/smash/web/templates/appointments/add.html index 419e28dc1ab5e1cdbf1f6c24c5b952e8985fd0f3..8dcd32ef4be051c4ae1c4624c3f1e6dc95203fa5 100644 --- a/smash/web/templates/appointments/add.html +++ b/smash/web/templates/appointments/add.html @@ -136,18 +136,7 @@ document.getElementById("id_datetime_when").value = dateString; }, - events: [ - {% for appointment in full_appointment_list %} - { - title: '{{ appointment.title }}', - start: '{{ appointment.datetime_when | date:"c" }}', - end: '{{ appointment.datetime_until | date:"c" }}', - color: '{{ appointment.color }}', - subject_id: '{{ appointment.visit.subject.id }}', - id: '{{ appointment.id }}' - }, - {% endfor %} - ], + events: get_calendar_events_function("{% url 'web.api.appointments' full_list %}", false), }); }); diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html index 09b901ea52a7e62ba4f27e12cec547610161de7f..66aa979771b9489aa2cf7f065dc700b76a6e7454 100644 --- a/smash/web/templates/appointments/index.html +++ b/smash/web/templates/appointments/index.html @@ -24,53 +24,20 @@ {% block maincontent %} <div class="row"> <div class="col-md-5"> - {% if approaching_list %} - <table id="approaching_table" class="table table-bordered table-striped"> - <thead> - <tr> - <th>Subject</th> - <th>Visit</th> - <th>Type</th> - <th>Date</th> - <th>Details</th> - </tr> - </thead> - <tbody> + <table id="approaching_table" class="table table-bordered table-striped"> + <thead> + <tr> + <th>Subject</th> + <th>Visit</th> + <th>Type</th> + <th>Date</th> + <th>Details</th> + </tr> + </thead> + <tbody> + </tbody> + </table> - {% for approach in approaching_list %} - <tr> - {% if approach.visit == None %} - <td> - </td> - <td> - </td> - {% else %} - <td> - {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} - ({{ approach.visit.subject.nd_number }}) - </td> - <td> - {{ approach.visit.follow_up_title }} - </td> - {% endif %} - <td> - {% for type in approach.appointment_types.all %} - {{ type.code }}, - {% endfor %} - </td> - <td>{{ approach.datetime_when | date:"Y-m-d H:i" }}</td> - <td> - <a href="{% url 'web.views.appointment_edit' approach.id %}" type="button" - class="btn btn-block btn-default">Details</a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No visits approaching in close future.</p> - {% endif %} </div> <div class="col-md-7"> @@ -98,19 +65,36 @@ <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.js' %}"></script> + <script src="{% static 'js/appointment.js' %}"></script> <script> $(function () { - $('#planning_table, #approaching_table').DataTable({ - "paging": true, - "lengthChange": false, - "searching": true, - "ordering": true, - "order": [[3, "asc"]], - "info": true, - "autoWidth": false + var table = $('#approaching_table').DataTable({ + serverSide: true, + processing: true, + ordering: false, + ajax: "{% url 'web.api.appointments' approaching_list %}", + columns: [ + {"data": "subject"}, + {"data": "title"}, + {"data": "type"}, + {"data": "datetime_when"}, + {"data": null}, + ], + columnDefs: [{ + "targets": 4, + "data": "id", + "defaultContent": '<a href="#" type="button" class="btn btn-block btn-default">Edit</a>' + }] + }) + $('#approaching_table tbody').on('click', 'a', function () { + var data = table.row($(this).parents('tr')).data(); + var url = "{% url 'web.views.appointment_edit' 12345 %}".replace(/12345/, data.id.toString()); + window.location.href = url; }); + $('#approaching_table_filter').css("display", "none"); + $('#calendar').fullCalendar({ header: { left: 'prev,next today', @@ -119,19 +103,9 @@ }, editable: false, weekNumbers: true, - events: [ - {% for appointment in full_list %} - { - title: '{{ appointment.title }}', - start: '{{ appointment.datetime_when | date:"c" }}', - end: '{{ appointment.datetime_until | date:"c" }}', - color: '{{ appointment.color }}', - subject_id: '{{ appointment.visit.subject.id }}', - id: '{{ appointment.id }}', - url: '{% url 'web.views.appointment_edit' appointment.id %}', - }, - {% endfor %} - ], + startParam: "start_date", + endParam: "end_date", + events: get_calendar_events_function("{% url 'web.api.appointments' full_list %}", false), }); }); </script> diff --git a/smash/web/templates/appointments/list.html b/smash/web/templates/appointments/list.html index 782f8d5ba79e2aa93e8361023872a950f9acad2c..b20d99c7b0dfcf3dee0d1eb9609ae3902b84faf0 100644 --- a/smash/web/templates/appointments/list.html +++ b/smash/web/templates/appointments/list.html @@ -6,9 +6,6 @@ <!-- DataTables --> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> - <!-- fullCalendar 2.2.5--> - <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.css' %}"> - <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.print.css' %}" media="print"> {% endblock styles %} {% block ui_active_tab %}'appointments'{% endblock ui_active_tab %} @@ -24,7 +21,7 @@ {% block maincontent %} <div class="row"> <div class="col-md-16"> - <table id="approaching_table" class="table table-bordered table-striped"> + <table id="table" class="table table-bordered table-striped"> <thead> <tr> <th>Subject</th> @@ -32,41 +29,70 @@ <th>Type</th> <th>Date</th> <th>Details</th> + <th>Edit</th> </tr> </thead> <tbody> - - {% for approach in appointment_list %} - <tr> - {% if approach.visit == None %} - <td> - </td> - <td> - </td> - {% else %} - <td> - {{ approach.visit.subject.first_name }} {{ approach.visit.subject.last_name }} - ({{ approach.visit.subject.nd_number }}) - </td> - <td> - {{ approach.visit.follow_up_title }} - </td> - {% endif %} - <td> - {% for type in approach.appointment_types.all %} - {{ type.code }}, - {% endfor %} - </td> - <td>{{ approach.datetime_when | date:"Y-m-d H:i" }}</td> - <td> - <a href="{% url 'web.views.appointment_edit' approach.id %}" type="button" - class="btn btn-block btn-default">Details</a> - </td> - </tr> - {% endfor %} </tbody> + <tfoot style="display: table-header-group;"/> </table> </div> </div> {% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> + <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> + + <script> + $(function () { + var table = $('#table').DataTable({ + serverSide: true, + processing: true, + ordering: false, + ajax: "{% url 'web.api.appointments' list_type %}", + columns: [ + {"data": "subject"}, + {"data": "title"}, + {"data": "type"}, + {"data": "datetime_when"}, + {"data": "comment"}, + {"data": null}, + ], + columnDefs: [{ + "targets": 5, + "data": "id", + "defaultContent": '<a href="#" type="button" class="btn btn-block btn-default">Edit</a>' + }, +{# {#} +{# render: function (data, type, row) {#} +{# var date = new Date(data);#} +{# var mm = date.getMonth() + 1; // getMonth() is zero-based#} +{# var dd = date.getDate();#} +{# var hour = date.getHours();#} +{# var minute = date.getMinutes();#} +{##} +{# return [date.getFullYear(),#} +{# (mm > 9 ? '' : '0') + mm,#} +{# (dd > 9 ? '' : '0') + dd#} +{# ].join('-') + " " + hour + ":" + minute;#} +{# },#} +{# targets: 3#} +{# }#} + ] + }); + + $('#table tbody').on('click', 'a', function () { + var data = table.row($(this).parents('tr')).data(); + var url = "{% url 'web.views.appointment_edit' 12345 %}".replace(/12345/, data.id.toString()); + window.location.href = url; + }); + + $('#table_filter').css("display", "none"); + }); + </script> + +{% endblock scripts %} diff --git a/smash/web/tests/test_api_appointment.py b/smash/web/tests/test_api_appointment.py new file mode 100644 index 0000000000000000000000000000000000000000..bf28f7c757745e3c1afbe8fa1853c47a58e04b1f --- /dev/null +++ b/smash/web/tests/test_api_appointment.py @@ -0,0 +1,100 @@ +# coding=utf-8 + +import datetime + +from django.contrib.auth.models import User +from django.test import Client +from django.test import TestCase +from django.urls import reverse + +from web.tests.functions import create_subject, create_worker, create_visit, create_appointment, \ + create_appointment_type, create_get_suffix +from web.views.appointment import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_APPROACHING, APPOINTMENT_LIST_UNFINISHED +from web.views.notifications import get_today_midnight_date + + +class TestApi(TestCase): + def setUp(self): + self.subject = create_subject() + self.client = Client() + username = 'piotr' + password = 'top_secret' + self.user = User.objects.create_user( + username=username, email='jacob@bla', password=password) + self.worker = create_worker(self.user) + self.client.login(username=username, password=password) + + def test_appointments_invalid(self): + response = self.client.get(reverse('web.api.appointments', kwargs={'type': "bla"})) + self.assertEqual(response.status_code, 500) + + def test_appointments_valid(self): + name = "Piotrek" + self.subject.first_name = name + self.subject.save() + visit = create_visit(self.subject) + create_appointment(visit) + appointment2 = create_appointment(visit, get_today_midnight_date()) + appointment2.visit = None + appointment2.appointment_types.add(create_appointment_type()) + appointment2.save() + + url = reverse('web.api.appointments', kwargs={'type': APPOINTMENT_LIST_GENERIC}) + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertTrue(name in response.content) + + def test_appointments_approaching(self): + name = "Piotrek" + self.subject.first_name = name + self.subject.save() + visit = create_visit(self.subject) + create_appointment(visit, get_today_midnight_date() + datetime.timedelta(days=2)) + + url = reverse('web.api.appointments', kwargs={'type': APPOINTMENT_LIST_APPROACHING}) + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertTrue(name in response.content) + + def test_appointments_unfinished(self): + name = "Piotrek" + self.subject.first_name = name + self.subject.save() + visit = create_visit(self.subject) + create_appointment(visit, get_today_midnight_date() + datetime.timedelta(days=-12)) + + url = reverse('web.api.appointments', kwargs={'type': APPOINTMENT_LIST_UNFINISHED}) + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertTrue(name in response.content) + + def test_get_calendar_appointments(self): + name = "Peter" + self.subject.first_name = name + self.subject.save() + visit = create_visit(self.subject) + appointment = create_appointment(visit, get_today_midnight_date()) + appointment.appointment_types.add(create_appointment_type()) + appointment.save() + + params = { + "start_date": (get_today_midnight_date() + datetime.timedelta(days=2)).strftime("%Y-%m-%d"), + "end_date": (get_today_midnight_date() + datetime.timedelta(days=3)).strftime("%Y-%m-%d"), + } + url = ("%s" + create_get_suffix(params)) % reverse('web.api.appointments', + kwargs={'type': APPOINTMENT_LIST_GENERIC}) + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertFalse(name in response.content) + + params["start_date"] = (get_today_midnight_date() + datetime.timedelta(days=-2)).strftime("%Y-%m-%d") + url = ("%s" + create_get_suffix(params)) % reverse('web.api.appointments', + kwargs={'type': APPOINTMENT_LIST_GENERIC}) + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertTrue(name in response.content) diff --git a/smash/web/tests/test_api_appointment_type.py b/smash/web/tests/test_api_appointment_type.py new file mode 100644 index 0000000000000000000000000000000000000000..24b06c1feda1ac4e0f6b20237fcd38147f00b529 --- /dev/null +++ b/smash/web/tests/test_api_appointment_type.py @@ -0,0 +1,40 @@ +# coding=utf-8 +import json + +from django.contrib.auth.models import User +from django.test import Client +from django.test import TestCase +from django.urls import reverse + +from web.tests.functions import create_worker, create_appointment_type + + +class TestApi(TestCase): + def setUp(self): + self.client = Client() + username = 'piotr' + password = 'top_secret' + self.user = User.objects.create_user( + username=username, email='jacob@bla', password=password) + self.worker = create_worker(self.user) + self.client.login(username=username, password=password) + + def test_appointment_types(self): + type_name = "some type name" + + response = self.client.get(reverse('web.api.appointment_types')) + self.assertEqual(response.status_code, 200) + + self.appointment_type = create_appointment_type() + self.appointment_type.code = type_name + self.appointment_type.save() + + response = self.client.get(reverse('web.api.appointment_types')) + appointment_types = json.loads(response.content)['appointment_types'] + + found = False + for type in appointment_types: + if type['type'] == type_name: + found = True + + self.assertTrue(found) diff --git a/smash/web/tests/test_api_location.py b/smash/web/tests/test_api_location.py new file mode 100644 index 0000000000000000000000000000000000000000..cd7c55167b75022e929324430344271ad8fac5de --- /dev/null +++ b/smash/web/tests/test_api_location.py @@ -0,0 +1,38 @@ +# coding=utf-8 +import json + +from django.contrib.auth.models import User +from django.test import Client +from django.test import TestCase +from django.urls import reverse + +from web.tests.functions import create_worker, create_location + + +class TestApi(TestCase): + def setUp(self): + self.client = Client() + username = 'piotr' + password = 'top_secret' + self.user = User.objects.create_user( + username=username, email='jacob@bla', password=password) + self.worker = create_worker(self.user) + self.client.login(username=username, password=password) + + def test_locations(self): + location_name = "some location" + + response = self.client.get(reverse('web.api.locations')) + self.assertEqual(response.status_code, 200) + + create_location(location_name) + + response = self.client.get(reverse('web.api.locations')) + locations = json.loads(response.content)['locations'] + + found = False + for location in locations: + if location['name'] == location_name: + found = True + + self.assertTrue(found) diff --git a/smash/web/tests/test_api.py b/smash/web/tests/test_api_subject.py similarity index 76% rename from smash/web/tests/test_api.py rename to smash/web/tests/test_api_subject.py index f032b1d602d107f30e1e410d4ac9f0c3a26256a0..9a947b410031fe06d9fd96e3ed113f7b8647d8f2 100644 --- a/smash/web/tests/test_api.py +++ b/smash/web/tests/test_api_subject.py @@ -1,21 +1,27 @@ # coding=utf-8 import json +from django.contrib.auth.models import User +from django.test import Client +from django.test import TestCase from django.urls import reverse -from web.api_views import get_subjects_order, get_subjects_filtered, serialize_subject +from web.api_views.subject import get_subjects_order, get_subjects_filtered, serialize_subject, SUBJECT_LIST_GENERIC, \ + SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT from web.models import Subject -from web.tests.functions import create_location, \ - create_get_suffix -from web.tests.functions import create_subject, create_appointment_type -from web.views.subject import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT -from . import LoggedInWithWorkerTestCase +from web.tests.functions import create_subject, create_worker, create_get_suffix -class TestApi(LoggedInWithWorkerTestCase): +class TestApi(TestCase): def setUp(self): - super(TestApi, self).setUp() self.subject = create_subject() + self.client = Client() + username = 'piotr' + password = 'top_secret' + self.user = User.objects.create_user( + username=username, email='jacob@bla', password=password) + self.worker = create_worker(self.user) + self.client.login(username=username, password=password) def test_cities(self): city_name = "some city" @@ -35,24 +41,6 @@ class TestApi(LoggedInWithWorkerTestCase): self.assertTrue(city_name in cities) - def test_locations(self): - location_name = "some location" - - response = self.client.get(reverse('web.api.locations')) - self.assertEqual(response.status_code, 200) - - location = create_location(location_name) - - response = self.client.get(reverse('web.api.locations')) - appointment_types = json.loads(response.content)['locations'] - - found = False - for type in appointment_types: - if type['name'] == location_name: - found = True - - self.assertTrue(found) - def test_countries(self): country_name = "some country" @@ -71,42 +59,6 @@ class TestApi(LoggedInWithWorkerTestCase): self.assertTrue(country_name in countries) - def test_specializations(self): - specialization_name = "some spec" - - response = self.client.get(reverse('web.api.specializations')) - self.assertEqual(response.status_code, 200) - - specializations = json.loads(response.content)['specializations'] - - self.assertFalse(specialization_name in specializations) - - self.worker.specialization = specialization_name - self.worker.save() - - response = self.client.get(reverse('web.api.specializations')) - specializations = json.loads(response.content)['specializations'] - - self.assertTrue(specialization_name in specializations) - - def test_units(self): - unit_name = "some unit" - - response = self.client.get(reverse('web.api.units')) - self.assertEqual(response.status_code, 200) - - units = json.loads(response.content)['units'] - - self.assertFalse(unit_name in units) - - self.worker.unit = unit_name - self.worker.save() - - response = self.client.get(reverse('web.api.units')) - units = json.loads(response.content)['units'] - - self.assertTrue(unit_name in units) - def test_referrals(self): referral_name = "some referral" @@ -125,26 +77,6 @@ class TestApi(LoggedInWithWorkerTestCase): self.assertTrue(referral_name in referrals) - def test_appointment_types(self): - type_name = "some type name" - - response = self.client.get(reverse('web.api.appointment_types')) - self.assertEqual(response.status_code, 200) - - self.appointment_type = create_appointment_type() - self.appointment_type.code = type_name - self.appointment_type.save() - - response = self.client.get(reverse('web.api.appointment_types')) - appointment_types = json.loads(response.content)['appointment_types'] - - found = False - for type in appointment_types: - if type['type'] == type_name: - found = True - - self.assertTrue(found) - def test_subjects_general(self): response = self.client.get(reverse('web.api.subjects', kwargs={'type': SUBJECT_LIST_GENERIC})) self.assertEqual(response.status_code, 200) diff --git a/smash/web/tests/test_api_worker.py b/smash/web/tests/test_api_worker.py new file mode 100644 index 0000000000000000000000000000000000000000..f3f353d3b4fbd2a45dd4703545dc8269b5f2c617 --- /dev/null +++ b/smash/web/tests/test_api_worker.py @@ -0,0 +1,56 @@ +# coding=utf-8 +import json + +from django.contrib.auth.models import User +from django.test import Client +from django.test import TestCase +from django.urls import reverse + +from web.tests.functions import create_subject, create_worker + + +class TestApi(TestCase): + def setUp(self): + self.client = Client() + username = 'piotr' + password = 'top_secret' + self.user = User.objects.create_user( + username=username, email='jacob@bla', password=password) + self.worker = create_worker(self.user) + self.client.login(username=username, password=password) + + def test_specializations(self): + specialization_name = "some spec" + + response = self.client.get(reverse('web.api.specializations')) + self.assertEqual(response.status_code, 200) + + specializations = json.loads(response.content)['specializations'] + + self.assertFalse(specialization_name in specializations) + + self.worker.specialization = specialization_name + self.worker.save() + + response = self.client.get(reverse('web.api.specializations')) + specializations = json.loads(response.content)['specializations'] + + self.assertTrue(specialization_name in specializations) + + def test_units(self): + unit_name = "some unit" + + response = self.client.get(reverse('web.api.units')) + self.assertEqual(response.status_code, 200) + + units = json.loads(response.content)['units'] + + self.assertFalse(unit_name in units) + + self.worker.unit = unit_name + self.worker.save() + + response = self.client.get(reverse('web.api.units')) + units = json.loads(response.content)['units'] + + self.assertTrue(unit_name in units) diff --git a/smash/web/views/appointment.py b/smash/web/views/appointment.py index c13a07129603005fb0a2d6cb508573299822d5cb..8bc59f0c2d1b637b96abe4c12ba5966c2dea6732 100644 --- a/smash/web/views/appointment.py +++ b/smash/web/views/appointment.py @@ -1,34 +1,27 @@ # coding=utf-8 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 wrap_response from ..forms import AppointmentDetailForm, AppointmentAddForm, AppointmentEditForm, SubjectEditForm from ..models import Appointment +APPOINTMENT_LIST_GENERIC = "GENERIC" +APPOINTMENT_LIST_UNFINISHED = "UNFINISHED" +APPOINTMENT_LIST_APPROACHING = "APPROACHING" -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) +def appointments(request): context = { - 'approaching_list': approaching_list, - 'full_list': full_list + 'approaching_list': APPOINTMENT_LIST_APPROACHING, + 'full_list': APPOINTMENT_LIST_GENERIC } return wrap_response(request, "appointments/index.html", context) def unfinished_appointments(request): - appointments = get_unfinished_appointments(request.user) context = { - 'appointment_list': appointments, + 'list_type': APPOINTMENT_LIST_UNFINISHED, } return wrap_response(request, "appointments/list.html", context) @@ -41,7 +34,6 @@ def appointment_details(request, id): def appointment_add(request, visit_id=None): - full_list = get_calendar_full_appointments(request.user) if request.method == 'POST': form = AppointmentAddForm(request.POST, request.FILES, user=request.user) if form.is_valid(): @@ -55,7 +47,7 @@ def appointment_add(request, visit_id=None): form = AppointmentAddForm(user=request.user) return wrap_response(request, 'appointments/add.html', - {'form': form, 'visitID': visit_id, 'full_appointment_list': full_list}) + {'form': form, 'visitID': visit_id, 'full_list': APPOINTMENT_LIST_GENERIC}) def appointment_edit(request, id): @@ -84,7 +76,7 @@ def appointment_edit(request, id): subject_form.save() the_appointment = get_object_or_404(Appointment, id=id) if (the_appointment.status != Appointment.APPOINTMENT_STATUS_SCHEDULED) and ( - the_appointment.visit is not None): + the_appointment.visit is not None): return redirect('web.views.visit_details', id=the_appointment.visit.id) else: return redirect('web.views.appointments') diff --git a/smash/web/views/notifications.py b/smash/web/views/notifications.py index 0c57e769614b0c18076a4bc6079520af0a4ed79d..31f749d8f8997c25ada97ffa4f2043b059f2ce21 100644 --- a/smash/web/views/notifications.py +++ b/smash/web/views/notifications.py @@ -241,12 +241,4 @@ def get_filter_locations(user): 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') + return today_midnight \ No newline at end of file