diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py index 0d19d00e0d4e2fae924d54b839fbc72f68e6f411..abdd81b424eeae69231dd0b0b2a45bf3236e440b 100644 --- a/smash/web/api_views/subject.py +++ b/smash/web/api_views/subject.py @@ -153,10 +153,10 @@ def subjects(request, type): return e500_error(request) - @login_required def types(request): - data = [{"id": subject_type_id, "name": subject_type_name} for subject_type_id, subject_type_name in SUBJECT_TYPE_CHOICES.items() ] + data = [{"id": subject_type_id, "name": subject_type_name} for subject_type_id, subject_type_name in + SUBJECT_TYPE_CHOICES.items()] return JsonResponse({ "types": data }) diff --git a/smash/web/forms.py b/smash/web/forms.py index 7ff1bc1a001969c4323ad3f40e7eebac6cd1a1be..6dda525d948bdc994968347163c5fb989dbc4240 100644 --- a/smash/web/forms.py +++ b/smash/web/forms.py @@ -5,13 +5,15 @@ from django import forms from django.forms import ModelForm, Form from django.utils.dates import MONTHS -from models import Subject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink +from models import Subject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink, \ + Availability from models.constants import SUBJECT_TYPE_CHOICES, SCREENING_NUMBER_PREFIXES_FOR_TYPE """ Possible redundancy, but if need arises, contents of forms can be easily customized """ +DATE_FORMAT_TIME = "%H:%M" CURRENT_YEAR = datetime.datetime.now().year YEAR_CHOICES = tuple(range(CURRENT_YEAR, CURRENT_YEAR - 120, -1)) FUTURE_YEAR_CHOICES = tuple(range(CURRENT_YEAR, CURRENT_YEAR + 5, 1)) @@ -24,6 +26,11 @@ DATETIMEPICKER_DATE_ATTRS = { 'class': 'datetimepicker', 'data-date-format': 'Y-MM-DD HH:mm', } +TIMEPICKER_DATE_ATTRS = { + 'class': 'datetimepicker', + 'data-date-format': 'HH:mm', + 'data-date-stepping': 15, +} START_YEAR_STATISTICS = 2015 APPOINTMENT_TYPES_FIELD_POSITION = 1 @@ -171,12 +178,6 @@ class WorkerAddForm(ModelForm): exclude = ['appointments'] -class WorkerDetailForm(ModelForm): - class Meta: - model = Worker - fields = '__all__' - - class WorkerEditForm(ModelForm): class Meta: model = Worker @@ -383,3 +384,66 @@ class StatisticsForm(Form): choices.extend(SUBJECT_TYPE_CHOICES.items()) self.fields['subject_type'] = forms.ChoiceField(choices=choices, initial="-1") self.fields['visit'] = forms.ChoiceField(choices=visit_choices, initial="-1") + + +class AvailabilityAddForm(ModelForm): + available_from = forms.TimeField(label="Available from", + widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), + initial="8:00", + ) + available_till = forms.TimeField(label="Available until", + widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), + initial="17:00", + ) + + class Meta: + model = Availability + fields = '__all__' + + def clean(self): + worker = Worker.objects.get(id=self.cleaned_data["person"].id) + availabilities = worker.availability_set.all() + for availability in availabilities: + validate_availability_conflict(self, self.cleaned_data, availability) + + +class AvailabilityEditForm(ModelForm): + available_from = forms.TimeField(label="Available from", + widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), + ) + available_till = forms.TimeField(label="Available until", + widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), + ) + + class Meta: + model = Availability + fields = '__all__' + + def __init__(self, *args, **kwargs): + super(ModelForm, self).__init__(*args, **kwargs) + instance = getattr(self, 'instance', None) + if instance is not None: + self.availability_id = instance.id + self.fields['person'].disabled = True + + def clean(self): + worker = Worker.objects.get(id=self.cleaned_data["person"].id) + availabilities = worker.availability_set.all() + for availability in availabilities: + if availability.id<> self.availability_id: + validate_availability_conflict(self, self.cleaned_data, availability) + + +def validate_availability_conflict(self, cleaned_data, availability): + start_hour = self.cleaned_data.get("available_from",None) + end_hour = self.cleaned_data.get("available_till",None) + if availability.day_number == self.cleaned_data.get("day_number", None) and \ + ((start_hour <= availability.available_from < end_hour) or + (start_hour < availability.available_till <= end_hour) or + (availability.available_from <= start_hour < availability.available_till) or + (availability.available_from < end_hour <= availability.available_till)): + error = "User has defined availability for this day that overlaps: " + availability.available_from.strftime( + DATE_FORMAT_TIME) + ", " + availability.available_till.strftime(DATE_FORMAT_TIME) + self.add_error('day_number', error) + self.add_error('available_from', error) + self.add_error('available_till', error) diff --git a/smash/web/migrations/0043_auto_20170904_1240.py b/smash/web/migrations/0043_auto_20170904_1240.py new file mode 100644 index 0000000000000000000000000000000000000000..d3e36a76b842b5102a1fd59c8782d64b873ad530 --- /dev/null +++ b/smash/web/migrations/0043_auto_20170904_1240.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-09-04 10:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0042_auto_20170613_1634'), + ] + + operations = [ + migrations.RemoveField( + model_name='availability', + name='is_current', + ), + migrations.AlterField( + model_name='availability', + name='available_from', + field=models.TimeField(verbose_name=b'Available from'), + ), + migrations.AlterField( + model_name='availability', + name='available_till', + field=models.TimeField(default=b'17:00', verbose_name=b'Available until'), + ), + migrations.AlterField( + model_name='availability', + name='day_number', + field=models.IntegerField(choices=[(1, b'MONDAY'), (2, b'TUESDAY'), (3, b'WEDNESDAY'), (4, b'THURSDAY'), (5, b'FRIDAY'), (6, b'SATURDAY'), (7, b'SUNDAY')], verbose_name=b'Day of the week'), + ), + ] diff --git a/smash/web/migrations/0044_auto_20170904_1602.py b/smash/web/migrations/0044_auto_20170904_1602.py new file mode 100644 index 0000000000000000000000000000000000000000..204314cb090d496ae0185b5509487534a84f0983 --- /dev/null +++ b/smash/web/migrations/0044_auto_20170904_1602.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-09-04 14:02 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0043_auto_20170904_1240'), + ] + + operations = [ + migrations.AlterField( + model_name='availability', + name='available_till', + field=models.TimeField(verbose_name=b'Available until'), + ), + ] diff --git a/smash/web/models/availability.py b/smash/web/models/availability.py index 8323a6ab311756145b1a307d4d17ba83f32cf2bd..a375ce11e93a03fb5b7616a99afb133219cff033 100644 --- a/smash/web/models/availability.py +++ b/smash/web/models/availability.py @@ -1,6 +1,11 @@ # coding=utf-8 + +import datetime + from django.db import models +from constants import WEEKDAY_CHOICES + class Availability(models.Model): class Meta: @@ -10,17 +15,14 @@ class Availability(models.Model): verbose_name='Worker' ) day_number = models.IntegerField( - verbose_name='Day of the week' + verbose_name='Day of the week', + choices=WEEKDAY_CHOICES ) available_from = models.TimeField( - verbose_name='Available since' + verbose_name='Available from', ) available_till = models.TimeField( - verbose_name='Available until' - ) - is_current = models.BooleanField( - verbose_name='Is current?', - default=True + verbose_name='Available until', ) def __str__(self): diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py index 6d5fbeef623b083661c57842689254ac95f12fde..0ce288687e46156dd99ede9f0d1c76c2610ca193 100644 --- a/smash/web/models/constants.py +++ b/smash/web/models/constants.py @@ -61,3 +61,13 @@ THURSDAY_AS_DAY_OF_WEEK = 4 FRIDAY_AS_DAY_OF_WEEK = 5 SATURDAY_AS_DAY_OF_WEEK = 6 SUNDAY_AS_DAY_OF_WEEK = 7 + +WEEKDAY_CHOICES = ( + (MONDAY_AS_DAY_OF_WEEK, 'MONDAY'), + (TUESDAY_AS_DAY_OF_WEEK, 'TUESDAY'), + (WEDNESDAY_AS_DAY_OF_WEEK, 'WEDNESDAY'), + (THURSDAY_AS_DAY_OF_WEEK, 'THURSDAY'), + (FRIDAY_AS_DAY_OF_WEEK, 'FRIDAY'), + (SATURDAY_AS_DAY_OF_WEEK, 'SATURDAY'), + (SUNDAY_AS_DAY_OF_WEEK, 'SUNDAY'), +) diff --git a/smash/web/templates/doctors/add.html b/smash/web/templates/doctors/add.html index e70a0b8064a6daa80de09dd812fe18bb26cc1228..eb17a92775c2ae3206b8545d674c9b2614361274 100644 --- a/smash/web/templates/doctors/add.html +++ b/smash/web/templates/doctors/add.html @@ -25,10 +25,6 @@ <a href="{% url 'web.views.doctors' %}" class="btn btn-block btn-default">Go back (without changes)</a> </div> - {% comment %} <div class="box-header with-border"> - <h3 class="box-title">Add new worker</h3> - </div>{% endcomment %} - <form method="post" action="" class="form-horizontal"> {% csrf_token %} @@ -46,8 +42,8 @@ {% if field.errors %} <span class="help-block"> - {{ field.errors }} - </span> + {{ field.errors }} + </span> {% endif %} </div> {% endfor %} @@ -76,7 +72,7 @@ <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> <script> - // If ever to debug and thinking why it doesn't work => look if theres 'null' in data from API + // If ever to debug and thinking why it doesn't work => look if there is 'null' in data from API $.get("{% url 'web.api.specializations' %}", function (data) { new Awesomplete(document.querySelector("#id_specialization")).list = data.specializations; }); diff --git a/smash/web/templates/doctors/add_availability.html b/smash/web/templates/doctors/add_availability.html new file mode 100644 index 0000000000000000000000000000000000000000..a5c7da1ec1b84329368af1b8b135bbb60044d02b --- /dev/null +++ b/smash/web/templates/doctors/add_availability.html @@ -0,0 +1,85 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + {% include "includes/datetimepicker.css.html" %} + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/> +{% endblock styles %} + +{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} +{% block page_header %}New worker availability{% endblock page_header %} +{% block page_description %}{% endblock page_description %} + +{% block title %}{{ block.super }} - Add availability{% endblock %} + +{% block breadcrumb %} + {% include "doctors/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="box box-info"> + <div class="box-header with-border"> + <a href="{% url 'web.views.doctor_edit' doctor_id %}" class="btn btn-block btn-default">Go back (without + changes)</a> + </div> + + <form method="post" action="" class="form-horizontal"> + {% csrf_token %} + + <div class="box-body"> + <div class="col-sm-6"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %}"> + <label for="{# TODO #}" class="col-sm-4 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8"> + {{ field|add_class:'form-control' }} + </div> + + {% if field.errors %} + <span class="help-block"> + {{ field.errors }} + </span> + {% endif %} + </div> + {% endfor %} + </div> + </div><!-- /.box-body --> + + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">Add</button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.doctor_edit' doctor_id %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + </div> + {% endblock %} + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> + <script> + // If ever to debug and thinking why it doesn't work => look if there is 'null' in data from API + $.get("{% url 'web.api.specializations' %}", function (data) { + new Awesomplete(document.querySelector("#id_specialization")).list = data.specializations; + }); + $.get("{% url 'web.api.units' %}", function (data) { + new Awesomplete(document.querySelector("#id_unit")).list = data.units; + }); + </script> + + {% include "includes/datetimepicker.js.html" %} +{% endblock scripts %} diff --git a/smash/web/templates/doctors/availability_delete.html b/smash/web/templates/doctors/availability_delete.html deleted file mode 100644 index 64ee01760ab783c4e024d39d890e547e1db0b41a..0000000000000000000000000000000000000000 --- a/smash/web/templates/doctors/availability_delete.html +++ /dev/null @@ -1,252 +0,0 @@ -{% extends "_base.html" %} -{% load static %} - -{% block styles %} - {{ block.super }} - <!-- DataTables --> - <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> -{% endblock styles %} - -{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} -{% block page_header %}Workers{% endblock page_header %} -{% block page_description %}availability{% endblock page_description %} - -{% block breadcrumb %} - {% include "doctors/breadcrumb.html" %} -{% endblock breadcrumb %} - -{% block maincontent %} - - <div class="box-body"> - - <h3>Monday</h3> - {% if avmon %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <th>Remove</th> - </tr> - </thead> - <tbody> - {% for record in avmon %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Monday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - <h3>Tuesday</h3> - {% if avtue %} - <table id="tabtue" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avtue %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Tuesday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - <h3>Wednesday</h3> - {% if avwed %} - <table id="tabwed" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avwed %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Wednesday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - <h3>Thursday</h3> - {% if avthu %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avthu %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Thursday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - <h3>Friday</h3> - {% if avfri %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avfri %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Friday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - <h3>Saturday</h3> - {% if avsat %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <th>Remove</th> - </tr> - </thead> - <tbody> - {% for record in avsat %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - - {% else %} - <p>No availabilities on Saturday.</p> - {% endif %} - - <div> - <a href="{% url 'web.views.doctor_add' %}" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </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 () { - $('#table').DataTable({ - "paging": true, - "lengthChange": false, - "searching": false, - "ordering": true, - "info": true, - "autoWidth": false - }); - }); - </script> -{% endblock scripts %} diff --git a/smash/web/templates/doctors/availability_index.html b/smash/web/templates/doctors/availability_index.html deleted file mode 100644 index 9e09791f50552035e6d4f534189855cbddcbfd2c..0000000000000000000000000000000000000000 --- a/smash/web/templates/doctors/availability_index.html +++ /dev/null @@ -1,328 +0,0 @@ -{% extends "_base.html" %} -{% load static %} - -{% block styles %} - {{ block.super }} - <!-- DataTables --> - <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> -{% endblock styles %} - -{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} -{% block page_header %}Workers{% endblock page_header %} -{% block page_description %}availability{% endblock page_description %} - -{% block breadcrumb %} - {% include "doctors/breadcrumb.html" %} -{% endblock breadcrumb %} - -{% block maincontent %} - - <div class="box-body"> - <div class="box box-danger box-solid"> - <div class="box-header with-border"> - <h3 class="box-title">To be implemented</h3> - - <div class="box-tools center"> - <button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i> - </button> - </div> - <!-- /.box-tools --> - </div> - <!-- /.box-header --> - <div class="box-body"> - Currently only an overview of doctor's availibility is presented. - Changes to the schedules can be made only by the administrator in administrator's panel. - </div> - <!-- /.box-body --> - </div> - - <div> - <h3>Monday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avmon %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <th>Remove</th> - </tr> - </thead> - <tbody> - {% for record in avmon %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Monday.</p> - {% endif %} - </div> - - <hr/> - - <div> - <h3>Tuesday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avtue %} - <table id="tabtue" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avtue %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Tuesday.</p> - {% endif %} - </div> - - <hr/> - - <div> - <h3>Wednesday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avwed %} - <table id="tabwed" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avwed %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Wednesday.</p> - {% endif %} - </div> - - <hr/> - - <div> - <h3>Thursday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avthu %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avthu %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Thursday.</p> - {% endif %} - </div> - - <hr/> - - <div> - <h3>Friday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avfri %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <td> Remove</td> - </tr> - </thead> - <tbody> - {% for record in avfri %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Friday.</p> - {% endif %} - </div> - - <hr/> - - <div> - <h3>Saturday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avsat %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <th>Remove</th> - </tr> - </thead> - <tbody> - {% for record in avsat %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Saturday.</p> - {% endif %} - </div> - - <div> - <h3>Sunday</h3> - - <div class="new-availability"> - <a href="#" class="btn btn-app"> - <i class="fa fa-plus"></i> - Add new availability</a> - </div> - - {% if avsun %} - <table id="tabmon" class="table table-bordered table-striped"> - <thead> - <tr> - <th>No.</th> - <th>From</th> - <th>Until</th> - <th>Remove</th> - </tr> - </thead> - <tbody> - {% for record in avsun %} - <tr> - <td> {{ forloop.counter }} </td> - <td> {{ record.available_from }} </td> - <td> {{ record.available_till }} </td> - <td><a href="{% url 'web.views.doctor_availability_delete' id record.id %}" type="button" - class="btn btn-block btn-default">Delete</a></td> - </tr> - {% endfor %} - </tbody> - </table> - - {% else %} - <p>No availabilities on Sunday.</p> - {% endif %} - </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 () { - $('#table').DataTable({ - "paging": true, - "lengthChange": false, - "searching": false, - "ordering": true, - "info": true, - "autoWidth": false - }); - }); - </script> -{% endblock scripts %} diff --git a/smash/web/templates/doctors/details.html b/smash/web/templates/doctors/details.html deleted file mode 100644 index d9cb19ac5116130cad6ce47e68c376c7c17e8ee3..0000000000000000000000000000000000000000 --- a/smash/web/templates/doctors/details.html +++ /dev/null @@ -1,87 +0,0 @@ -{% extends "_base.html" %} -{% load static %} -{% load filters %} - -{% block styles %} - {{ block.super }} - <!-- DataTables --> - <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> -{% endblock styles %} - -{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} -{% block page_header %}Worker details{% endblock page_header %} -{% block page_description %}details{% endblock page_description %} - -{% block title %} - Details of worker{% endblock %} - -{% block breadcrumb %} - {% include "doctors/breadcrumb.html" %} -{% endblock breadcrumb %} - -{% block maincontent %} - - {% block content %} - <div class="box box-info"> - <div class="box-header with-border"> - <a href="{% url 'web.views.doctors' %}" class="btn btn-block btn-default" onclick="history.back()">Go - back</a> - </div> - - {% comment %} <div class="box-header with-border"> - <h3 class="box-title">Details of worker</h3> - </div>{% endcomment %} - - <form method="post" action="" class="form-horizontal"> - {% csrf_token %} - - <div class="box-body"> - {% for field in form %} - <div class="col-md-6 form-group {% if field.errors %}has-error{% endif %}"> - <label for="{# TODO #}" class="col-sm-4 control-label"> - {{ field.label }} - </label> - - <div class="col-sm-8"> - {{ field|disable|add_class:'form-control' }} - </div> - - {% if field.errors %} - <span class="help-block"> - {{ field.errors }} - </span> - {% endif %} - </div> - {% endfor %} - </div><!-- /.box-body --> - - <div class="box-footer"> - <a href="{% url 'web.views.doctors' %}" class="btn btn-block btn-default" onclick="history.back()">Go - back</a> - </div><!-- /.box-footer --> - </form> - </div> - {% endblock %} - - - - -{% 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 () { - $('#table').DataTable({ - "paging": true, - "lengthChange": false, - "searching": true, - "ordering": true, - "info": true, - "autoWidth": false - }); - }); - </script> -{% endblock scripts %} diff --git a/smash/web/templates/doctors/edit.html b/smash/web/templates/doctors/edit.html index c22db7cc4ad26bcc9889eb2b67261597f9eddf5f..241ad9eafc2164f92f9469c683f33624847ec0d1 100644 --- a/smash/web/templates/doctors/edit.html +++ b/smash/web/templates/doctors/edit.html @@ -27,10 +27,6 @@ back (without changes)</a> </div> - {% comment %} <div class="box-header with-border"> - <h3 class="box-title">Details of worker</h3> - </div>{% endcomment %} - <form method="post" action="" class="form-horizontal"> {% csrf_token %} @@ -47,8 +43,8 @@ {% if field.errors %} <span class="help-block"> - {{ field.errors }} - </span> + {{ field.errors }} + </span> {% endif %} </div> {% endfor %} @@ -67,6 +63,52 @@ </div> {% endblock %} + <div class="box-body"> + <table id="table" class="table table-bordered table-striped"> + <thead> + <tr> + <th>Day</th> + <th>From</th> + <th>Until</th> + <th>Modify</th> + <th>Remove</th> + </tr> + </thead> + <tbody> + {% for availability in availabilities %} + <tr> + <td> + {% for weekday in weekdays %} + {% if availability.day_number == weekday.0 %} + {{ weekday.1 }} + {% endif %} + {% endfor %} + </td> + <td>{{ availability.available_from }}</td> + <td>{{ availability.available_till }}</td> + <td> + <a href="{% url 'web.views.doctor_availability_edit' availability.id %}" type="button" + class="btn btn-block btn-default">Edit</a> + </td> + <td> + <a href="{% url 'web.views.doctor_availability_delete' availability.id %}" type="button" + class="btn btn-block btn-default">Delete</a> + </td> + </tr> + {% endfor %} + + </tbody> + </table> + + <div class="box-footer"> + <div class="col-sm-6"> + <a href="{% url 'views.doctor.doctor_availability_add' doctor_id %}" type="button" + class="btn btn-block btn-success">Add availability</a> + </div> + </div><!-- /.box-footer --> + + </div> + @@ -83,7 +125,7 @@ "paging": true, "lengthChange": false, "searching": true, - "ordering": true, + "ordering": false, "info": true, "autoWidth": false }); diff --git a/smash/web/templates/doctors/edit_availability.html b/smash/web/templates/doctors/edit_availability.html new file mode 100644 index 0000000000000000000000000000000000000000..37de10ae4cc064b45b0173ef53d7a80e43296227 --- /dev/null +++ b/smash/web/templates/doctors/edit_availability.html @@ -0,0 +1,75 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <!-- DataTables --> + {% include "includes/datetimepicker.css.html" %} +{% endblock styles %} + +{% block ui_active_tab %}'workers'{% endblock ui_active_tab %} +{% block page_header %}Edit availability{% endblock page_header %} +{% block page_description %}{% endblock page_description %} + +{% block title %} - Edit worker availability{% endblock %} + +{% block breadcrumb %} + {% include "doctors/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="box box-info"> + <div class="box-header with-border"> + <a href="{% url 'web.views.doctor_edit' doctor_id %}" class="btn btn-block btn-default">Go back (without + changes)</a> + </div> + + <form method="post" action="" class="form-horizontal"> + {% csrf_token %} + + <div class="box-body"> + <div class="col-sm-6"> + {% for field in form %} + <div class="form-group {% if field.errors %}has-error{% endif %}"> + <label for="{# TODO #}" class="col-sm-4 control-label"> + {{ field.label }} + </label> + + <div class="col-sm-8"> + {{ field|add_class:'form-control' }} + </div> + + {% if field.errors %} + <span class="help-block"> + {{ field.errors }} + </span> + {% endif %} + </div> + {% endfor %} + </div> + </div><!-- /.box-body --> + + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-success">Save</button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.doctor_edit' doctor_id %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + </div> + {% endblock %} + + + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + {% include "includes/datetimepicker.js.html" %} +{% endblock scripts %} diff --git a/smash/web/templates/doctors/index.html b/smash/web/templates/doctors/index.html index c8fc622133ffea7159da87900ea08e590b00c6ed..37c31f6dc2fb793ee1b49438c3f9593edbc00bc6 100644 --- a/smash/web/templates/doctors/index.html +++ b/smash/web/templates/doctors/index.html @@ -34,8 +34,6 @@ <th>Languages</th> <th>Unit</th> <th>Details</th> - <th>Edit</th> - <th>Availibility details</th> <th>On leave</th> </tr> </thead> @@ -53,12 +51,8 @@ {% endautoescape %} </td> <td>{{ worker.unit }}</td> - <td><a href="{% url 'web.views.doctor_details' worker.id %}" type="button" - class="btn btn-block btn-default">Details</a></td> <td><a href="{% url 'web.views.doctor_edit' worker.id %}" type="button" - class="btn btn-block btn-default">Edit</a></td> - <td><a href="{% url 'web.views.doctor_availability' worker.id %}" type="button" - class="btn btn-block btn-default">Modify availability</a></td> + class="btn btn-block btn-default">Details</a></td> <td> {% if worker.is_on_leave %} <button type="button" class="btn btn-block btn-danger">YES</button> diff --git a/smash/web/tests/test_AvailabilityAddForm.py b/smash/web/tests/test_AvailabilityAddForm.py new file mode 100644 index 0000000000000000000000000000000000000000..2f6b9b3568efaa9fffb8e2f910b3b9fd649f8a8b --- /dev/null +++ b/smash/web/tests/test_AvailabilityAddForm.py @@ -0,0 +1,48 @@ +from django.test import TestCase + +from functions import create_user, create_visit +from functions import get_test_location +from web.models.constants import MONDAY_AS_DAY_OF_WEEK +from web.forms import AvailabilityAddForm +from web.models import Worker + + +class AvailabilityAddFormTests(TestCase): + def setUp(self): + location = get_test_location() + self.user = create_user() + + worker = Worker.get_by_user(self.user) + worker.locations = [get_test_location()] + worker.save() + + self.visit = create_visit() + + self.sample_data = {'person': worker.id, + 'available_from': '8:00', + 'available_till': "9:00", + 'day_number': MONDAY_AS_DAY_OF_WEEK, + } + + def test_validation(self): + form = AvailabilityAddForm(data=self.sample_data) + self.assertTrue(form.is_valid()) + + def test_invalid(self): + form = AvailabilityAddForm(data=self.sample_data) + form.save() + form = AvailabilityAddForm(data=self.sample_data) + self.assertFalse(form.is_valid()) + + def test_complex_invalid(self): + form = AvailabilityAddForm(data=self.sample_data) + form.save() + self.sample_data["available_from"] = '10:00' + self.sample_data["available_till"] = '11:00' + form = AvailabilityAddForm(data=self.sample_data) + form.save() + + self.sample_data["available_from"] = '7:00' + self.sample_data["available_till"] = '20:00' + form = AvailabilityAddForm(data=self.sample_data) + self.assertFalse(form.is_valid()) diff --git a/smash/web/tests/test_AvailabilityEditForm.py b/smash/web/tests/test_AvailabilityEditForm.py new file mode 100644 index 0000000000000000000000000000000000000000..3f3a3c854bb60d8faa4072d24eaef7450660f6ec --- /dev/null +++ b/smash/web/tests/test_AvailabilityEditForm.py @@ -0,0 +1,31 @@ +from django.test import TestCase + +from functions import create_user, create_visit +from functions import get_test_location +from web.models.constants import MONDAY_AS_DAY_OF_WEEK +from web.forms import AvailabilityEditForm, AvailabilityAddForm +from web.models import Worker + + +class AvailabilityEditFormTests(TestCase): + def setUp(self): + location = get_test_location() + self.user = create_user() + + worker = Worker.get_by_user(self.user) + worker.locations = [get_test_location()] + worker.save() + + self.visit = create_visit() + + self.sample_data = {'person': worker.id, + 'available_from': '8:00', + 'available_till': "9:00", + 'day_number': MONDAY_AS_DAY_OF_WEEK, + } + form = AvailabilityAddForm(data=self.sample_data) + self.availability = form.save() + + def test_validation(self): + form = AvailabilityEditForm(instance=self.availability, data=self.sample_data) + self.assertTrue(form.is_valid()) diff --git a/smash/web/urls.py b/smash/web/urls.py index 9c50298a34d5ce746718a97beb8d5c379615048b..f23574d1e5748d82c9b9d679b19a5f2325f00b0d 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -89,13 +89,14 @@ urlpatterns = [ 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, + url(r'^doctors/availability/(?P<availability_id>\d+)/delete$', views.doctor.doctor_availability_delete, name='web.views.doctor_availability_delete'), + url(r'^doctors/availability/(?P<availability_id>\d+)/edit', views.doctor.doctor_availability_edit, + name='web.views.doctor_availability_edit'), + + url(r'^doctors/(?P<doctor_id>\d+)/availability/add$', views.doctor.doctor_availability_add, + name='views.doctor.doctor_availability_add'), #################### # EQUIPMENT # diff --git a/smash/web/views/doctor.py b/smash/web/views/doctor.py index 43a7465552e55183bf4104bc53c667b3f4e5876b..5e3a4f04f09ad6747a072e47c5a1895d5e27c830 100644 --- a/smash/web/views/doctor.py +++ b/smash/web/views/doctor.py @@ -2,10 +2,10 @@ from django.shortcuts import redirect, get_object_or_404 from . import wrap_response -from ..forms import WorkerAddForm, WorkerEditForm, WorkerDetailForm +from ..forms import WorkerAddForm, WorkerEditForm, AvailabilityAddForm, AvailabilityEditForm from ..models import Worker, Availability -from ..models.constants import MONDAY_AS_DAY_OF_WEEK, TUESDAY_AS_DAY_OF_WEEK, WEDNESDAY_AS_DAY_OF_WEEK, \ - THURSDAY_AS_DAY_OF_WEEK, FRIDAY_AS_DAY_OF_WEEK, SATURDAY_AS_DAY_OF_WEEK, SUNDAY_AS_DAY_OF_WEEK +from ..models.constants import WEEKDAY_CHOICES + def doctors(request): doctors_list = Worker.objects.order_by('-last_name') @@ -37,43 +37,54 @@ def doctor_edit(request, doctor_id): 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}) + availabilities = Availability.objects.filter(person=doctor_id).order_by('day_number', 'available_from'); + return wrap_response(request, 'doctors/edit.html', + { + 'form': form, + 'availabilities': availabilities, + 'doctor_id': doctor_id, + 'weekdays': WEEKDAY_CHOICES + }) -def doctor_availability(request, doctor_id): - availabilities = Availability.objects.filter(person=doctor_id) - - availability_on_monday = availabilities.filter(day_number=MONDAY_AS_DAY_OF_WEEK) - availability_on_tuesday = availabilities.filter(day_number=TUESDAY_AS_DAY_OF_WEEK) - availability_on_wednesday = availabilities.filter(day_number=WEDNESDAY_AS_DAY_OF_WEEK) - availability_on_thursday = availabilities.filter(day_number=THURSDAY_AS_DAY_OF_WEEK) - availability_on_friday = availabilities.filter(day_number=FRIDAY_AS_DAY_OF_WEEK) - availability_on_saturday = availabilities.filter(day_number=SATURDAY_AS_DAY_OF_WEEK) - availability_on_sunday = availabilities.filter(day_number=SUNDAY_AS_DAY_OF_WEEK) +def doctor_availability_delete(request, availability_id): + availability = Availability.objects.filter(id=availability_id) + doctor_id = availability[0].person.id + availability.delete() + return redirect(doctor_edit, doctor_id=doctor_id) - context = { - 'avmon': availability_on_monday, - 'avtue': availability_on_tuesday, - 'avwed': availability_on_wednesday, - 'avthu': availability_on_thursday, - 'avfri': availability_on_friday, - 'avsat': availability_on_saturday, - 'avsun': availability_on_sunday, - 'id': doctor_id - } - return wrap_response(request, "doctors/availability_index.html", context) +def doctor_availability_add(request, doctor_id): + doctors = Worker.objects.filter(id=doctor_id) + doctor = None + if len(doctors) > 0: + doctor = doctors[0] + if request.method == 'POST': + form = AvailabilityAddForm(request.POST, request.FILES) + if form.is_valid(): + form.save() + return redirect(doctor_edit, doctor_id=doctor_id) + else: + form = AvailabilityAddForm(initial={'person': doctor}) + return wrap_response(request, 'doctors/add_availability.html', + { + 'form': form, + 'doctor_id': doctor_id + }) -def doctor_availability_delete(request, doctor_id, availability_id): - availability = Availability.objects.filter(id=availability_id) - if len(availability) > 0: - availability.delete() - return redirect(doctor_availability, id=doctor_id) +def doctor_availability_edit(request, availability_id): + availability = get_object_or_404(Availability, id=availability_id) + if request.method == 'POST': + form = AvailabilityEditForm(request.POST, request.FILES, instance=availability) + if form.is_valid(): + form.save() + return redirect(doctor_edit, doctor_id=availability.person_id) + else: + form = AvailabilityEditForm(instance=availability) + return wrap_response(request, 'doctors/edit_availability.html', + { + 'form': form, + 'availability_id': availability_id, + 'doctor_id': availability.person_id, + })