diff --git a/ferry/migrations/0017_auto_20210202_1254.py b/ferry/migrations/0017_auto_20210202_1254.py new file mode 100644 index 00000000..ff6aa062 --- /dev/null +++ b/ferry/migrations/0017_auto_20210202_1254.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.17 on 2021-02-02 11:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ferry', '0016_auto_20160424_1526'), + ] + + operations = [ + migrations.AlterField( + model_name='ferrykv6messages', + name='status', + field=models.PositiveSmallIntegerField(choices=[(1, 'Gereed voor vertrek'), (5, 'Vertrokken'), (10, 'Aankomst')], default=0, verbose_name='Status'), + ), + ] diff --git a/ferry/models.py b/ferry/models.py index e1c3d1ec..461d0557 100644 --- a/ferry/models.py +++ b/ferry/models.py @@ -42,7 +42,7 @@ class Status(object): ARRIVED = 10 STATUS = ( - (Status.READY, _("Gereerd voor vertrek")), + (Status.READY, _("Gereed voor vertrek")), (Status.DEPARTED, _("Vertrokken")), (Status.ARRIVED, _("Aankomst")), ) diff --git a/openebs/form.py b/openebs/form.py index 247d532c..1840b722 100644 --- a/openebs/form.py +++ b/openebs/form.py @@ -7,8 +7,10 @@ import floppyforms.__future__ as forms from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ +from django.db.models import Q + from kv1.models import Kv1Stop -from openebs.models import Kv15Stopmessage, Kv15Scenario, Kv15ScenarioMessage, get_end_service +from openebs.models import Kv15Stopmessage, Kv15Scenario, Kv15ScenarioMessage, get_end_service, Kv15MessageStop from datetime import datetime log = logging.getLogger('openebs.forms') @@ -17,30 +19,32 @@ class Kv15StopMessageForm(forms.ModelForm): def clean(self): # TODO Move _all_ halte parsing here! - datetimevalidation = [] try: - datetime.strptime(self.data['messagestarttime'], "%d-%m-%Y %H:%M:%S") + starttime = datetime.strptime(self.data['messagestarttime'], "%d-%m-%Y %H:%M:%S") + if not is_aware(starttime): + starttime = make_aware(starttime) except: - datetimevalidation.append(_("Voer een geldige begintijd in (dd-mm-jjjj uu:mm:ss)")) - pass + datetimevalidation.append(_("Voer een geldige begintijd in (dd-mm-jjjj uu:mm:ss).")) try: endtime = datetime.strptime(self.data['messageendtime'], "%d-%m-%Y %H:%M:%S") if not is_aware(endtime): endtime = make_aware(endtime) except: - datetimevalidation.append(_("Voer een geldige eindtijd in (dd-mm-jjjj uu:mm:ss)")) - pass + datetimevalidation.append(_("Voer een geldige eindtijd in (dd-mm-jjjj uu:mm:ss).")) + validationerrors = [] if len(datetimevalidation) == 2: - raise ValidationError(_("Voer een geldige begin- en eindtijd in (dd-mm-jjjj uu:mm:ss)")) + validationerrors.append(ValidationError(_("Voer een geldige begin- en eindtijd in (dd-mm-jjjj uu:mm:ss)."))) elif len(datetimevalidation) == 1: - raise ValidationError(datetimevalidation[0]) + validationerrors.append(ValidationError(datetimevalidation[0])) current = datetime.now() if not is_aware(current): current = make_aware(current) + if current > endtime: + validationerrors.append(ValidationError(_("Eindtijd van bericht ligt in het verleden."))) valid_ids = [] nonvalid_ids = [] @@ -50,26 +54,41 @@ def clean(self): stop = Kv1Stop.find_stop(halte_split[0], halte_split[1]) if stop: valid_ids.append(stop.pk) + if starttime: + if 'messagetype' in self.data and self.data['messagetype'] != 'OVERRULE': + dataownercode = self.instance.dataownercode + if len(valid_ids) > 0: + msg_count = Kv15MessageStop.objects.filter(~Q(stopmessage__id=self.instance.id), + stopmessage__dataownercode=dataownercode, + stop__id=stop.pk, + stopmessage__messagestarttime__lte=starttime, + stopmessage__messageendtime__gte=starttime, + stopmessage__isdeleted=False).count() + if msg_count > 0: + validationerrors.append( + ValidationError(_("Halte heeft al een bericht voor deze begintijd."))) else: nonvalid_ids.append(halte) if len(nonvalid_ids) != 0: log.warning("Ongeldige haltes: %s" % ', '.join(nonvalid_ids)) if len(valid_ids) == 0 and len(nonvalid_ids) != 0: - raise ValidationError(_("Er werd geen geldige halte geselecteerd.")) + validationerrors.append(ValidationError(_("Er werd geen geldige halte geselecteerd."))) elif len(valid_ids) == 0: - raise ValidationError(_("Selecteer minimaal een halte.")) - elif current > endtime: - raise ValidationError(_("Eindtijd van bericht ligt in het verleden")) + validationerrors.append(ValidationError(_("Selecteer minimaal een halte."))) + + if len(validationerrors) != 0: + raise ValidationError(validationerrors) else: return self.cleaned_data def clean_messagecontent(self): - # Improve: Strip spaces from message - if ('messagecontent' not in self.cleaned_data or self.cleaned_data['messagecontent'] is None or len( - self.cleaned_data['messagecontent']) < 1) \ + if 'messagetype' not in self.cleaned_data: + raise ValidationError(_("Type bericht moet zijn ingevuld.")) + elif ('messagecontent' not in self.cleaned_data or self.cleaned_data['messagecontent'] is None or len( + self.cleaned_data['messagecontent'].strip()) < 1) \ and self.cleaned_data['messagetype'] != 'OVERRULE': - raise ValidationError(_("Bericht mag niet leeg zijn")) + raise ValidationError(_("Bericht mag niet leeg zijn.")) return self.cleaned_data['messagecontent'] class Meta(object): @@ -177,20 +196,24 @@ def clean(self): qry = Kv1Stop.objects.filter(kv15scenariostop__message__scenario=self.data['scenario'], pk__in=ids) if self.instance.pk is not None: # Exclude ourselves if we've been saved qry = qry.exclude(kv15scenariostop__message=self.instance.pk) - + validationerrors = [] if qry.count() > 0: # Check that this stop isn't already in a messages for this scenario. If not, write a nice message out = "" for stop in qry: out += "%s, " % stop.name - raise ValidationError(_("Halte(s) ' %s ' bestaan al voor dit scenario") % out) + validationerrors.append(ValidationError(_("Halte(s) ' %s ' bestaan al voor dit scenario.") % out)) elif len(ids) == 0: # Select at least one stop for a message - raise ValidationError(_("Selecteer minimaal een halte")) + validationerrors.append(ValidationError(_("Selecteer minimaal een halte."))) + if 'messagetype' not in self.cleaned_data: + validationerrors.append(ValidationError(_("Type bericht moet zijn ingevuld."))) elif ('messagecontent' not in self.cleaned_data or self.cleaned_data['messagecontent'] is None or len( self.cleaned_data['messagecontent'].strip()) == 0) \ and self.cleaned_data['messagetype'] != 'OVERRULE': - raise ValidationError(_("Bericht mag niet leeg zijn")) + validationerrors.append(ValidationError(_("Bericht mag niet leeg zijn."))) + if len(validationerrors) != 0: + raise ValidationError(validationerrors) else: return self.cleaned_data @@ -274,8 +297,27 @@ def clean(self): if 'messageendtime' not in data: raise ValidationError(_("Voer een geldige eindtijd in")) + datetimevalidation = [] + try: + datetime.strptime(self.data['messagestarttime'], "%d-%m-%Y %H:%M:%S") + except: + datetimevalidation.append(_("Voer een geldige begintijd in (dd-mm-jjjj uu:mm:ss)")) + pass + + try: + datetime.strptime(self.data['messageendtime'], "%d-%m-%Y %H:%M:%S") + except: + datetimevalidation.append(_("Voer een geldige eindtijd in (dd-mm-jjjj uu:mm:ss)")) + pass + + if len(datetimevalidation) == 2: + raise ValidationError(_("Voer een geldige begin- en eindtijd in (dd-mm-jjjj uu:mm:ss)")) + elif len(datetimevalidation) == 1: + raise ValidationError(datetimevalidation[0]) + if data['messageendtime'] <= data['messagestarttime']: raise ValidationError(_("Einde bericht moet na begin zijn")) + return data def __init__(self, *args, **kwargs): diff --git a/openebs/form_kv17.py b/openebs/form_kv17.py index a9386f25..bd469f9a 100644 --- a/openebs/form_kv17.py +++ b/openebs/form_kv17.py @@ -13,7 +13,7 @@ from django.utils.dateparse import parse_date from datetime import datetime, timedelta, time from django.db.models import Q -from django.utils.timezone import make_aware, utc +from django.utils.timezone import make_aware log = logging.getLogger('openebs.forms') @@ -36,11 +36,12 @@ class Kv17ChangeForm(forms.ModelForm): def clean(self): cleaned_data = super(Kv17ChangeForm, self).clean() operatingday = parse_date(self.data['operatingday']) + validationerrors = [] if operatingday is None: - raise ValidationError(_("Er staan geen ritten in de database")) + validationerrors.append(ValidationError(_("Er staan geen ritten in de database"))) if 'journeys' not in self.data: - raise ValidationError(_("Een of meer geselecteerde ritten zijn ongeldig")) + validationerrors.append(ValidationError(_("Een of meer geselecteerde ritten zijn ongeldig"))) if self.data['begintime_part'] != '': hh, mm = self.data['begintime_part'].split(':') @@ -55,52 +56,48 @@ def clean(self): if begintime > endtime: # if endtime before begintime endtime = endtime + timedelta(days=1) # endtime is next day if endtime.time() >= time(6, 0): # and after 6 am: validation error - raise ValidationError(_("Eindtijd valt op volgende operationele dag")) + validationerrors.append(ValidationError(_("Eindtijd valt op volgende operationele dag"))) else: endtime = None dataownercode = self.user.userprofile.company if 'Alle ritten' in self.data['journeys']: - valid_journeys = self.clean_all_journeys(operatingday, dataownercode, begintime, endtime) + validationerrors = self.clean_all_journeys(operatingday, dataownercode, begintime, endtime, validationerrors) elif 'Hele vervoerder' in self.data['lines']: - valid_journeys = self.clean_all_lines(operatingday, dataownercode, begintime, endtime) + validationerrors = self.clean_all_lines(operatingday, dataownercode, begintime, endtime, validationerrors) else: - valid_journeys = self.clean_journeys(operatingday, dataownercode) + validationerrors = self.clean_journeys(operatingday, dataownercode, validationerrors) - if valid_journeys == 0: - raise ValidationError(_("Er zijn geen ritten geselecteerd om op te heffen")) - - return cleaned_data + if len(validationerrors) != 0: + raise ValidationError(validationerrors) + else: + return cleaned_data - def clean_journeys(self, operatingday, dataownercode): - valid_journeys = 0 + def clean_journeys(self, operatingday, dataownercode, validationerrors): if self.data['journeys'] != '': for journey in self.data['journeys'].split(',')[0:-1]: - journey_qry = Kv1Journey.objects.filter(dataownercode=dataownercode, pk=journey, dates__date=operatingday) + journey_qry = Kv1Journey.objects.filter(dataownercode=dataownercode, pk=journey, + dates__date=operatingday) if journey_qry.count() == 0: - raise ValidationError(_("Een of meer geselecteerde ritten zijn ongeldig")) + validationerrors.append(ValidationError(_("Een of meer geselecteerde ritten zijn ongeldig"))) # delete recovered if query is the same. Kv17Change.objects.filter(dataownercode=dataownercode, journey__pk=journey, line=journey_qry[0].line, operatingday=operatingday, is_recovered=True).delete() else: - raise ValidationError(_("Er werd geen rit geselecteerd.")) - - valid_journeys += 1 - - return valid_journeys + validationerrors.append(ValidationError(_("Er werd geen rit geselecteerd."))) - def clean_all_journeys(self, operatingday, dataownercode, begintime, endtime): - valid_journeys = 0 + return validationerrors + def clean_all_journeys(self, operatingday, dataownercode, begintime, endtime, validationerrors): if 'lines' in self.data: if self.data['lines'] != '': for line in self.data['lines'].split(',')[0:-1]: line_qry = Kv1Line.objects.filter(pk=line) if line_qry.count() == 0: - raise ValidationError(_("Geen lijn gevonden.")) + validationerrors.append(ValidationError(_("Er werd geen lijn gevonden in de database."))) database_alljourneys = Kv17Change.objects.filter(dataownercode=dataownercode, is_alljourneysofline=True, line=line_qry[0], @@ -124,24 +121,20 @@ def clean_all_journeys(self, operatingday, dataownercode, begintime, endtime): if database_alllines: if database_alllines.filter(Q(endtime__gt=begintime) | Q(endtime=None), Q(begintime__lte=begintime) | Q(begintime=None)): - raise ValidationError(_( - "De gehele vervoerder is al aangepast voor de aangegeven ingangstijd.")) + validationerrors.append(ValidationError(_( + "De gehele vervoerder is al aangepast voor de aangegeven ingangstijd."))) elif database_alljourneys: if database_alljourneys.filter(Q(endtime__gt=begintime) | Q(endtime=None), Q(begintime__lte=begintime) | Q(begintime=None)): - raise ValidationError(_( - "Een of meer geselecteerde lijnen zijn al aangepast voor de aangegeven ingangstijd.")) + validationerrors.append(ValidationError(_( + "Een of meer geselecteerde lijnen zijn al aangepast voor de aangegeven ingangstijd."))) else: - raise ValidationError(_("Geen geldige lijn geselecteerd")) + validationerrors.append(ValidationError(_("Geen geldige lijn geselecteerd"))) - valid_journeys += 1 - - return valid_journeys - - def clean_all_lines(self, operatingday, dataownercode, begintime, endtime): - valid_journeys = 0 + return validationerrors + def clean_all_lines(self, operatingday, dataownercode, begintime, endtime, validationerrors): database_alllines = Kv17Change.objects.filter(dataownercode=dataownercode, is_alllines=True, operatingday=operatingday, is_recovered=False) @@ -158,11 +151,9 @@ def clean_all_lines(self, operatingday, dataownercode, begintime, endtime): if database_alllines.filter(Q(endtime__gt=begintime) | Q(endtime=None), Q(begintime__lte=begintime) | Q(begintime=None)): - raise ValidationError(_("De ingangstijd valt al binnen een geplande operatie.")) - - valid_journeys += 1 + validationerrors.append(ValidationError(_("De ingangstijd valt al binnen een geplande operatie."))) - return valid_journeys + return validationerrors def save(self, force_insert=False, force_update=False, commit=True): ''' Save each of the journeys in the model. This is a disaster, we return the XML diff --git a/openebs/models.py b/openebs/models.py index 2a38b6ac..bf68dda7 100644 --- a/openebs/models.py +++ b/openebs/models.py @@ -148,7 +148,7 @@ class Meta(object): def __str__(self): message = self.messagecontent - if message == "": + if not message or len(message.strip()) == 0: message = _("") return "%s|%s#%s : %s" % (self.dataownercode, self.messagecodedate, self.messagecodenumber, message) @@ -370,7 +370,7 @@ class Kv15ScenarioMessage(models.Model): def __str__(self): message = self.messagecontent - if message == "": + if not message or len(message.strip()) == 0: message = _("") return "%s : %s" % (self.scenario.name, message) diff --git a/openebs/templates/openebs/kv15scenariomessage_form.html b/openebs/templates/openebs/kv15scenariomessage_form.html index 539e1864..32a0eabd 100644 --- a/openebs/templates/openebs/kv15scenariomessage_form.html +++ b/openebs/templates/openebs/kv15scenariomessage_form.html @@ -24,11 +24,13 @@

