diff --git a/smash/web/api_urls.py b/smash/web/api_urls.py index 4db32fe7df7a63bb925204d415e42589b69c3d17..93f32c2839d8ea0448c8cc88324cb2630ccb2aec 100644 --- a/smash/web/api_urls.py +++ b/smash/web/api_urls.py @@ -43,6 +43,7 @@ urlpatterns = [ url(r'^specializations$', worker.specializations, name='web.api.specializations'), url(r'^units$', worker.units, name='web.api.units'), url(r'^workers$', worker.workers_for_daily_planning, name='web.api.workers'), + url(r'^workers/availabilities$', worker.availabilities, name='web.api.workers.availabilities$'), # daily planning events url(r'^events/(?P<date>\d{4}-\d{2}-\d{2})/$', daily_planning.events, name='web.api.events'), diff --git a/smash/web/api_views/worker.py b/smash/web/api_views/worker.py index 5183e3cd3fa5ae515102ed8e8d860f27f52c0c7f..d9edbcc1dab1a455c7c29f53165b8b278d86802a 100644 --- a/smash/web/api_views/worker.py +++ b/smash/web/api_views/worker.py @@ -1,7 +1,10 @@ +import datetime + from django.contrib.auth.decorators import login_required from django.http import JsonResponse +from django.utils import timezone -from web.api_views.daily_planning import get_workers_for_daily_planning +from web.api_views.daily_planning import get_workers_for_daily_planning, get_availabilities from ..models import Worker @@ -33,3 +36,31 @@ def workers_for_daily_planning(request): } workers_list_for_json.append(worker_dict_for_json) return JsonResponse(workers_list_for_json, safe=False) + + +@login_required +def availabilities(request): + result = [] + min_date = request.GET.get("start_date") + max_date = request.GET.get("end_date") + + workers = get_workers_for_daily_planning(request) + + min_date = datetime.datetime.strptime(min_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo) + max_date = datetime.datetime.strptime(max_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo) + + while min_date <= max_date: + str_date = min_date.strftime('%Y-%m-%d') + date_result = {"date": str_date, "workers": []} + for worker in workers: + if len(get_availabilities(worker, str_date)) > 0: + date_result["workers"].append({ + "worker_id": worker.id, + "initials": worker.initials(), + }) + result.append(date_result) + min_date += datetime.timedelta(days=1) + + return JsonResponse({ + "availabilities": result, + }) diff --git a/smash/web/models/worker.py b/smash/web/models/worker.py index dd9a2205c1f0448c2575259b15910969b077bfd8..8923532e3351205d48ed2e7b8fe0419b670d2efe 100644 --- a/smash/web/models/worker.py +++ b/smash/web/models/worker.py @@ -111,3 +111,11 @@ class Worker(models.Model): def __unicode__(self): return "%s %s" % (self.first_name, self.last_name) + + def initials(self): + result = "" + if len(self.first_name) > 0: + result += self.first_name[0] + if len(self.last_name) > 0: + result += self.last_name[0] + return result diff --git a/smash/web/static/js/appointment.js b/smash/web/static/js/appointment.js index a2e1b2222be56ac369170aefb062a161b2a6ea66..a4d594bab159699c5a2c247589176075e5f788ad 100644 --- a/smash/web/static/js/appointment.js +++ b/smash/web/static/js/appointment.js @@ -202,11 +202,35 @@ function appointment_date_change_behaviour(datetime_picker, worker_select, minut } -function get_calendar_events_function(source, allow_url_redirection) { +function get_calendar_events_function(source, allow_url_redirection, day_headers, workerAvailabilitiesUrl) { if (allow_url_redirection === undefined) { allow_url_redirection = false; } return function (start, end, timezone, callback) { + if (day_headers !== undefined) { + console.log("XXXX"); + $.ajax({ + data: { + start_date: start.format(), + end_date: end.format() + }, + url: workerAvailabilitiesUrl, + success: function (doc) { + for (var i = 0; i < doc.availabilities.length; i++) { + const entry = doc.availabilities[i]; + var initials = ''; + for (var j = 0; j < entry.workers.length; j++) { + initials += entry.workers[j].initials + ", "; + } + var element = day_headers[entry.date]; + if (element !== undefined) { + element.innerHTML = initials; + } + } + } + }); + + } $.ajax({ data: { // our hypothetical feed requires UNIX timestamps @@ -220,7 +244,7 @@ function get_calendar_events_function(source, allow_url_redirection) { const entry = doc.data[i]; var title = entry.subject; - if (title != "") { + if (title !== "") { title += " (" + entry.nd_number + "); type: " + entry.type; } else { title = entry.title diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html index ef999fa5639509de7ace34c3216a8a94d43186c3..81a642dc496a82ee4af2cf402e88b9ce640c42c2 100644 --- a/smash/web/templates/appointments/index.html +++ b/smash/web/templates/appointments/index.html @@ -75,6 +75,7 @@ <script> $(function () { + var dayHeaders = {}; var approachingTable = $('#approaching_table'); var table = approachingTable.DataTable({ serverSide: true, @@ -115,6 +116,12 @@ weekNumbers: true, startParam: "start_date", endParam: "end_date", + dayRender: function (date, cell) { + var element = document.createElement("div"); + cell[0].appendChild(element); + dayHeaders[$(cell[0]).attr("data-date")] = element; + }, + eventRender: function (event, element) { var content = "<ul>"; if (event.phone_number) { @@ -143,7 +150,10 @@ }); console.log(event); }, - events: get_calendar_events_function("{% url 'web.api.appointments' full_list %}", true), + events: get_calendar_events_function( + "{% url 'web.api.appointments' full_list %}", + true, dayHeaders, + "{% url 'web.api.workers.availabilities$' %}") }); }); </script> diff --git a/smash/web/tests/api_views/test_redcap.py b/smash/web/tests/api_views/test_redcap.py index 5c1c774b91eda013b507d0ae611b98101609047c..276c09f2db2d7d4ade530fade85a604bb070aebe 100644 --- a/smash/web/tests/api_views/test_redcap.py +++ b/smash/web/tests/api_views/test_redcap.py @@ -1,5 +1,4 @@ # coding=utf-8 -import json from django.contrib.auth.models import User from django.test import Client diff --git a/smash/web/tests/api_views/test_worker.py b/smash/web/tests/api_views/test_worker.py index 061f4ca810dca335585e8efda7aeb2d6097c768b..33e4b71dcea12e2aec30eb85cc4b24ff6f382467 100644 --- a/smash/web/tests/api_views/test_worker.py +++ b/smash/web/tests/api_views/test_worker.py @@ -1,8 +1,12 @@ # coding=utf-8 import json +from django.test import RequestFactory from django.urls import reverse +from web.models import Availability +from web.models.constants import TUESDAY_AS_DAY_OF_WEEK +from web.api_views.worker import availabilities from web.tests import LoggedInWithWorkerTestCase @@ -47,3 +51,29 @@ class TestApi(LoggedInWithWorkerTestCase): response = self.client.get(reverse('web.api.workers')) self.assertEqual(response.status_code, 200) self.assertTrue(self.worker.first_name in response.content) + + def test_empty_availabilities(self): + factory = RequestFactory() + request = factory.get('/api/workers?start_date=2017-10-20&end_date=2017-11-20') + request.user = self.user + + result = availabilities(request) + entries = json.loads(result.content)['availabilities'] + for entry in entries: + self.assertEqual(0, len(entry["workers"])) + + def test_non_empty_availabilities(self): + factory = RequestFactory() + request = factory.get('/api/workers?start_date=2017-10-20&end_date=2017-11-20') + request.user = self.user + + availability = Availability.objects.create(person=self.worker, day_number=TUESDAY_AS_DAY_OF_WEEK, + available_from="8:00", available_till="16:00") + availability.save() + + result = availabilities(request) + entries = json.loads(result.content)['availabilities'] + count = 0; + for entry in entries: + count += len(entry["workers"]) + self.assertTrue(count > 0)