From 010ad6ef4f1db15a15e1e595eab85852519b4039 Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sat, 10 Feb 2018 16:16:14 +0100 Subject: [PATCH 01/18] Add product info to settings file --- billard/templatetags/form_tags.py | 6 ++++++ caromserver/settings.py | 2 ++ templates/_base.html | 6 +++--- templates/_base_accounts.html | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/billard/templatetags/form_tags.py b/billard/templatetags/form_tags.py index 8c89b26..d2c518f 100644 --- a/billard/templatetags/form_tags.py +++ b/billard/templatetags/form_tags.py @@ -1,4 +1,5 @@ from django import template +from django.conf import settings register = template.Library() @@ -17,3 +18,8 @@ def input_class(bound_field): elif field_type(bound_field) != 'PasswordInput': css_class = 'is-valid' return 'form-control {}'.format(css_class) + + +@register.simple_tag +def settings_value(name): + return getattr(settings, name, '') diff --git a/caromserver/settings.py b/caromserver/settings.py index 621dd8c..40047df 100644 --- a/caromserver/settings.py +++ b/caromserver/settings.py @@ -158,6 +158,8 @@ EMAIL_PORT = 25 URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata' +PRODUCT_INFO = 'CAROM-DEV' + try: from local_settings import * except ImportError: diff --git a/templates/_base.html b/templates/_base.html index 9852361..741c271 100644 --- a/templates/_base.html +++ b/templates/_base.html @@ -1,10 +1,10 @@ -{% load static %} +{% load static form_tags %} - carom - {% block title %}TITLE SETZEN{% endblock %} + {% settings_value "PRODUCT_INFO" %} - {% block title %}TITLE SETZEN{% endblock %} @@ -26,7 +26,7 @@
-{% if object_list %} -

Location Data

- - - - - - - - - - - {% for location_data in object_list %} - - - - - - - - - - {% endfor %} -
IDLocationTableTimestampOn_OffProcError
{{ location_data.id }}{{ location_data.location_id }}{{ location_data.table_no }}{{ location_data.tst }}{{ location_data.on_off }}{{ location_data.processed }}{{ location_data.error_msg }}
-{% else %} -

No data available.

-{% endif %} + {% if object_list %} +

Location Data

+ + + + + + + + + + + {% for location_data in object_list %} + + + + + + + + + + {% endfor %} +
IDLocationTableTimestampOn_OffProcError
{{ location_data.id }}{{ location_data.location_id }}{{ location_data.table_no }}{{ location_data.tst }}{{ location_data.on_off }}{{ location_data.processed }}{{ location_data.error_msg }}
+ {% else %} +

No data available.

+ {% endif %} {% endblock %} diff --git a/billard/templatetags/display_client.py b/billard/templatetags/display_client.py index 90a9db4..e1616d5 100644 --- a/billard/templatetags/display_client.py +++ b/billard/templatetags/display_client.py @@ -1,7 +1,9 @@ +from datetime import datetime + from django import template from django.utils.html import format_html + from billard import utils -from datetime import datetime register = template.Library() @@ -36,15 +38,15 @@ def display_client(client, desk_no): html += '
\n'.format(alert) html += '

({}) {}

