diff --git a/billard/admin.py b/billard/admin.py
index 2caca6d..062d815 100644
--- a/billard/admin.py
+++ b/billard/admin.py
@@ -57,4 +57,8 @@ class DeskAdmin(admin.ModelAdmin):
@admin.register(Accounting)
class AccountingAdmin(admin.ModelAdmin):
- list_display = ('desk', 'time_from', 'time_to', 'prize', 'billed')
+ list_display = ('desk', 'time_from', 'time_to', 'prize', 'billed', 'account_user', 'account_tst')
+ list_filter = ('desk__client__location', 'account_user', 'account_tst', 'billed')
+
+ def has_add_permission(self, request):
+ return False
diff --git a/billard/migrations/0001_initial.py b/billard/migrations/0001_initial.py
index 143db55..6a2e816 100644
--- a/billard/migrations/0001_initial.py
+++ b/billard/migrations/0001_initial.py
@@ -10,6 +10,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
+ ('sessions', '0001_initial'),
]
operations = [
diff --git a/billard/migrations/0021_accounting_account_user.py b/billard/migrations/0021_accounting_account_user.py
new file mode 100644
index 0000000..a36ff21
--- /dev/null
+++ b/billard/migrations/0021_accounting_account_user.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11 on 2017-04-26 10:17
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('billard', '0020_auto_20170410_1853'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='accounting',
+ name='account_user',
+ field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Abr. Benutzer'),
+ ),
+ ]
diff --git a/billard/migrations/0022_auto_20170427_0835.py b/billard/migrations/0022_auto_20170427_0835.py
new file mode 100644
index 0000000..96e686e
--- /dev/null
+++ b/billard/migrations/0022_auto_20170427_0835.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11 on 2017-04-27 08:35
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('billard', '0021_accounting_account_user'),
+ ]
+
+ operations = [
+ 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'),
+ ),
+ ]
diff --git a/billard/migrations/0023_accounting_account_tst.py b/billard/migrations/0023_accounting_account_tst.py
new file mode 100644
index 0000000..7fe5c71
--- /dev/null
+++ b/billard/migrations/0023_accounting_account_tst.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11 on 2017-04-29 11:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('billard', '0022_auto_20170427_0835'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='accounting',
+ name='account_tst',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='Abr. TST'),
+ ),
+ ]
diff --git a/billard/models.py b/billard/models.py
index 33aedfe..65d6875 100644
--- a/billard/models.py
+++ b/billard/models.py
@@ -2,8 +2,6 @@ import uuid
import logging
from django.db import models
from django.contrib.auth.models import User
-from datetime import datetime, timezone
-from billard import utils
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
@@ -50,7 +48,7 @@ class Location(models.Model):
class Client(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier")
- location = models.ForeignKey(Location, verbose_name="Standort")
+ location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort")
report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients')
def __str__(self):
@@ -70,7 +68,6 @@ class Desk(models.Model):
prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True,
verbose_name="Preis Happy Hour")
-
def __str__(self):
return '{}, {}'.format(self.client.uuid, self.name)
@@ -88,6 +85,8 @@ class Accounting(models.Model):
reporter_uuid = models.UUIDField(blank=True, null=True, verbose_name='Reporter UUID')
prize_normal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Normalzeit")
prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Happy Hour")
+ account_user = models.CharField(blank=True, null=True, max_length=128, verbose_name="Abr. Benutzer")
+ account_tst = models.DateTimeField(blank=True, null=True, verbose_name="Abr. TST")
def __str__(self):
return '{}: {} -> {}, {}, {}'.format(self.desk, self.time_from, self.time_to, self.prize, self.billed)
diff --git a/billard/templates/billard/accounting.html b/billard/templates/billard/accounting.html
index 112beae..207b502 100644
--- a/billard/templates/billard/accounting.html
+++ b/billard/templates/billard/accounting.html
@@ -1,24 +1,14 @@
{% extends 'billard/base.html' %}
{% load display_client %}
-{% block title %}Accounting Data{% endblock %}
+{% block title %}Abrechnung{% endblock %}
{% block content %}
-{% if not locations|length_is:"1" %}
-
-{% endif %}
Gesamt-Summe: {{ acc_sum }}
+ {{ pk }}
+
Start-Datum: |
@@ -38,7 +28,7 @@
{% endfor %}
-
{% endif %}
+
+
+
+
{% include 'billard/index_ajax.html' %}
{% endblock %}
+
{% block js %}
+{% endblock %}
\ No newline at end of file
diff --git a/billard/templates/billard/location_detail_ajax.html b/billard/templates/billard/location_detail_ajax.html
new file mode 100644
index 0000000..cef9821
--- /dev/null
+++ b/billard/templates/billard/location_detail_ajax.html
@@ -0,0 +1,12 @@
+{% load display_client %}
+{% if location.clients.all %}
+{% for cli in location.clients.all %}
+{% for i in "12345678" %}
+ {{ cli|display_client:i }}
+{% endfor %}
+{% endfor %}
+{% else %}
+
+
Keine Tische angelegt!
+
+{% endif %}
diff --git a/billard/templates/billard/location_index.html b/billard/templates/billard/location_index.html
new file mode 100644
index 0000000..cfad5af
--- /dev/null
+++ b/billard/templates/billard/location_index.html
@@ -0,0 +1,37 @@
+{% extends 'billard/base.html' %}
+
+{% block title %}Standortliste{% endblock %}
+
+{% block content %}
+
+{% if location_list %}
+ Bitte Standort auswählen:
+
+
+ Code |
+ Name |
+ Strasse |
+ Plz |
+ Ort |
+{% if perms.billard.change_accounting %}
+ Accounting |
+{% endif %}
+
+{% for loc in location_list %}
+
+ {{ loc.code|default_if_none:"" }} |
+ {{ loc.name|default_if_none:"" }} |
+ {{ loc.street|default_if_none:"" }} |
+ {{ loc.plz|default_if_none:"" }} |
+ {{ loc.city|default_if_none:"" }} |
+{% if perms.billard.change_accounting %}
+ Abrechnen |
+{% endif %}
+
+{% endfor %}
+
+{% else %}
+ Keine Standorte Zugeordnet.
+{% endif %}
+
+{% endblock %}
diff --git a/billard/urls.py b/billard/urls.py
index c61e51c..79d842e 100644
--- a/billard/urls.py
+++ b/billard/urls.py
@@ -1,16 +1,28 @@
from django.conf.urls import url, include
+from django.contrib.auth.decorators import login_required
from rest_framework import routers
from billard import views
router = routers.DefaultRouter()
router.register(r'location_data', views.LocationDataViewSet)
+app_name = 'billard'
urlpatterns = [
- url(r'^$', views.index, name='carom_index'),
- url(r'^(?P[0-9]+)/$', views.LocationDataDetailView.as_view(), name='detail'),
+ # ex. /billard/
+ url(r'^$', login_required(views.LocationIndexView.as_view()), name='location_index'),
+ # ex. /billard/1/
+ url(r'^(?P[0-9]+)/$', login_required(views.LocationDetailView.as_view()), name='location_detail'),
+ # ex. /billard/1/accounting/
+ url(r'^(?P[0-9]+)/accounting/$', views.AccountingView.as_view(), name='accounting_detail'),
+ # ex. /billard/1/accounting/confirm
+ url(r'^(?P[0-9]+)/accounting/confirm/$', views.accounting_confirm, name='accounting_detail_confirm'),
+ # ex. /billard/1/account_modal/
+ url(r'^(?P[0-9]+)/account_modal/$', views.account_modal_view, name='account_modal'),
+ # ex. /billard/1/account_modal/confirm/
+ url(r'^(?P[0-9]+)/account_modal/(?P[0-9]+)/confirm/$', views.account_modal_confirm_view,
+ name='account_modal_confirm'),
+ # ex. /billard/api/v1/ (rest api)
url(r'api/v1/', include(router.urls)),
- url(r'process_locationdata', views.process_locationdata, name='process_locationdata'),
- url(r'accounting', views.accounting, name='accounting'),
- url(r'accountmodal$', views.accountmodalview, name='accountmodal'),
- url(r'accoutmodal/confirm/(?P[0-9]+)$', views.accountmodalconfirmview, name="accountmodalconfirm")
+ # ex. /billard/process_location_data/
+ url(r'^process_location_data/$', views.process_location_data, name='process_location_data'),
]
diff --git a/billard/views.py b/billard/views.py
index d9b091e..087fef1 100644
--- a/billard/views.py
+++ b/billard/views.py
@@ -1,13 +1,96 @@
+import ast
+
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.views.generic.detail import DetailView
from django.contrib.auth.decorators import login_required, permission_required
-from django.db.models import Min, Sum
+from django.db.models import Sum
from django.http import HttpResponse
+from django.utils.decorators import method_decorator
+from django.utils import timezone
+
+
+class LocationIndexView(generic.ListView):
+ template_name = 'billard/location_index.html'
+ context_object_name = 'location_list'
+
+ def get_queryset(self):
+ """Return the last five published questions."""
+ return Location.objects.filter(users__id=self.request.user.id).order_by('code')
+
+
+class LocationDetailView(generic.DetailView):
+ model = Location
+ template_name = 'billard/location_detail.html'
+
+ def dispatch(self, request, *args, **kwargs):
+ if request.is_ajax():
+ context = {
+ 'location': self.get_object(),
+ }
+ return render(request, template_name='billard/location_detail_ajax.html', context=context)
+ result = super(LocationDetailView, self).dispatch(request, *args, **kwargs)
+ result.context_data['pk'] = self.kwargs['pk']
+ return result
+
+
+@method_decorator(login_required, name='dispatch')
+class AccountingView(generic.ListView):
+ template_name = 'billard/accounting.html'
+ context_object_name = 'accounting'
+
+ def get_queryset(self):
+ return Accounting.objects.filter(billed=False).exclude(time_to__isnull=True).order_by('time_from')
+
+ def dispatch(self, request, *args, **kwargs):
+ result = super(AccountingView, self).dispatch(request, *args, **kwargs)
+ acc_sum = self.get_queryset().aggregate(Sum('prize'))
+ if acc_sum['prize__sum'] is None:
+ result.context_data['acc_sum'] = 0
+ else:
+ result.context_data['acc_sum'] = acc_sum['prize__sum']
+ result.context_data['acc_ids'] = [acc.id for acc in self.get_queryset().all()]
+ return result
+
+
+@login_required
+@permission_required('billard.change_accounting')
+def accounting_confirm(request, pk):
+ if request.method == 'POST':
+ if 'accountings' in request.POST:
+ acc_ids = ast.literal_eval(request.POST['accountings'])
+ if len(acc_ids) > 0:
+ Accounting.objects.filter(id__in=acc_ids).update(billed=True)
+ Accounting.objects.filter(id__in=acc_ids).update(account_user=request.user.username)
+ Accounting.objects.filter(id__in=acc_ids).update(account_tst=timezone.now())
+ resp = redirect('billard:accounting_detail', pk=pk)
+ return resp
+
+
+@login_required
+def account_modal_view(request, loc_pk):
+ try:
+ uuids = Client.objects.filter(report_user=request.user).values_list('uuid')
+ account = Accounting.objects.filter(reporter_uuid__in=uuids).first
+ # TODO: support multiple account objects
+ except Client.DoesNotExist:
+ account = None
+ context = {
+ 'account': account,
+ 'loc_pk': loc_pk,
+ }
+ return render(request, 'billard/accountmodal.html', context=context)
+
+
+@login_required
+def account_modal_confirm_view(request, loc_pk, pk):
+ account = Accounting.objects.get(pk=pk)
+ account.reporter_uuid = None
+ account.save()
+ return redirect('billard:location_detail', pk=loc_pk)
class LocationDataViewSet(viewsets.ModelViewSet):
@@ -15,133 +98,6 @@ class LocationDataViewSet(viewsets.ModelViewSet):
serializer_class = LocationDataSerializer
-class IndexView(generic.ListView):
- model = LocationData
-
- def get_template_names(self):
- if self.request.is_ajax():
- return ('billard/locationdata_list_ajax.html',)
- return super().get_template_names()
-
-
-class LocationDataDetailView(DetailView):
- model = LocationData
-
- def get_template_names(self):
- if self.request.is_ajax():
- return ('billard/locationdata_detail_ajax.html',)
- return super().get_template_names()
-
-
-@login_required
-def accountmodalview(request):
- try:
- uuids = Client.objects.filter(report_user=request.user).values_list('uuid')
- account = Accounting.objects.filter(reporter_uuid__in=uuids).first
- #TODO: support multiple account objects
- except Client.DoesNotExist:
- account = None
- context = {
- 'account': account
- }
- return render(request, 'billard/accountmodal.html', context=context)
-
-
-@login_required
-def accountmodalconfirmview(request, pk):
- account = Accounting.objects.get(pk=pk)
- account.reporter_uuid = None
- account.save()
- return redirect('carom_index')
-
-
-@login_required
-@permission_required('billard.change_accounting')
-def accounting(request):
- if request.method == 'GET':
- template = 'billard/accounting.html'
- loc = None
- min_loc = Location.objects.filter(users__id=request.user.id).aggregate(Min('id'))['id__min']
- if 'loc' in request.GET:
- loc = request.GET['loc']
- if not Location.objects.filter(users__id=request.user.id).filter(id=loc).exists():
- resp = redirect('accounting')
- if min_loc is not None:
- resp['Location'] += '?loc={}'.format(str(min_loc))
- request.session['loc'] = str(min_loc)
- return resp
- else:
- return render(request, accounting)
- if loc is None:
- loc = min_loc
- locations = Location.objects.filter(users__id=request.user.id).order_by('code')
- acc = Accounting.objects.filter(billed=False).exclude(time_to__isnull=True).\
- filter(desk__client__location_id=loc).order_by('-time_from')
- acc_sum = acc.aggregate(Sum('prize'))
- acc_ids = list()
- for a in acc:
- acc_ids.append(a.id)
-
- context = {
- 'location_id': int(loc),
- 'locations': locations,
- 'accounting': acc,
- 'acc_ids': ','.join(str(e) for e in acc_ids),
- }
- if acc_sum['prize__sum'] is None:
- context['acc_sum'] = 0
- else:
- context['acc_sum'] = acc_sum['prize__sum']
- return render(request, template_name=template, context=context)
- if request.method == 'POST':
- loc = request.POST['location-selector']
- if 'accountings' in request.POST:
- acc_ids = request.POST['accountings'].split(',')
- Accounting.objects.filter(id__in=acc_ids).update(billed=True)
- request.session['loc'] = str(loc)
- resp = redirect('accounting')
- resp['Location'] += '?loc={}'.format(str(loc))
- return resp
-
-
-@login_required
-def index(request):
- if request.method == 'GET':
- template = 'billard/index.html'
- loc = None
- if request.is_ajax():
- template = 'billard/index_ajax.html'
- loc = request.session.get('loc')
- min_loc = Location.objects.filter(users__id=request.user.id).aggregate(Min('id'))['id__min']
- if 'loc' in request.GET:
- loc = request.GET['loc']
- if not Location.objects.filter(users__id=request.user.id).filter(id=loc).exists():
- resp = redirect('carom_index')
- if min_loc is not None:
- resp['Location'] += '?loc={}'.format(str(min_loc))
- request.session['loc'] = str(min_loc)
- return resp
- else:
- return render(request, template)
- if loc is None:
- loc = min_loc
- locations = Location.objects.filter(users__id=request.user.id).order_by('code')
- clients = Client.objects.filter(location_id=loc).order_by('id')
- context = {
- 'range': range(1, 9),
- 'locations': locations,
- 'clients': clients,
- 'location_id': int(loc),
- }
- return render(request, template, context=context)
- if request.method == 'POST':
- loc = request.POST['location-selector']
- request.session['loc'] = str(loc)
- resp = redirect('carom_index')
- resp['Location'] += '?loc={}'.format(str(loc))
- return resp
-
-
-def process_locationdata(request):
+def process_location_data(request):
process_location_data()
return HttpResponse('DONE')
diff --git a/caromserver/settings.py b/caromserver/settings.py
index f966cca..d6ee8c9 100644
--- a/caromserver/settings.py
+++ b/caromserver/settings.py
@@ -135,8 +135,8 @@ REST_FRAMEWORK = {
CRISPY_TEMPLATE_PACK = 'bootstrap3'
LOGIN_URL = 'login'
LOGOUT_URL = 'logout'
-LOGIN_REDIRECT_URL = 'carom_index'
-LOGOUT_REDIRECT_URL = 'carom_index'
+LOGIN_REDIRECT_URL = 'billard:location_index'
+LOGOUT_REDIRECT_URL = 'billard:location_index'
# CELERY STUFF
BROKER_URL = 'redis://localhost:6379'