Merge branch 'release/1.0.0'
This commit is contained in:
@@ -8,3 +8,5 @@ build/
|
|||||||
*/*/__pycache__/
|
*/*/__pycache__/
|
||||||
caromserver/local_settings.py
|
caromserver/local_settings.py
|
||||||
/staticfiles/
|
/staticfiles/
|
||||||
|
.venv/
|
||||||
|
update.sh
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
django = "==2.1.5"
|
||||||
|
django-crispy-forms = "==1.7.2"
|
||||||
|
django-debug-toolbar = "==1.11"
|
||||||
|
django-extensions = "==2.1.5"
|
||||||
|
django-tables2 = "==2.0.4"
|
||||||
|
djangorestframework = "==3.9.1"
|
||||||
|
requests = "==2.21.0"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.5"
|
||||||
Generated
+126
@@ -0,0 +1,126 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "de1e65bd4b2342db22fea58996979f48314fcad56bd7b50f4c939035771ef85c"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.5"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||||
|
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||||
|
],
|
||||||
|
"version": "==2018.11.29"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"django": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8",
|
||||||
|
"sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.1.5"
|
||||||
|
},
|
||||||
|
"django-crispy-forms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5952bab971110d0b86c278132dae0aa095beee8f723e625c3d3fa28888f1675f",
|
||||||
|
"sha256:705ededc554ad8736157c666681165fe22ead2dec0d5446d65fc9dd976a5a876"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.7.2"
|
||||||
|
},
|
||||||
|
"django-debug-toolbar": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736",
|
||||||
|
"sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.11"
|
||||||
|
},
|
||||||
|
"django-extensions": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6fcedb2ea660c9dbf9ac59441721ffdd4ab5b753fbd6159c3e28f391a65bab46",
|
||||||
|
"sha256:a607459e5fa8c579a672131b63366fa52fab80adb2a862d362f5fb48cd2d2cac"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.1.5"
|
||||||
|
},
|
||||||
|
"django-tables2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a893fca1afe2e95b9739c6428cc6c9735a219f65707e24274df3920f61358525",
|
||||||
|
"sha256:b5f7b4c76160ee927005e52ebea633c86d4529cf84757c0acd5d0434d31798a1"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.0.4"
|
||||||
|
},
|
||||||
|
"djangorestframework": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:79c6efbb2514bc50cf25906d7c0a5cfead714c7af667ff4bd110312cd380ae66",
|
||||||
|
"sha256:a4138613b67e3a223be6c97f53b13d759c5b90d2b433bad670b8ebf95402075f"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.9.1"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||||
|
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||||
|
],
|
||||||
|
"version": "==2.8"
|
||||||
|
},
|
||||||
|
"pytz": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
|
||||||
|
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
|
||||||
|
],
|
||||||
|
"version": "==2018.9"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
||||||
|
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.21.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||||
|
],
|
||||||
|
"version": "==1.12.0"
|
||||||
|
},
|
||||||
|
"sqlparse": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ce028444cfab83be538752a2ffdb56bc417b7784ff35bb9a3062413717807dec",
|
||||||
|
"sha256:d9cf190f51cbb26da0412247dfe4fb5f4098edb73db84e02f9fc21fdca31fed4"
|
||||||
|
],
|
||||||
|
"version": "==0.2.4"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||||
|
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||||
|
],
|
||||||
|
"version": "==1.24.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
||||||
@@ -35,6 +35,12 @@ class ClientAdmin(admin.ModelAdmin):
|
|||||||
fields = ['location', 'uuid', 'report_user', 'last_seen']
|
fields = ['location', 'uuid', 'report_user', 'last_seen']
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ClientData)
|
||||||
|
class ClientDataAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('uuid', 'last_seen')
|
||||||
|
fields = ['location', 'last_seen']
|
||||||
|
|
||||||
|
|
||||||
@admin.register(LocationData)
|
@admin.register(LocationData)
|
||||||
class LocationDataAdmin(admin.ModelAdmin):
|
class LocationDataAdmin(admin.ModelAdmin):
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
@@ -46,6 +52,8 @@ class LocationDataAdmin(admin.ModelAdmin):
|
|||||||
return my_urls + urls
|
return my_urls + urls
|
||||||
|
|
||||||
def process_locationdata(self, request):
|
def process_locationdata(self, request):
|
||||||
|
from .tasks import process_location_data
|
||||||
|
process_location_data(sender=None)
|
||||||
messages.success(request, 'Items processed.')
|
messages.success(request, 'Items processed.')
|
||||||
return redirect('admin:billard_locationdata_changelist')
|
return redirect('admin:billard_locationdata_changelist')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserInformationUpdateForm(forms.ModelForm):
|
||||||
|
email = forms.EmailField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ('first_name', 'last_name', 'email',)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 2.0.2 on 2018-02-19 10:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('billard', '0026_client_last_seen'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ClientData',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('uuid', models.UUIDField(verbose_name='Identifier')),
|
||||||
|
('last_seen', models.DateTimeField(verbose_name='Letzter Update')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Client Data logs',
|
||||||
|
'verbose_name_plural': 'Client Data logs',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
+10
-6
@@ -4,8 +4,6 @@ import uuid
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.signals import post_save
|
|
||||||
from django.dispatch import receiver
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -102,7 +100,13 @@ class Accounting(models.Model):
|
|||||||
verbose_name_plural = "Buchhaltungseinträge"
|
verbose_name_plural = "Buchhaltungseinträge"
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=LocationData)
|
class ClientData(models.Model):
|
||||||
def test(sender, **kwargs):
|
uuid = models.UUIDField(verbose_name="Identifier")
|
||||||
from .tasks import process_location_data
|
last_seen = models.DateTimeField(verbose_name="Letzter Update")
|
||||||
process_location_data()
|
|
||||||
|
def __str__(self):
|
||||||
|
return '{}, {}'.format(self.uuid, self.last_seen)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Client Data logs"
|
||||||
|
verbose_name_plural = "Client Data logs"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from billard.models import LocationData, Client
|
from billard.models import LocationData, ClientData
|
||||||
|
|
||||||
|
|
||||||
class LocationDataSerializer(serializers.HyperlinkedModelSerializer):
|
class LocationDataSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
@@ -11,5 +11,5 @@ class LocationDataSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
|
|
||||||
class ClientUpdateLastSeenSerializer(serializers.HyperlinkedModelSerializer):
|
class ClientUpdateLastSeenSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Client
|
model = ClientData
|
||||||
fields = ('uuid', 'last_seen')
|
fields = ('uuid', 'last_seen')
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import django_tables2 as tables
|
||||||
|
|
||||||
|
from .models import Location
|
||||||
|
|
||||||
|
|
||||||
|
class LocationTable(tables.Table):
|
||||||
|
code = tables.TemplateColumn(template_name='billard/tc_location_detail.html')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Location
|
||||||
|
fields = ('code', 'name', 'street', 'plz', 'city')
|
||||||
|
orderable = False
|
||||||
|
|
||||||
|
|
||||||
|
class LocationAccountingTable(tables.Table):
|
||||||
|
code = tables.TemplateColumn(template_name='billard/tc_location_detail.html')
|
||||||
|
accounting = tables.TemplateColumn(template_name='billard/tc_accounting_detail.html')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Location
|
||||||
|
fields = ('code', 'name', 'street', 'plz', 'city', 'accounting')
|
||||||
|
orderable = False
|
||||||
+24
-2
@@ -2,13 +2,28 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
import billard.utils as utils
|
import billard.utils as utils
|
||||||
from billard.models import LocationData, Client, Accounting
|
from billard.models import LocationData, Client, Accounting, ClientData
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def process_location_data():
|
@receiver(post_save, sender=ClientData)
|
||||||
|
def process_client_data(sender, **kwargs):
|
||||||
|
data = ClientData.objects.all().order_by('last_seen')
|
||||||
|
for cd in data:
|
||||||
|
client = Client.objects.get(uuid=cd.uuid)
|
||||||
|
client.last_seen = cd.last_seen
|
||||||
|
client.save()
|
||||||
|
cd.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=LocationData)
|
||||||
|
def process_location_data(sender, **kwargs):
|
||||||
|
log.info('Starte die Verarbeitung der Location-Data-Objecte')
|
||||||
data = LocationData.objects.filter(processed=False).order_by('tst')
|
data = LocationData.objects.filter(processed=False).order_by('tst')
|
||||||
for ld in data:
|
for ld in data:
|
||||||
try:
|
try:
|
||||||
@@ -64,3 +79,10 @@ def process_location_data():
|
|||||||
log.error(ld.error_msg)
|
log.error(ld.error_msg)
|
||||||
except:
|
except:
|
||||||
log.exception('', exc_info=True)
|
log.exception('', exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Accounting)
|
||||||
|
def process_accounting_data(sender, **kwargs):
|
||||||
|
log.info('Starte die Verarbeitung der Accounting-Data-Objecte')
|
||||||
|
data = Accounting.objects.filter(prize=0.0, reporter_uuid__isnull=True).exclude(time_to__isnull=True)
|
||||||
|
data.delete()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load i18n admin_urls static admin_list %}
|
{% load i18n admin_urls static admin_list %}
|
||||||
{% block object-tools-items %}
|
{% block object-tools-items %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'admin:process_locationdata' %}">
|
<a href="{% url 'admin:process_locationdata' %}" title="Verarbeiten der LocationDate Elemente">
|
||||||
LD Verarbeiten
|
LD Verarbeiten
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -15,30 +15,33 @@
|
|||||||
|
|
||||||
{{ pk }}
|
{{ pk }}
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
<tr>
|
|
||||||
<th>Start-Datum:</th>
|
|
||||||
<th>Stop-Datum:</th>
|
|
||||||
<th>Preis Normal:</th>
|
|
||||||
<th>Preis Happy Hour:</th>
|
|
||||||
<th>Preis gesamt:</th>
|
|
||||||
</tr>
|
|
||||||
{% for acc in accounting %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ acc.time_from }}</td>
|
|
||||||
<td>{{ acc.time_to }}</td>
|
|
||||||
<td>{{ acc.prize_normal }}</td>
|
|
||||||
<td>{{ acc.prize_hh }}</td>
|
|
||||||
<td>{{ acc.prize }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<form action="confirm/" method="post" id="accounting">
|
<form action="confirm/" method="post" id="accounting">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Start-Datum:</th>
|
||||||
|
<th>Stop-Datum:</th>
|
||||||
|
<th>Preis Normal:</th>
|
||||||
|
<th>Preis Happy Hour:</th>
|
||||||
|
<th>Preis gesamt:</th>
|
||||||
|
</tr>
|
||||||
|
{% for acc in accounting %}
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" name="list_acc_id" id="option{{ acc.id }}"
|
||||||
|
value={{ acc.id }} checked="checked"/></td>
|
||||||
|
<td>{{ acc.time_from }}</td>
|
||||||
|
<td>{{ acc.time_to }}</td>
|
||||||
|
<td>{{ acc.prize_normal }}</td>
|
||||||
|
<td>{{ acc.prize_hh }}</td>
|
||||||
|
<td>{{ acc.prize }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
<input type="hidden" name="location-selector" value="{{ location_id }}">
|
<input type="hidden" name="location-selector" value="{{ location_id }}">
|
||||||
<input type="hidden" name="accountings" value="{{ acc_ids }}">
|
<input type="hidden" name="accountings" value="{{ acc_ids }}">
|
||||||
<button type="submit" class="btn btn-default">Abrechnen</button>
|
<button type="submit" class="btn btn-danger">Abrechnen</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
{% extends '_base.html' %}
|
|
||||||
{% load display_client %}
|
|
||||||
|
|
||||||
{% block title %}Location Data{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% if not locations|length_is:"1" %}
|
|
||||||
<form action="." method="post" id="location-form">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div id="location-selector" class="alert">
|
|
||||||
<select class="form-control" form="location-form" name="location-selector" id="location-select">
|
|
||||||
{% for loc in locations %}
|
|
||||||
<option value="{{ loc.id }}"{% if loc.id == location_id %} selected{% endif %}>{{ loc.code }}
|
|
||||||
- {{ loc.name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="desk_data">
|
|
||||||
{% include 'billard/index_ajax.html' %}
|
|
||||||
</div>
|
|
||||||
<div id="modal-wrapper">
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
var interval;
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.ajaxSetup({cache: false});
|
|
||||||
interval = window.setInterval(refresh_page, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
function refresh_page() {
|
|
||||||
$('#desk_data').load('#');
|
|
||||||
$('#modal-wrapper').load('{% url 'accountmodal' %}', function () {
|
|
||||||
if ($('#accountsmodal').length) {
|
|
||||||
window.clearInterval(interval);
|
|
||||||
$('#accountsmodal').modal('show');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{% load display_client %}
|
|
||||||
{% if clients %}
|
|
||||||
{% for cli in clients %}
|
|
||||||
{% for i in range %} {{ cli|display_client:i }} {% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="col-md-12 alert alert-danger">Keine Tische angelegt!</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% load display_client %}
|
{% load display_client display_daily_sale %}
|
||||||
{% if location.clients.all %}
|
{% if location.clients.all %}
|
||||||
{% for cli in location.clients.all %}
|
{% for cli in location.clients.all %}
|
||||||
{% for i in "12345678" %}
|
{% for i in "12345678" %}
|
||||||
@@ -10,3 +10,8 @@
|
|||||||
<div class="alert alert-danger">Keine Tische angelegt!</div>
|
<div class="alert alert-danger">Keine Tische angelegt!</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div class="col col-12">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{{ location|display_daily_sale }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends '_base.html' %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
|
||||||
{% block title %}Standortliste{% endblock %}
|
{% block title %}Standortliste{% endblock %}
|
||||||
|
|
||||||
@@ -7,37 +8,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<h2>Bitte Standort auswählen:</h2>
|
||||||
{% if location_list %}
|
{% render_table table %}
|
||||||
<h2>Bitte Standort auswählen:</h2>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<tr>
|
|
||||||
<th>Code</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Strasse</th>
|
|
||||||
<th>Plz</th>
|
|
||||||
<th>Ort</th>
|
|
||||||
{% if perms.billard.change_accounting %}
|
|
||||||
<th>Accounting</th>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
{% for loc in location_list %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'billard:location_detail' loc.id %}"
|
|
||||||
class="btn btn-outline-primary btn-sm">{{ loc.code|default_if_none:"" }}</a></td>
|
|
||||||
<td>{{ loc.name|default_if_none:"" }}</td>
|
|
||||||
<td>{{ loc.street|default_if_none:"" }}</td>
|
|
||||||
<td>{{ loc.plz|default_if_none:"" }}</td>
|
|
||||||
<td>{{ loc.city|default_if_none:"" }}</td>
|
|
||||||
{% if perms.billard.change_accounting %}
|
|
||||||
<td><a href="{% url 'billard:accounting_detail' loc.id %}"
|
|
||||||
class="btn btn-outline-danger btn-sm">Abrechnen</a></td>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p>Keine Standorte Zugeordnet.</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
{% extends '_base.html' %}
|
|
||||||
|
|
||||||
{% block title %}Location Data{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% include 'billard/locationdata_detail_ajax.html' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function () {
|
|
||||||
setInterval(function () {
|
|
||||||
$("#content").load("#")
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<h1>Locationdata: {{ locationdata.id }}</h1>
|
|
||||||
|
|
||||||
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
|
|
||||||
|
|
||||||
<form action="{% url 'index' %}" method="post" class="form-horizontal">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="location_id" class="col-sm-2 control-label">Location Id</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="location_id" type="text" name="location_id" value="{{ locationdata.location_id }}"
|
|
||||||
placeholder="Locaton" class="form-control" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="table_no" class="col-sm-2 control-label">Table Number</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="table_no" type="number" name="table_no" value="{{ locationdata.table_no }}"
|
|
||||||
placeholder="Table" class="form-control" min="1" max="8" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="tst" class="col-sm-2 control-label">Timestamp</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="tst" type="datetime" name="tst" value="{{ locationdata.tst }}"
|
|
||||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="on_off" class="col-sm-2 control-label">On / Off</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="on_off" type="checkbox" name="on_off" value="{{ locationdata.on_off }}"
|
|
||||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="processed" class="col-sm-2 control-label">Processed</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="processed" type="checkbox" name="processed" value="{{ locationdata.processed }}"
|
|
||||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="error_msg" class="col-sm-2 control-label">Error Message</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input id="error_msg" type="text" name="error_msg" value="{{ locationdata.error_msg }}"
|
|
||||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-default">Abschicken</button>
|
|
||||||
<a class="btn btn-default" href=".." role="button">Zurück</a>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{% extends '_base.html' %}
|
|
||||||
|
|
||||||
{% block title %}Location Data{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% include 'billard/locationdata_list_ajax.html' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function () {
|
|
||||||
setInterval(function () {
|
|
||||||
$("#content").load("#")
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{% extends '_base.html' %}
|
|
||||||
|
|
||||||
{% block title %}Location Data{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div id="location-selector" class="alert">
|
|
||||||
<select class="form-control">
|
|
||||||
<option value="1">Casino 1</option>
|
|
||||||
<option value="2">Casino 2</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if object_list %}
|
|
||||||
<h1>Location Data</h1>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Location</th>
|
|
||||||
<th>Table</th>
|
|
||||||
<th>Timestamp</th>
|
|
||||||
<th>On_Off</th>
|
|
||||||
<th>Proc</th>
|
|
||||||
<th>Error</th>
|
|
||||||
</tr>
|
|
||||||
{% for location_data in object_list %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'detail' location_data.id %}">{{ location_data.id }}</a></td>
|
|
||||||
<td>{{ location_data.location_id }}</td>
|
|
||||||
<td>{{ location_data.table_no }}</td>
|
|
||||||
<td>{{ location_data.tst }}</td>
|
|
||||||
<td>{{ location_data.on_off }}</td>
|
|
||||||
<td>{{ location_data.processed }}</td>
|
|
||||||
<td>{{ location_data.error_msg }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p>No data available.</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{% load static from staticfiles %}
|
||||||
|
<a href="{% url 'billard:accounting_detail' record.id %}" class="btn btn-outline-danger btn-sm">Abrechnen</a>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{% load static from staticfiles %}
|
||||||
|
<a href="{% url 'billard:location_detail' record.id %}"
|
||||||
|
class="btn btn-outline-primary btn-sm">{{ record.code|default_if_none:"" }}</a>
|
||||||
@@ -17,28 +17,10 @@ def display_client(client, desk_no):
|
|||||||
loc = desk.client.location
|
loc = desk.client.location
|
||||||
if not desk.enabled:
|
if not desk.enabled:
|
||||||
return ''
|
return ''
|
||||||
alert = 'alert-success'
|
|
||||||
acc = desk.accounting_set.all()[:3][::-1]
|
acc = desk.accounting_set.all()[:3][::-1]
|
||||||
if acc is not None and len(acc) > 0:
|
_calc_prize(desk, acc)
|
||||||
a = acc[-1]
|
|
||||||
if a.time_to is None:
|
|
||||||
alert = 'alert-info'
|
|
||||||
prize, u1, u2 = utils.get_prize_for(
|
|
||||||
start=a.time_from,
|
|
||||||
end=datetime.now(),
|
|
||||||
pph=desk.prize,
|
|
||||||
hh_start=loc.happy_hour_start,
|
|
||||||
hh_end=loc.happy_hour_end,
|
|
||||||
pphh=desk.prize_hh,
|
|
||||||
)
|
|
||||||
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 = '<div class="col col-12 col-lg-6">\n'
|
html = '<div class="col col-12 col-lg-6">\n'
|
||||||
html += ' <div class="table-info alert {}">\n'.format(alert)
|
html += ' <div class="table-info alert {}">\n'.format(_get_alert_name(desk))
|
||||||
html += ' <h4 style="text-align: center">({}) {}</h4>\n'.format(desk_no, desk.name)
|
html += ' <h4 style="text-align: center">({}) {}</h4>\n'.format(desk_no, desk.name)
|
||||||
if loc.happy_hour_start is not None and desk.prize_hh is not None:
|
if loc.happy_hour_start is not None and desk.prize_hh is not None:
|
||||||
html += ' <h6 style="text-align: center">Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde</h6>\n' \
|
html += ' <h6 style="text-align: center">Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde</h6>\n' \
|
||||||
@@ -67,3 +49,33 @@ def display_client(client, desk_no):
|
|||||||
html += '</div>\n'
|
html += '</div>\n'
|
||||||
html = format_html(html)
|
html = format_html(html)
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
def _get_alert_name(desk):
|
||||||
|
alert = 'alert-success'
|
||||||
|
acc = desk.accounting_set.all()[:3][::-1]
|
||||||
|
if acc is not None and len(acc) > 0:
|
||||||
|
a = acc[-1]
|
||||||
|
if a.time_to is None:
|
||||||
|
alert = 'alert-info'
|
||||||
|
before5min = datetime.now() - timedelta(minutes=5)
|
||||||
|
if desk.client.last_seen is not None and desk.client.last_seen < before5min:
|
||||||
|
alert = 'alert-danger'
|
||||||
|
return alert
|
||||||
|
|
||||||
|
|
||||||
|
def _calc_prize(desk, acc):
|
||||||
|
if acc is not None and len(acc) > 0:
|
||||||
|
a = acc[-1]
|
||||||
|
if a.time_to is None:
|
||||||
|
prize, u1, u2 = utils.get_prize_for(
|
||||||
|
start=a.time_from,
|
||||||
|
end=datetime.now(),
|
||||||
|
pph=desk.prize,
|
||||||
|
hh_start=desk.client.location.happy_hour_start,
|
||||||
|
hh_end=desk.client.location.happy_hour_end,
|
||||||
|
pphh=desk.prize_hh,
|
||||||
|
)
|
||||||
|
prize = '{0:.2f}'.format(prize)
|
||||||
|
if prize != a.prize:
|
||||||
|
a.prize = prize
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
|
from billard.models import Accounting
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(is_safe=True)
|
||||||
|
def display_daily_sale(location):
|
||||||
|
start_date = datetime.now().replace(hour=5, minute=0, second=0, microsecond=0)
|
||||||
|
end_date = start_date + timedelta(days=1)
|
||||||
|
prize__sum = Accounting.objects.filter(desk__client__location=location,
|
||||||
|
time_to__range=(start_date, end_date)).aggregate(Sum('prize'))
|
||||||
|
if prize__sum['prize__sum'] is None:
|
||||||
|
prize__sum['prize__sum'] = 0
|
||||||
|
return "Tagesumsatz: {0:.2f} EUR".format(prize__sum['prize__sum'])
|
||||||
+2
-2
@@ -25,6 +25,6 @@ urlpatterns = [
|
|||||||
path('<int:loc_pk>/account_modal/<pks>/confirm/', views.account_modal_confirm_view, name='account_modal_confirm'),
|
path('<int:loc_pk>/account_modal/<pks>/confirm/', views.account_modal_confirm_view, name='account_modal_confirm'),
|
||||||
# ex. /billard/api/v1/ (rest api)
|
# ex. /billard/api/v1/ (rest api)
|
||||||
path('api/v1/', include(router.urls)),
|
path('api/v1/', include(router.urls)),
|
||||||
# ex. /billard/process_location_data/
|
# ex. /billard/myaccount/
|
||||||
path('process_location_data/', views.process_location_data, name='process_location_data'),
|
path('my_account', views.UserUpdateView.as_view(), name='my_account'),
|
||||||
]
|
]
|
||||||
|
|||||||
+25
-9
@@ -1,23 +1,25 @@
|
|||||||
import ast
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.urls import reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
from django.views.generic import UpdateView
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
|
||||||
from billard.models import LocationData, Location, Client, Accounting
|
from billard.models import LocationData, Location, Client, Accounting
|
||||||
from billard.serializers import LocationDataSerializer, ClientUpdateLastSeenSerializer
|
from billard.serializers import LocationDataSerializer, ClientUpdateLastSeenSerializer
|
||||||
from billard.tasks import process_location_data
|
from .forms import UserInformationUpdateForm
|
||||||
|
from .tables import LocationTable, LocationAccountingTable
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LocationIndexView(generic.ListView):
|
class LocationIndexView(LoginRequiredMixin, generic.ListView):
|
||||||
template_name = 'billard/location_index.html'
|
template_name = 'billard/location_index.html'
|
||||||
context_object_name = 'location_list'
|
context_object_name = 'location_list'
|
||||||
|
|
||||||
@@ -25,8 +27,17 @@ class LocationIndexView(generic.ListView):
|
|||||||
"""Return the last five published questions."""
|
"""Return the last five published questions."""
|
||||||
return Location.objects.filter(users__id=self.request.user.id).order_by('code')
|
return Location.objects.filter(users__id=self.request.user.id).order_by('code')
|
||||||
|
|
||||||
|
def get_context_data(self, *, object_list=None, **kwargs):
|
||||||
|
context = super().get_context_data(object_list=object_list, **kwargs)
|
||||||
|
table = LocationTable(self.get_queryset())
|
||||||
|
user = self.request.user
|
||||||
|
if user.has_perm('billard.change_accounting'):
|
||||||
|
table = LocationAccountingTable(self.get_queryset())
|
||||||
|
context['table'] = table
|
||||||
|
return context
|
||||||
|
|
||||||
class LocationDetailView(generic.DetailView):
|
|
||||||
|
class LocationDetailView(LoginRequiredMixin, generic.DetailView):
|
||||||
model = Location
|
model = Location
|
||||||
template_name = 'billard/location_detail.html'
|
template_name = 'billard/location_detail.html'
|
||||||
|
|
||||||
@@ -67,7 +78,7 @@ class AccountingView(generic.ListView):
|
|||||||
def accounting_confirm(request, pk):
|
def accounting_confirm(request, pk):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if 'accountings' in request.POST:
|
if 'accountings' in request.POST:
|
||||||
acc_ids = ast.literal_eval(request.POST['accountings'])
|
acc_ids = request.POST.getlist('list_acc_id')
|
||||||
if len(acc_ids) > 0:
|
if len(acc_ids) > 0:
|
||||||
Accounting.objects.filter(id__in=acc_ids).update(
|
Accounting.objects.filter(id__in=acc_ids).update(
|
||||||
billed=True,
|
billed=True,
|
||||||
@@ -113,6 +124,11 @@ class ClientUpdateLastSeenViewSet(viewsets.ModelViewSet):
|
|||||||
serializer_class = ClientUpdateLastSeenSerializer
|
serializer_class = ClientUpdateLastSeenSerializer
|
||||||
|
|
||||||
|
|
||||||
def process_location_data(request):
|
@method_decorator(login_required, name='dispatch')
|
||||||
process_location_data()
|
class UserUpdateView(UpdateView):
|
||||||
return HttpResponse('DONE')
|
form_class = UserInformationUpdateForm
|
||||||
|
template_name = 'registration/my_account.html'
|
||||||
|
success_url = reverse_lazy('billard:my_account')
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
return self.request.user
|
||||||
|
|||||||
@@ -35,10 +35,13 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
# third party apps
|
||||||
|
'crispy_forms',
|
||||||
|
'debug_toolbar',
|
||||||
|
'django_tables2',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework.authtoken',
|
'rest_framework.authtoken',
|
||||||
'debug_toolbar',
|
# carom apps
|
||||||
'crispy_forms',
|
|
||||||
'billard',
|
'billard',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -160,10 +163,12 @@ EMAIL_PORT = 25
|
|||||||
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
||||||
|
|
||||||
PRODUCT_INFO = 'CAROM-DEV'
|
PRODUCT_INFO = 'CAROM-DEV'
|
||||||
PRODUCT_VERSION = 'v 0.5.1'
|
PRODUCT_VERSION = 'v 1.0.0'
|
||||||
|
|
||||||
INTERNAL_IPS = ['127.0.0.1']
|
INTERNAL_IPS = ['127.0.0.1']
|
||||||
|
|
||||||
|
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from local_settings import *
|
from local_settings import *
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ urlpatterns = [
|
|||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
path('billard/', include('billard.urls')),
|
path('billard/', include('billard.urls')),
|
||||||
path('login/', auth_views.login, name='login'),
|
|
||||||
path('logout/', auth_views.logout, name='logout'),
|
|
||||||
path('', include('django.contrib.auth.urls')),
|
path('', include('django.contrib.auth.urls')),
|
||||||
path('', RedirectView.as_view(url='billard/', permanent=False), name='index')
|
path('', RedirectView.as_view(url='billard/', permanent=False), name='index')
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
Django<2.1
|
|
||||||
django-crispy-forms==1.7.0
|
|
||||||
django-extensions>=1.7.0
|
|
||||||
djangorestframework>=3.6.0
|
|
||||||
requests>=2.18.0
|
|
||||||
django-debug-toolbar<2.0.0
|
|
||||||
Vendored
-2050
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
-7
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-330
@@ -1,330 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
line-height: 1.15;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-ms-viewport {
|
|
||||||
width: device-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #212529;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[tabindex="-1"]:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title],
|
|
||||||
abbr[data-original-title] {
|
|
||||||
text-decoration: underline;
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
dl {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol,
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
position: relative;
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #007bff;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: transparent;
|
|
||||||
-webkit-text-decoration-skip: objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #0056b3;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
overflow: auto;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
color: #6c757d;
|
|
||||||
text-align: left;
|
|
||||||
caption-side: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
outline: 1px dotted;
|
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
optgroup,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
html [type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
padding: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="date"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="month"] {
|
|
||||||
-webkit-appearance: listbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: inherit;
|
|
||||||
color: inherit;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
outline-offset: -2px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-cancel-button,
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
font: inherit;
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
output {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
||||||
File diff suppressed because one or more lines are too long
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
|
||||||
File diff suppressed because one or more lines are too long
Vendored
+1718
-806
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-6328
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
-7
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1281
-926
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Vendored
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -36,11 +36,6 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{% url 'billard:location_index' %}">Standorte</a>
|
<a class="nav-link" href="{% url 'billard:location_index' %}">Standorte</a>
|
||||||
</li>
|
</li>
|
||||||
{% if user.is_superuser %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/admin">Administration</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
@@ -50,8 +45,12 @@
|
|||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
|
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
|
||||||
<!-- <a class="dropdown-item" href="#">My account</a> -->
|
<a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||||
<a class="disabled dropdown-item" href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
{% if user.is_superuser %}
|
||||||
|
<a class="dropdown-item" href="/admin">Administration</a>
|
||||||
|
{% endif %}
|
||||||
|
<a class="disabled dropdown-item"
|
||||||
|
href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
|
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
{% extends '_base_accounts.html' %}
|
{% extends '_base.html' %}
|
||||||
|
{% load static from staticfiles %}
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
{% load form_tags %}
|
||||||
{% block title %}login{% endblock %}
|
{% block title %}Anmelden{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center" style="margin-top: 80px;">
|
||||||
<div class="col-lg-4 col-md-6 col-sm-8">
|
<div class="col-lg-4 col-md-6 col-sm-8">
|
||||||
<div class="card">
|
<form method="post" novalidate>
|
||||||
<div class="card-body">
|
{% csrf_token %}
|
||||||
<h3 class="card-title">Log in</h3>
|
<div class="card">
|
||||||
<form method="post" novalidate>
|
<div class="card-header text-center">
|
||||||
{% csrf_token %}
|
<h3>{% settings_value "PRODUCT_INFO" %}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title">Login</h3>
|
||||||
<input type="hidden" name="next" value="{{ next }}">
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
<button type="submit" class="btn btn-primary btn-block">Log in</button>
|
<button type="submit" class="btn btn-primary btn-block">Log in</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{% extends '_base.html' %}
|
||||||
|
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
|
{% block title %}My account{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumb %}
|
||||||
|
<li class="breadcrumb-item active">My account</li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 col-md-8 col-sm-10">
|
||||||
|
<form method="post" novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<button type="submit" class="btn btn-success">Save changes</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user