{% trans "Bericht" %}

+ +
{% crispy form form.helper %}
-
- +
+
diff --git a/openebs/templates/openebs/kv15scenariomessage_update.html b/openebs/templates/openebs/kv15scenariomessage_update.html index e2735d2c..1af8dab5 100644 --- a/openebs/templates/openebs/kv15scenariomessage_update.html +++ b/openebs/templates/openebs/kv15scenariomessage_update.html @@ -24,12 +24,13 @@

Bericht

+
{% csrf_token %} {% crispy form form.helper %}
- +
diff --git a/openebs/templates/openebs/kv15stopmessage_form.html b/openebs/templates/openebs/kv15stopmessage_form.html index dbc9a27d..dd0c1f8f 100644 --- a/openebs/templates/openebs/kv15stopmessage_form.html +++ b/openebs/templates/openebs/kv15stopmessage_form.html @@ -9,7 +9,7 @@

{% trans "Bericht" %}

-
+

{% if prefilled_stop %} @@ -29,11 +29,13 @@

{% trans "Bericht" %}

value="{% for halte in object.kv15messagestop_set.all %}{{ halte.stop.dataownercode }}_{{ halte.stop.userstopcode }},{% endfor %}" /> {% endif %}
+ +
{% crispy form form.helper %}
-
- +
+
diff --git a/openebs/templates/openebs/kv15stopmessage_update.html b/openebs/templates/openebs/kv15stopmessage_update.html index 9aebe220..be42fc5f 100644 --- a/openebs/templates/openebs/kv15stopmessage_update.html +++ b/openebs/templates/openebs/kv15stopmessage_update.html @@ -9,7 +9,7 @@