\n'.format(desk_no, desk.name) if loc.happy_hour_start is not None and desk.prize_hh is not None: - html += '
Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde
\n'\ + html += '
Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde
\n' \ .format( - desk.prize, - loc.happy_hour_start.strftime('%H:%M'), - loc.happy_hour_end.strftime('%H:%M'), - desk.prize_hh,) + desk.prize, + loc.happy_hour_start.strftime('%H:%M'), + loc.happy_hour_end.strftime('%H:%M'), + desk.prize_hh, ) else: html += '
Preis: {0:.2f} / Stunde
\n'.format( - desk.prize,) + desk.prize, ) if len(acc) > 0: html += ' \n' for a in acc: @@ -52,7 +54,7 @@ def display_client(client, desk_no): html += ' \n'.format(a.time_from.strftime('%d.%m.%Y %H:%M:%S')) html += ' \n'.format( (a.time_to.strftime('%d.%m.%Y %H:%M:%S') if a.time_to is not None else '')) - html += ' \n'\ + html += ' \n' \ .format((a.prize if a.prize is not None else '')) html += ' \n' html += ' \n' diff --git a/billard/tests.py b/billard/tests.py index e738093..b1cc778 100644 --- a/billard/tests.py +++ b/billard/tests.py @@ -38,7 +38,7 @@ class PrizeCalculationTestCase(TestCase): class PrizeGetTestCase(TestCase): - def get_prize_for(self, start, end, pph=0, hh_start=None, hh_end=None, pphh=0, expected=(0,0,0)): + def get_prize_for(self, start, end, pph=0, hh_start=None, hh_end=None, pphh=0, expected=(0, 0, 0)): self.assertEqual(get_prize_for(start, end, pph, hh_start, hh_end, pphh), expected) def test_gpf_1(self): @@ -109,4 +109,4 @@ class PrizeGetTestCase(TestCase): pph = 10 pphh = 5 expected = (7.5, 5, 2.5) - self.get_prize_for(start, end, pph, hh_start, hh_end, pphh, expected) \ No newline at end of file + self.get_prize_for(start, end, pph, hh_start, hh_end, pphh, expected) diff --git a/billard/utils.py b/billard/utils.py index 9f8b6f0..29db778 100644 --- a/billard/utils.py +++ b/billard/utils.py @@ -1,4 +1,4 @@ -from datetime import datetime, date, time, timedelta +from datetime import datetime, date, timedelta def get_prize_for(start, end, pph=0, hh_start=None, hh_end=None, pphh=0): diff --git a/billard/views.py b/billard/views.py index f0ef987..e12f4fa 100644 --- a/billard/views.py +++ b/billard/views.py @@ -1,18 +1,18 @@ import ast import logging -from billard.serializers import LocationDataSerializer -from billard.models import LocationData, Location, Client, Accounting -from billard.tasks import process_location_data -from rest_framework import viewsets -from django.shortcuts import render, redirect -from django.views import generic from django.contrib.auth.decorators import login_required, permission_required from django.db.models import Sum from django.http import HttpResponse -from django.utils.decorators import method_decorator +from django.shortcuts import render, redirect from django.utils import timezone +from django.utils.decorators import method_decorator +from django.views import generic +from rest_framework import viewsets +from billard.models import LocationData, Location, Client, Accounting +from billard.serializers import LocationDataSerializer +from billard.tasks import process_location_data log = logging.getLogger(__name__) @@ -47,7 +47,7 @@ class AccountingView(generic.ListView): context_object_name = 'accounting' def get_queryset(self): - return Accounting.objects.filter(billed=False).filter(desk__client__location_id=self.kwargs['pk'])\ + return Accounting.objects.filter(billed=False).filter(desk__client__location_id=self.kwargs['pk']) \ .exclude(time_to__isnull=True).order_by('time_from') def dispatch(self, request, *args, **kwargs): From 64d38dfcd88225d811f72f882fdfa5b580b736ab Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sun, 11 Feb 2018 10:59:45 +0100 Subject: [PATCH 14/18] fix model dependencies --- billard/migrations/0025_auto_20180211_1059.py | 31 +++++++++++++++++++ billard/models.py | 6 ++-- 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 billard/migrations/0025_auto_20180211_1059.py diff --git a/billard/migrations/0025_auto_20180211_1059.py b/billard/migrations/0025_auto_20180211_1059.py new file mode 100644 index 0000000..9f2a0c6 --- /dev/null +++ b/billard/migrations/0025_auto_20180211_1059.py @@ -0,0 +1,31 @@ +# Generated by Django 2.0.2 on 2018-02-11 10:59 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('billard', '0024_auto_20180210_1105'), + ] + + operations = [ + migrations.AlterField( + model_name='accounting', + name='desk', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billard.Desk', + verbose_name='Tisch'), + ), + migrations.AlterField( + model_name='client', + name='location', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='clients', + to='billard.Location', verbose_name='Standort'), + ), + migrations.AlterField( + model_name='desk', + name='client', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='desks', + to='billard.Client', verbose_name='Client'), + ), + ] diff --git a/billard/models.py b/billard/models.py index a3ebe2c..45e7378 100644 --- a/billard/models.py +++ b/billard/models.py @@ -49,7 +49,7 @@ class Location(models.Model): class Client(models.Model): uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier") - location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort", on_delete=models.DO_NOTHING) + location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort", on_delete=models.CASCADE) report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients', on_delete=models.DO_NOTHING) @@ -62,7 +62,7 @@ class Client(models.Model): class Desk(models.Model): - client = models.ForeignKey(Client, verbose_name='Client', related_name='desks', on_delete=models.DO_NOTHING) + client = models.ForeignKey(Client, verbose_name='Client', related_name='desks', on_delete=models.CASCADE) desk_no = models.IntegerField(verbose_name='Tischnummer') name = models.CharField(max_length=32, blank=True, null=True, verbose_name='Tischbezeichnung') enabled = models.BooleanField(verbose_name='Tisch aktiv') @@ -79,7 +79,7 @@ class Desk(models.Model): class Accounting(models.Model): - desk = models.ForeignKey(Desk, verbose_name="Tisch", on_delete=models.DO_NOTHING) + desk = models.ForeignKey(Desk, verbose_name="Tisch", on_delete=models.CASCADE) time_from = models.DateTimeField(verbose_name="Beginn") time_to = models.DateTimeField(blank=True, null=True, verbose_name="Ende") prize = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True, verbose_name="Preis") From 1a0c0ff63a04793c6b535fe6d08858f33ff46244 Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sun, 11 Feb 2018 11:05:50 +0100 Subject: [PATCH 15/18] add abrechnen button to location detail --- billard/templates/billard/location_detail.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/billard/templates/billard/location_detail.html b/billard/templates/billard/location_detail.html index 60d3c14..1574d26 100644 --- a/billard/templates/billard/location_detail.html +++ b/billard/templates/billard/location_detail.html @@ -11,6 +11,14 @@
{% include 'billard/location_detail_ajax.html' %}
+
+
+ {% if perms.billard.change_accounting %} + Abrechnen + {% endif %} +
+
{% endblock %} From bab9196c3884e17272d8593e1926086b476867c6 Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sun, 11 Feb 2018 11:18:15 +0100 Subject: [PATCH 16/18] show alert-danger if client last_seen older then 5 minutes --- billard/admin.py | 4 ++-- billard/migrations/0026_client_last_seen.py | 17 +++++++++++++++++ billard/models.py | 1 + billard/templatetags/display_client.py | 5 ++++- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 billard/migrations/0026_client_last_seen.py diff --git a/billard/admin.py b/billard/admin.py index f23d77c..b06774c 100644 --- a/billard/admin.py +++ b/billard/admin.py @@ -31,8 +31,8 @@ class LocationAdmin(admin.ModelAdmin): @admin.register(Client) class ClientAdmin(admin.ModelAdmin): - list_display = ('uuid', 'location', 'report_user') - fields = ['location', 'uuid', 'report_user'] + list_display = ('uuid', 'location', 'report_user', 'last_seen') + fields = ['location', 'uuid', 'report_user', 'last_seen'] @admin.register(LocationData) diff --git a/billard/migrations/0026_client_last_seen.py b/billard/migrations/0026_client_last_seen.py new file mode 100644 index 0000000..d716f52 --- /dev/null +++ b/billard/migrations/0026_client_last_seen.py @@ -0,0 +1,17 @@ +# Generated by Django 2.0.2 on 2018-02-11 11:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('billard', '0025_auto_20180211_1059'), + ] + + operations = [ + migrations.AddField( + model_name='client', + name='last_seen', + field=models.DateTimeField(blank=True, null=True, verbose_name='Letzter Update'), + ), + ] diff --git a/billard/models.py b/billard/models.py index 45e7378..5ce0cde 100644 --- a/billard/models.py +++ b/billard/models.py @@ -52,6 +52,7 @@ class Client(models.Model): location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort", on_delete=models.CASCADE) report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients', on_delete=models.DO_NOTHING) + last_seen = models.DateTimeField(blank=True, null=True, verbose_name="Letzter Update") def __str__(self): return '{}, {}'.format(self.location.name, self.uuid) diff --git a/billard/templatetags/display_client.py b/billard/templatetags/display_client.py index e1616d5..d15f81a 100644 --- a/billard/templatetags/display_client.py +++ b/billard/templatetags/display_client.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta from django import template from django.utils.html import format_html @@ -34,6 +34,9 @@ def display_client(client, desk_no): prize = '{0:.2f}'.format(prize) if prize != a.prize: a.prize = prize + before5min = datetime.now() - timedelta(minutes=5) + if client.last_seen is not None and client.last_seen < before5min: + alert = 'alert-danger' html = '
\n' html += '
\n'.format(alert) html += '

