Merge branch 'release/1.0.0'
This commit is contained in:
commit
d042f8ebed
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,3 +8,5 @@ build/
|
|||||||
*/*/__pycache__/
|
*/*/__pycache__/
|
||||||
caromserver/local_settings.py
|
caromserver/local_settings.py
|
||||||
/staticfiles/
|
/staticfiles/
|
||||||
|
.venv/
|
||||||
|
update.sh
|
||||||
|
18
Pipfile
Normal file
18
Pipfile
Normal file
@ -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"
|
126
Pipfile.lock
generated
Normal file
126
Pipfile.lock
generated
Normal file
@ -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')
|
||||||
|
|
||||||
|
10
billard/forms.py
Normal file
10
billard/forms.py
Normal file
@ -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',)
|
24
billard/migrations/0027_clientdata.py
Normal file
24
billard/migrations/0027_clientdata.py
Normal file
@ -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',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -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')
|
||||||
|
22
billard/tables.py
Normal file
22
billard/tables.py
Normal file
@ -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
|
@ -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,8 +15,12 @@
|
|||||||
|
|
||||||
{{ pk }}
|
{{ pk }}
|
||||||
|
|
||||||
|
|
||||||
|
<form action="confirm/" method="post" id="accounting">
|
||||||
|
{% csrf_token %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th></th>
|
||||||
<th>Start-Datum:</th>
|
<th>Start-Datum:</th>
|
||||||
<th>Stop-Datum:</th>
|
<th>Stop-Datum:</th>
|
||||||
<th>Preis Normal:</th>
|
<th>Preis Normal:</th>
|
||||||
@ -25,6 +29,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% for acc in accounting %}
|
{% for acc in accounting %}
|
||||||
<tr>
|
<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_from }}</td>
|
||||||
<td>{{ acc.time_to }}</td>
|
<td>{{ acc.time_to }}</td>
|
||||||
<td>{{ acc.prize_normal }}</td>
|
<td>{{ acc.prize_normal }}</td>
|
||||||
@ -33,12 +39,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<form action="confirm/" method="post" id="accounting">
|
|
||||||
{% csrf_token %}
|
|
||||||
<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 %}
|
||||||
|
|
||||||
{% if location_list %}
|
|
||||||
<h2>Bitte Standort auswählen:</h2>
|
<h2>Bitte Standort auswählen:</h2>
|
||||||
<table class="table table-hover">
|
{% render_table table %}
|
||||||
<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 %}
|
|
||||||
|
|
||||||
|
|
2
billard/templates/billard/tc_accounting_detail.html
Normal file
2
billard/templates/billard/tc_accounting_detail.html
Normal file
@ -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>
|
3
billard/templates/billard/tc_location_detail.html
Normal file
3
billard/templates/billard/tc_location_detail.html
Normal file
@ -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
|
||||||
|
19
billard/templatetags/display_daily_sale.py
Normal file
19
billard/templatetags/display_daily_sale.py
Normal file
@ -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'])
|
@ -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'),
|
||||||
]
|
]
|
||||||
|
@ -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
|
|
2050
static/css/bootstrap-grid.css
vendored
2050
static/css/bootstrap-grid.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
static/css/bootstrap-grid.min.css
vendored
7
static/css/bootstrap-grid.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
330
static/css/bootstrap-reboot.css
vendored
330
static/css/bootstrap-reboot.css
vendored
@ -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
8
static/css/bootstrap-reboot.min.css
vendored
8
static/css/bootstrap-reboot.min.css
vendored
@ -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
2520
static/css/bootstrap.css
vendored
2520
static/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
4
static/css/bootstrap.min.css
vendored
4
static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6328
static/js/bootstrap.bundle.js
vendored
6328
static/js/bootstrap.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
static/js/bootstrap.bundle.min.js
vendored
7
static/js/bootstrap.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2103
static/js/bootstrap.js
vendored
2103
static/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
4
static/js/bootstrap.min.js
vendored
4
static/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8269
static/js/jquery-3.3.1.slim.js
Normal file
8269
static/js/jquery-3.3.1.slim.js
Normal file
File diff suppressed because it is too large
Load Diff
2
static/js/jquery-3.3.1.slim.min.js
vendored
Normal file
2
static/js/jquery-3.3.1.slim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/jquery-3.3.1.slim.min.map
Normal file
1
static/js/jquery-3.3.1.slim.min.map
Normal file
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">
|
|
||||||
<div class="card-body">
|
|
||||||
<h3 class="card-title">Log in</h3>
|
|
||||||
<form method="post" novalidate>
|
<form method="post" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-center">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
21
templates/registration/my_account.html
Normal file
21
templates/registration/my_account.html
Normal file
@ -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 %}
|
Loading…
Reference in New Issue
Block a user