{% trans "Bewerk bericht" %}

-
+

{% if object.kv15messagestop_set.count > 0 %} @@ -23,6 +23,7 @@

{% trans "Bewerk bericht" %}

+
{% csrf_token %} {% crispy form form.helper %} @@ -33,7 +34,7 @@

{% trans "Bewerk bericht" %}

- +
diff --git a/openebs/templates/openebs/kv17change_form.html b/openebs/templates/openebs/kv17change_form.html index 84182374..dcfb2357 100644 --- a/openebs/templates/openebs/kv17change_form.html +++ b/openebs/templates/openebs/kv17change_form.html @@ -64,7 +64,7 @@

{% trans "Ritaanpassing" %}

- diff --git a/openebs/templates/openebs/snippet_halte-picker-js.html b/openebs/templates/openebs/snippet_halte-picker-js.html index 9ac50f68..579087c7 100644 --- a/openebs/templates/openebs/snippet_halte-picker-js.html +++ b/openebs/templates/openebs/snippet_halte-picker-js.html @@ -19,8 +19,9 @@ $('body').on('click', '#id_messagestarttime,#id_messageendtime', function() { $(this).select(); }); -$('body').on('blur', '#id_messagestarttime,#id_messageendtime', calculateTime); -$('body').on('blur', '#id_messagestarttime,#id_messageendtime', checkMessageTime); +$('body').on('change', '#id_messagestarttime,#id_messageendtime', calculateTime); +$('body').on('change', '#id_messagestarttime,#id_messageendtime', checkMessageTime); +$('body').on('change', '#id_messagestarttime,#id_messageendtime', showStopsOnChange); $('body').on('change', '#id_messagedurationtype_1', function() { hideEndTime(); }); diff --git a/openebs/templates/openebs/snippet_message-duration_small.html b/openebs/templates/openebs/snippet_message-duration_small.html index 2a513cc9..b78059f9 100644 --- a/openebs/templates/openebs/snippet_message-duration_small.html +++ b/openebs/templates/openebs/snippet_message-duration_small.html @@ -1,5 +1,9 @@ {% load i18n %} -{{ msg.messagestarttime|date:"H:i" }} - +{% if msg.is_future %} + {{ msg.messagestarttime|date:"d-m-Y H:i" }} - +{% else %} + {{ msg.messagestarttime|date:"H:i" }} - +{% endif %} {% if msg.get_message_duration == 0 %} {{ msg.messageendtime|date:"H:i" }} {% elif msg.get_message_duration == 1 %} diff --git a/openebs/views.py b/openebs/views.py index ca1f98a8..7d0f74ee 100644 --- a/openebs/views.py +++ b/openebs/views.py @@ -1,6 +1,6 @@ # Create your views here. import logging -from datetime import timedelta +from datetime import timedelta, datetime from django.contrib.gis.db.models import Extent from django.urls import reverse_lazy @@ -8,7 +8,7 @@ from django.shortcuts import redirect from django.views.generic import ListView, UpdateView, DetailView from django.views.generic.edit import CreateView, DeleteView -from django.utils.timezone import now +from django.utils.timezone import now, is_aware, make_aware from djgeojson.views import GeoJSONLayerView @@ -16,7 +16,7 @@ from openebs.views_push import Kv15PushMixin from openebs.views_utils import FilterDataownerMixin from utils.client import get_client_ip -from utils.views import JSONListResponseMixin, AccessMixin, AccessJsonMixin +from utils.views import JSONListResponseMixin, AccessMixin, AccessJsonMixin, JsonableResponseMixin from openebs.models import Kv15Stopmessage, Kv15Log, MessageStatus, Kv1StopFilter from openebs.form import Kv15StopMessageForm @@ -73,7 +73,7 @@ def is_view_all(self): (not user.is_superuser and (user.has_perm("openebs.view_all") or user.has_perm("openebs.edit_all"))) -class MessageCreateView(AccessMixin, Kv15PushMixin, CreateView): +class MessageCreateView(JsonableResponseMixin, AccessMixin, Kv15PushMixin, CreateView): permission_required = 'openebs.add_messages' model = Kv15Stopmessage form_class = Kv15StopMessageForm @@ -121,7 +121,7 @@ def form_valid(self, form): return ret -class MessageUpdateView(AccessMixin, Kv15PushMixin, FilterDataownerMixin, UpdateView): +class MessageUpdateView(JsonableResponseMixin, AccessMixin, Kv15PushMixin, FilterDataownerMixin, UpdateView): permission_required = 'openebs.add_messages' permission_level = 'write' model = Kv15Stopmessage @@ -225,13 +225,22 @@ class ActiveStopsAjaxView(AccessJsonMixin, JSONListResponseMixin, DetailView): def get_object(self, **kwargs): # Note, can't set this on the view, because it triggers the queryset cache - queryset = self.model.objects.filter(messages__stopmessage__messagestarttime__lte=now(), - messages__stopmessage__messageendtime__gte=now(), + queryset = self.model.objects.filter(#messages__stopmessage__messagestarttime__lte=now(), + Q(messages__stopmessage__messageendtime__gte=now()) | + Q(messages__stopmessage__messageendtime=None), messages__stopmessage__isdeleted=False, # These two are double, but just in case messages__stopmessage__dataownercode=self.request.user.userprofile.company, dataownercode=self.request.user.userprofile.company).distinct() - return list(queryset.values('dataownercode', 'userstopcode')) + return list({'message_id': x['messages__stopmessage__id'], 'dataownercode': x['dataownercode'], + 'userstopcode': x['userstopcode'], + 'starttime': int(x['messages__stopmessage__messagestarttime'].timestamp()), + 'endtime': int(x['messages__stopmessage__messageendtime'].timestamp()) if + x['messages__stopmessage__messageendtime'] is not None else None, + 'message': x['messages__stopmessage__messagecontent']} for x in + queryset.values('messages__stopmessage__id', 'dataownercode', 'userstopcode', + 'messages__stopmessage__messagestarttime', 'messages__stopmessage__messageendtime', + 'messages__stopmessage__messagecontent')) class MessageStopsAjaxView(AccessJsonMixin, GeoJSONLayerView): diff --git a/openebs/views_change.py b/openebs/views_change.py index 258c5c2e..e55242f2 100644 --- a/openebs/views_change.py +++ b/openebs/views_change.py @@ -10,10 +10,11 @@ from openebs.views_push import Kv17PushMixin from openebs.views_utils import FilterDataownerMixin from utils.time import get_operator_date, get_operator_date_aware -from utils.views import AccessMixin, JSONListResponseMixin, AccessJsonMixin +from utils.views import AccessMixin, JSONListResponseMixin, AccessJsonMixin, JsonableResponseMixin from django.utils.dateparse import parse_date from django.utils.timezone import now + log = logging.getLogger('openebs.views.changes') @@ -51,7 +52,7 @@ def get_context_data(self, **kwargs): return context -class ChangeCreateView(AccessMixin, Kv17PushMixin, CreateView): +class ChangeCreateView(JsonableResponseMixin, AccessMixin, Kv17PushMixin, CreateView): permission_required = 'openebs.add_change' model = Kv17Change form_class = Kv17ChangeForm @@ -79,7 +80,7 @@ def add_journeys_from_request(self, data): journey_errors = 0 journeys = [] for journey in self.request.GET['journey'].split(','): - if journey == "": + if len(journey.strip()) == 0: continue log.info("Finding journey %s for '%s'" % (journey, self.request.user)) j = Kv1Journey.find_from_realtime(self.request.user.userprofile.company, journey) diff --git a/openebs2/static/css/site.css b/openebs2/static/css/site.css index eecad047..e31f873f 100644 --- a/openebs2/static/css/site.css +++ b/openebs2/static/css/site.css @@ -232,3 +232,14 @@ span.stop-selection,span.trip-selection{ margin-bottom: 15px; } +.msg_warning { + background-color: #fcf8e3; +} + +.error-label label { + color: #a94442; +} + +.stop_warning { + background-color: #f67f7f; +} \ No newline at end of file diff --git a/openebs2/static/js/add_msg.js b/openebs2/static/js/add_msg.js index e89296c9..f03251f7 100644 --- a/openebs2/static/js/add_msg.js +++ b/openebs2/static/js/add_msg.js @@ -2,6 +2,8 @@ var selectedStops = [] var scenarioStops = [] var blockedStops = [] /* Already have messages set */ +var messageData = [] /* all info from blocked stops */ +var activeLine = null /* lineplanningnumber */ function changeSearch(event) { if ($("#line_search").val().length > 0) { @@ -31,9 +33,11 @@ function writeList(data, status) { $.each(data.object_list, function (i, line) { validIds.push('l'+line.pk) if (!$('#l'+line.pk).length) { - row = ''+line.publiclinenumber+ ''; - row += ''+line.headsign+''; - $(row).hide().appendTo("#rows").fadeIn(200); + if (line.publiclinenumber) { // not all lines with a lineplanningnumber has a publiclinenumber or headsign + row = ''+line.publiclinenumber+ ''; + row += ''+line.headsign+''; + $(row).hide().appendTo("#rows").fadeIn(200); + } } }); @@ -56,14 +60,18 @@ function showStops(event) { } function selectStop(event, ui) { - $('#halte-list .help').remove() + var stop_id = $(ui.selected).attr('id').slice(1,-1); + if ($.inArray(stop_id, blockedStops) != -1 & $('#id_messagetype_3').parent().hasClass('active') === false) { // if blocked and no OVERRULE + return + } if (doSelectStop(ui.selected)) { + $('#halte-list .help').addClass('hidden'); writeHaltesField(); } } function selectStopFromBall(obj) { - $('#halte-list .help').remove() + $('#halte-list .help').addClass('hidden'); var did = false var parent = $(this).parents('.stopRow'); var left = $(parent).find(".stop-left"); @@ -83,6 +91,7 @@ function selectStopFromBall(obj) { } function selectAllVisibleStops() { + $('#halte-list .help').addClass('hidden'); $('#stops .stop').each(function(index, value) { /* Check this is not already selected */ index = $(this).attr('id').slice(0, -1); @@ -164,6 +173,9 @@ function removeStop(id) { $("#s"+id).remove(); $("#"+id+"l, #"+id+"r").removeClass('success') $("#"+id+"l .stop-check, #"+id+"r .stop-check").remove() + if (selectedStops.length == 0) { + $('#halte-list .help').removeClass('hidden'); + } writeHaltesField() } } @@ -171,6 +183,8 @@ function removeStop(id) { function writeLine(data, status) { $('#stops').fadeOut(100).empty(); out = "" + blockedStops = []; + $.each(data.object.stop_map, function (i, stop) { out += renderRow(stop) }); @@ -180,6 +194,21 @@ function writeLine(data, status) { } function renderRow(row) { + var pathname = window.location.pathname; + if (pathname.indexOf('scenario') == -1) { + var currentStopMeasures = []; + var messagestarttime = epoch(parseDate($('#id_messagestarttime').val())); + var messageendtime = epoch(parseDate($('#id_messageendtime').val())); + + messageData.filter(measure => { + if (measure.starttime <= messagestarttime) { + if (measure.endtime >= messagestarttime || measure.endtime === null) { + stop = measure.dataownercode + '_' + measure.userstopcode; + currentStopMeasures.push([stop, measure.starttime, measure.endtime, measure.message]); + } + } + }); + } out = ''; if (row.left != null) { if ($.inArray(row.left.id, scenarioStops) != -1) { @@ -189,11 +218,22 @@ function renderRow(row) { if ($.inArray('s'+row.left.id, selectedStops) != -1) { out += ''+row.left.name+' ' } else { - out += ''+row.left.name; - if ($.inArray(row.left.id, blockedStops) != -1) { - out += '' + var pathname = window.location.pathname; + if (pathname.indexOf('scenario') == -1) { + var selected = currentStopMeasures.filter(message => message[0] === row.left.id); + out += ''+row.left.name; + if (selected.length > 0) { + out += ''; + blockedStops.push(row.left.id); + } + out += ''; + } else { + out += ''+row.left.name; + if ($.inArray(row.left.id, blockedStops) != -1) { + out += '' + } + out += ''; } - out += ''; } } } else { @@ -214,11 +254,23 @@ function renderRow(row) { if ($.inArray('s'+row.right.id, selectedStops) != -1) { out += ''+row.right.name+' '; } else { - out += ''+row.right.name; - if ($.inArray(row.right.id, blockedStops) != -1) { - out += '' + var pathname = window.location.pathname; + if (pathname.indexOf('scenario') == -1) { + var selected = currentStopMeasures.filter(message => message[0] === row.right.id); + out += ''+row.right.name; + + if (selected.length > 0) { + out += '' + blockedStops.push(row.right.id); + } + out += ''; + } else { + out += ''+row.right.name; + if ($.inArray(row.right.id, blockedStops) != -1) { + out += '' + } + out += ''; } - out += ''; } } } else { @@ -245,29 +297,136 @@ function writeScenarioStops(data, status) { function getHaltesWithMessages() { $.ajax('/bericht/haltes.json', { - success : writeHaltesWithMessages - }) + success : function(data) { + messageData = data.object; + } + }); } -function writeHaltesWithMessages(data, status) { - $.each(data.object, function (i, halte) { - stop = halte['dataownercode']+ '_' + halte['userstopcode'] - blockedStops.push(stop) - }); +function formValidation() { + var pathname = window.location.pathname; + var validationdata = $('.form').serializeArray().reduce(function(obj, item) { + obj[item.name] = item.value; + return obj; + }, {}); + validationdata['csrfmiddlewaretoken'] = document.getElementsByName('csrfmiddlewaretoken')[0].value; + + $.ajax({url: pathname, + data: validationdata, + method: 'POST', + success : function(result) { + if (pathname.indexOf('scenario') !== -1) { + var base_href = pathname.split('bericht')[0]; + window.location.href = base_href + 'bewerk'; + } else { + window.location.href = '/bericht'; + } + }, + error: function(result) { + var response = result.responseJSON; + if (!$("#error_list").hasClass('hidden')) { + $("#error_list").empty(); + $(".has-error").removeClass('has-error'); + $(".error-label").removeClass('error-label'); + } + $.each(response, function(field, errorlist) { + $.each(errorlist, function(idx, error) { + $("#error_list").append('