({}) {}

\n'.format(desk_no, desk.name) From ae020102032a6cd5918759a4e77e5536f1742cf1 Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sun, 11 Feb 2018 11:27:27 +0100 Subject: [PATCH 17/18] add last_seen serializer --- billard/serializers.py | 8 +++++++- billard/urls.py | 1 + billard/views.py | 7 ++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/billard/serializers.py b/billard/serializers.py index 92d287c..dd40344 100644 --- a/billard/serializers.py +++ b/billard/serializers.py @@ -1,9 +1,15 @@ from rest_framework import serializers -from billard.models import LocationData +from billard.models import LocationData, Client class LocationDataSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = LocationData fields = ('client_id', 'desk_no', 'tst', 'on_off',) + + +class ClientUpdateLastSeenSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Client + fields = ('uuid', 'last_seen') diff --git a/billard/urls.py b/billard/urls.py index f70f7fe..a28b8b8 100644 --- a/billard/urls.py +++ b/billard/urls.py @@ -7,6 +7,7 @@ from billard import views router = routers.DefaultRouter() router.register(r'locationdata', views.LocationDataViewSet) +router.register(r'last_seen', views.ClientUpdateLastSeenViewSet) app_name = 'billard' urlpatterns = [ diff --git a/billard/views.py b/billard/views.py index e12f4fa..2b737d9 100644 --- a/billard/views.py +++ b/billard/views.py @@ -11,7 +11,7 @@ from django.views import generic from rest_framework import viewsets from billard.models import LocationData, Location, Client, Accounting -from billard.serializers import LocationDataSerializer +from billard.serializers import LocationDataSerializer, ClientUpdateLastSeenSerializer from billard.tasks import process_location_data log = logging.getLogger(__name__) @@ -108,6 +108,11 @@ class LocationDataViewSet(viewsets.ModelViewSet): serializer_class = LocationDataSerializer +class ClientUpdateLastSeenViewSet(viewsets.ModelViewSet): + queryset = LocationData.objects.all() + serializer_class = ClientUpdateLastSeenSerializer + + def process_location_data(request): process_location_data() return HttpResponse('DONE') From 3bb906c732877407c4c02ed64b928805e6708d6b Mon Sep 17 00:00:00 2001 From: Robert Einsle Date: Sun, 11 Feb 2018 11:30:09 +0100 Subject: [PATCH 18/18] Update Version information --- caromserver/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caromserver/settings.py b/caromserver/settings.py index ac8d0f0..767644f 100644 --- a/caromserver/settings.py +++ b/caromserver/settings.py @@ -160,7 +160,7 @@ EMAIL_PORT = 25 URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata' PRODUCT_INFO = 'CAROM-DEV' -PRODUCT_VERSION = 'v 0.5.0' +PRODUCT_VERSION = 'v 0.5.1' INTERNAL_IPS = ['127.0.0.1']
{}{}{}{}