'+error+'

'); + error = error.toLowerCase(); + if (error.indexOf('begin') !== -1) { + $('#div_id_messagestarttime').addClass('has-error'); + } + if (error.indexOf('eind') !== -1) { + $('#div_id_messageendtime').addClass('has-error'); + } else if (error.indexOf('type') !== -1) { + $('#div_id_messagetype').addClass('has-error'); + } + + if (error.indexOf('halte') !== -1) { + $('#div_id_haltes').addClass('error-label'); + } else if (error.indexOf('bericht') !== -1) { + $('#div_id_messagecontent').addClass('has-error'); + } + + }); + }); + if ($("#error_list").hasClass('hidden')) { + $("#error_list").removeClass('hidden'); + } + } + }); +} + +function showStopsOnChange() { + $('.stopRow span').remove(); + if (!$("#error_list").hasClass('hidden')) { + $("#error_list").empty(); + $("#error_list").addClass('hidden'); + $('[id^=ss'+stop+']').removeClass('stop_warning'); + $('#div_id_haltes').addClass('error-label'); + } + blockedStops = []; + if (messageData.length > 0) { + const filtered_messagedata = messageData.filter(message => { + start_epoch = epoch(parseDate($('#id_messagestarttime').val())); + end_epoch = epoch(parseDate($('#id_messageendtime').val())); + if (message.starttime <= start_epoch) { + if (message.endtime >= start_epoch || message.endtime === null) { + return true + } + } + }); + if (window.location.pathname.indexOf('bewerken') !== -1 && window.location.pathname.indexOf('scenario') === -1) { // remove current message_id from current when updating message + var current_id = window.location.pathname.split('/')[2]; + var filtered = filtered_messagedata.filter(message => { + if (message.message_id != current_id) { + return true + } + }); + } else { + var filtered = filtered_messagedata; + } + + var stops = []; + if (filtered.length > 0) { + filtered.filter(message => { + if ($.inArray(message.userstopcode, stops) == -1) { + stops.push(message.userstopcode); + blockedStops.push(message.dataownercode+"_"+message.userstopcode); + } + }); + + $.each(blockedStops, function(i, stop) { + $('[id^=s'+stop+']').append(''); + if ($.inArray('s'+stop, selectedStops) !== -1) { + $('[id^=ss'+stop+']').addClass('stop_warning'); + $('[id^=s'+stop+']').addClass('stop_warning'); + $('#div_id_haltes').addClass('error-label'); + $("#error_list").append('

Halte heeft al een bericht voor deze begintijd

'); + $("#error_list").removeClass('hidden'); + } + }); + } + } + $('.stopRow td.success').append(' '); + writeHaltesField(); + } /* TIME FUNCTIONS */ function checkMessageTime(event, ui) { var starttime = parseDate($("#id_messagestarttime").val()); var endtime = parseDate($("#id_messageendtime").val()); - - if (starttime >= endtime) { - if ($(this).attr('id') == "id_messagestarttime") { - endtime.setDate(endtime.getDate()+1); - $("#id_messageendtime").val(formatDate(endtime)); - } else { - starttime.setDate(endtime.getDate()-1); - $("#id_messagestarttime").val(formatDate(starttime)); + if (starttime != 'Invalid Date') { + if (starttime >= endtime) { + var new_endtime = starttime; + if ($(this).attr('id') == "id_messagestarttime") { + new_endtime.setDate(new_endtime.getDate()+1); + $("#id_messageendtime").val(formatDate(new_endtime)); + } else { + starttime.setDate(endtime.getDate()-1); + $("#id_messagestarttime").val(formatDate(starttime)); + } } } } @@ -348,10 +507,21 @@ function hideEndTime() { } function showEndTime() { - $('#div_id_messageendtime').show(); - var enddate = new Date(); - enddate.setHours(3, 0, 0); - enddate.setDate(enddate.getDate()+1); - $('#id_messageendtime').val(formatDate(enddate)); + $('#div_id_messageendtime').show(); + var enddate = new Date(); + enddate.setHours(3, 0, 0); + + var startdate = parseDate($('#id_messagestarttime').val()); + if (startdate != 'Invalid Date') { + var new_enddate = startdate; + new_enddate.setDate(new_enddate.getDate()+1); + $("#id_messageendtime").val(formatDate(new_enddate)); + } else { + enddate.setDate(enddate.getDate()+1); + $('#id_messageendtime').val(formatDate(enddate)); + } +} -} \ No newline at end of file +function epoch(date) { + return Date.parse(date) / 1000; +} diff --git a/openebs2/static/js/add_msg_journey.js b/openebs2/static/js/add_msg_journey.js index 215ce2e3..2ee62a22 100644 --- a/openebs2/static/js/add_msg_journey.js +++ b/openebs2/static/js/add_msg_journey.js @@ -154,7 +154,9 @@ function writeTrips(data, status) { tripSelection = data.object.trips_1.concat(data.object.trips_2); maxLen = Math.max(data.object.trips_1.length, data.object.trips_2.length); if (maxLen > 0) { - $('#trips tbody').fadeOut(100).empty(); + $('#trips tbody').fadeOut(100); + $('#trips tbody').text(""); + $('#trips tr').not('.help').remove(); tripRows = null; for (i = 0; i <= maxLen; i = i + 1) { a = null; @@ -168,6 +170,7 @@ function writeTrips(data, status) { $('#trips tbody').hide().append(tripRows); $('#trips thead').fadeIn(200); $('#trips tbody').fadeIn(200); + $('#trips tr.help').hide(); $("#all_journeys").removeAttr('disabled'); } else { $('#trips thead').hide(); @@ -208,20 +211,19 @@ function renderTripCell(trip) { } }); - if ($.inArray(trip.id, activeJourneys) != -1) { - out = ''; - } else if (currentTripMeasures.length > 0) { + if (currentTripMeasures.length > 0) { out = ''; + } else if ($.inArray(trip.id, activeJourneys) != -1) { + out = ''; } else { out = ''; } out += "Rit "+trip.journeynumber+""; out += " Vertrek "+convertSecondsToTime(trip.departuretime)+""; - if ($.inArray(trip.id, activeJourneys) != -1) { - out += ''; - } if (currentTripMeasures.length > 0) { out += ''; + } else if ($.inArray(trip.id, activeJourneys) != -1) { + out += ''; } out += ""; return out; @@ -361,7 +363,6 @@ function emptyLineList() { $("#lijn-list").empty(); $("#lines").val(''); selectedLines = []; - cancelledLines = []; currentLineMeasures = []; $('#lijn-list span').remove(); $('.lijn-overzicht').css("display","none"); @@ -375,6 +376,7 @@ function removeLineFromX(event, ui) { $('#rit-list .help').show(); $('#trips thead').show(); $('#trips tbody').show(); + $('#trips tr.help').show(); } else { lijnnr =$(this).parent().attr('id').replace('st', ''); //remove from selectTripMeasures & allTrips @@ -402,6 +404,10 @@ function removeLineFromX(event, ui) { removeLine($(this).parent().attr('id').substring(2)); colorSelectedRange(); } + if ($('#lines').val().length == 0) { + $('#div_id_begintime_part').addClass('hidden'); + $('#div_id_endtime_part').addClass('hidden'); + } } function removeLine(lijn) { @@ -447,7 +453,7 @@ function selectAllLines() { $('#div_id_begintime_part').removeClass('hidden'); $('#div_id_endtime_part').removeClass('hidden'); } - $('#trips tbody tr').remove(); + $('#trips tr').not('.help').remove(); $('.rit-overzicht').css("display","none"); $('#trips thead').hide(); $('#trips tbody').hide(); @@ -484,6 +490,9 @@ function colorSelectedRange() { var end_hour = parseInt($('#id_endtime_part').val().split(':')[0])*3600; var end_minutes = parseInt($('#id_endtime_part').val().split(':')[1])*60; selection_endtime = end_hour+end_minutes; + if ($('#id_begintime_part').val().length !=0 && selection_endtime < selection_begintime) { + selection_endtime += 24*3600; + } }; selectTripMeasures = []; @@ -527,6 +536,48 @@ function changeOfRange() { colorSelectedRange(); } +function formValidation() { + var validationdata = $('.form').serializeArray().reduce(function(obj, item) { + obj[item.name] = item.value; + return obj; + }, {}); + validationdata['csrfmiddlewaretoken'] = document.getElementsByName('csrfmiddlewaretoken')[0].value; + + $.ajax({url: window.location.pathname, + data: validationdata, + method: 'POST', + success : function(result) { + window.location.href = '/ritaanpassing'; + }, + error: function(result) { + var response = result.responseJSON; + if (!$("#error_list").hasClass('hidden')) { + $("#error_list").empty(); + $(".has-error").removeClass('has-error'); + $(".error-label").removeClass('error-label'); + } + $.each(response, function(field, errorlist) { + $.each(errorlist, function(idx, error) { + error = error.toLowerCase(); + if (error.indexOf('ingangstijd') !== -1) { + $('#div_id_messagestarttime').addClass('has-error'); + } else if (error.indexOf('eind') !== -1) { + $('#div_id_messageendtime').addClass('has-error'); + } else if (error.indexOf('rit') !== -1 && error.indexOf('database') === -1) { + $('#div_id_ritten').addClass('error-label'); + } else if (error.indexOf('lijn') !== -1 && error.indexOf('database') === -1) { + $('#div_id_lijnen').addClass('error-label'); + } + $("#error_list").append('

'+error+'

'); + }); + }); + if ($("#error_list").hasClass('hidden')) { + $("#error_list").removeClass('hidden'); + } + } + }); +} + /* TIME FUNCTIONS */ function convertSecondsToTime(seconds) { var hours = Math.floor(seconds / 3600); @@ -549,3 +600,9 @@ function padTime(i) { return '00'; } } + +function stringToTime(timestring) { + timestring = timestring.split(/:/); + var time = timestring[0] * 3600 + timestring[1] * 60; + return time; +} diff --git a/utils/views.py b/utils/views.py index 774f39e8..3b492523 100644 --- a/utils/views.py +++ b/utils/views.py @@ -19,6 +19,7 @@ from django.shortcuts import redirect, render from utils.push import Push from django.db.models.query import QuerySet +from django.http import JsonResponse log = logging.getLogger('openebs.views.mixins') @@ -183,6 +184,33 @@ def dispatch(self, request, *args, **kwargs): request, *args, **kwargs) +class JsonableResponseMixin: + """ + Mixin to add JSON support to a form. + Must be used with an object-based FormView (e.g. CreateView) + """ + + def form_invalid(self, form): + response = super().form_invalid(form) + if self.request.is_ajax(): + return JsonResponse(form.errors, status=400) + else: + return response + + def form_valid(self, form): + # We make sure to call the parent's form_valid() method because + # it might do some processing (in the case of CreateView, it will + # call form.save() for example). + response = super().form_valid(form) + if self.request.is_ajax(): + data = { + 'pk': self.object.pk, + } + return JsonResponse(data) + else: + return response + + def handler403(request, exception): response = render(request, 'openebs/nopermission.html', {}) response.status_code = 404