Merge branch 'release/0.2.0'
This commit is contained in:
		@@ -57,4 +57,8 @@ class DeskAdmin(admin.ModelAdmin):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@admin.register(Accounting)
 | 
					@admin.register(Accounting)
 | 
				
			||||||
class AccountingAdmin(admin.ModelAdmin):
 | 
					class AccountingAdmin(admin.ModelAdmin):
 | 
				
			||||||
    list_display = ('desk', 'time_from', 'time_to', 'prize', 'billed')
 | 
					    list_display = ('desk', 'time_from', 'time_to', 'prize', 'billed', 'account_user', 'account_tst')
 | 
				
			||||||
 | 
					    list_filter = ('desk__client__location', 'account_user', 'account_tst', 'billed')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def has_add_permission(self, request):
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ class Migration(migrations.Migration):
 | 
				
			|||||||
    initial = True
 | 
					    initial = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dependencies = [
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('sessions', '0001_initial'),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    operations = [
 | 
					    operations = [
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								billard/migrations/0021_accounting_account_user.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								billard/migrations/0021_accounting_account_user.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.11 on 2017-04-26 10:17
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('billard', '0020_auto_20170410_1853'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='accounting',
 | 
				
			||||||
 | 
					            name='account_user',
 | 
				
			||||||
 | 
					            field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Abr. Benutzer'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										21
									
								
								billard/migrations/0022_auto_20170427_0835.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								billard/migrations/0022_auto_20170427_0835.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.11 on 2017-04-27 08:35
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('billard', '0021_accounting_account_user'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='client',
 | 
				
			||||||
 | 
					            name='location',
 | 
				
			||||||
 | 
					            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='clients', to='billard.Location', verbose_name='Standort'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										20
									
								
								billard/migrations/0023_accounting_account_tst.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								billard/migrations/0023_accounting_account_tst.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.11 on 2017-04-29 11:09
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('billard', '0022_auto_20170427_0835'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='accounting',
 | 
				
			||||||
 | 
					            name='account_tst',
 | 
				
			||||||
 | 
					            field=models.DateTimeField(blank=True, null=True, verbose_name='Abr. TST'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -2,8 +2,6 @@ import uuid
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
from datetime import datetime, timezone
 | 
					 | 
				
			||||||
from billard import utils
 | 
					 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
from django.db.models.signals import post_save
 | 
					from django.db.models.signals import post_save
 | 
				
			||||||
from django.dispatch import receiver
 | 
					from django.dispatch import receiver
 | 
				
			||||||
@@ -50,7 +48,7 @@ class Location(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Client(models.Model):
 | 
					class Client(models.Model):
 | 
				
			||||||
    uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier")
 | 
					    uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier")
 | 
				
			||||||
    location = models.ForeignKey(Location, verbose_name="Standort")
 | 
					    location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort")
 | 
				
			||||||
    report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients')
 | 
					    report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
@@ -70,7 +68,6 @@ class Desk(models.Model):
 | 
				
			|||||||
    prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True,
 | 
					    prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True,
 | 
				
			||||||
                                   verbose_name="Preis Happy Hour")
 | 
					                                   verbose_name="Preis Happy Hour")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return '{}, {}'.format(self.client.uuid, self.name)
 | 
					        return '{}, {}'.format(self.client.uuid, self.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,6 +85,8 @@ class Accounting(models.Model):
 | 
				
			|||||||
    reporter_uuid = models.UUIDField(blank=True, null=True, verbose_name='Reporter UUID')
 | 
					    reporter_uuid = models.UUIDField(blank=True, null=True, verbose_name='Reporter UUID')
 | 
				
			||||||
    prize_normal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Normalzeit")
 | 
					    prize_normal = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Normalzeit")
 | 
				
			||||||
    prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Happy Hour")
 | 
					    prize_hh = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True, verbose_name="Preis Happy Hour")
 | 
				
			||||||
 | 
					    account_user = models.CharField(blank=True, null=True, max_length=128, verbose_name="Abr. Benutzer")
 | 
				
			||||||
 | 
					    account_tst = models.DateTimeField(blank=True, null=True, verbose_name="Abr. TST")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return '{}: {} -> {}, {}, {}'.format(self.desk, self.time_from, self.time_to, self.prize, self.billed)
 | 
					        return '{}: {} -> {}, {}, {}'.format(self.desk, self.time_from, self.time_to, self.prize, self.billed)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +1,14 @@
 | 
				
			|||||||
{% extends 'billard/base.html' %}
 | 
					{% extends 'billard/base.html' %}
 | 
				
			||||||
{% load display_client %}
 | 
					{% load display_client %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}Accounting Data{% endblock %}
 | 
					{% block title %}Abrechnung{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
{% if not locations|length_is:"1" %}
 | 
					 | 
				
			||||||
    <form action="accounting" 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 class="alert alert-success" role="alert">Gesamt-Summe: {{ acc_sum }}</div>
 | 
					    <div class="alert alert-success" role="alert">Gesamt-Summe: {{ acc_sum }}</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {{ pk }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <table class="table">
 | 
					    <table class="table">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <th>Start-Datum:</th>
 | 
					            <th>Start-Datum:</th>
 | 
				
			||||||
@@ -38,7 +28,7 @@
 | 
				
			|||||||
{% endfor %}
 | 
					{% endfor %}
 | 
				
			||||||
    </table>
 | 
					    </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <form action="accounting" method="post" id="accounting">
 | 
					    <form action="confirm/" method="post" id="accounting">
 | 
				
			||||||
{% csrf_token %}
 | 
					{% 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 }}">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="modal-footer">
 | 
					      <div class="modal-footer">
 | 
				
			||||||
        <a class="btn btn-default btn-primary" href="{% url 'accountmodalconfirm' account.pk %}">Schliessen</a>
 | 
					        <a class="btn btn-default btn-primary" href="{% url 'billard:account_modal_confirm' pk=account.id loc_pk=loc_pk %}">Schliessen</a>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div><!-- /.modal-content -->
 | 
					    </div><!-- /.modal-content -->
 | 
				
			||||||
  </div><!-- /.modal-dialog -->
 | 
					  </div><!-- /.modal-dialog -->
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
    <meta charset="utf-8">
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
    <title>{% block title %}TITLE SETZEN{% endblock %}</title>
 | 
					    <title>carom - {% block title %}TITLE SETZEN{% endblock %}</title>
 | 
				
			||||||
    <meta name="description" content="">
 | 
					    <meta name="description" content="">
 | 
				
			||||||
    <meta name="author" content="">
 | 
					    <meta name="author" content="">
 | 
				
			||||||
{% block header %}
 | 
					{% block header %}
 | 
				
			||||||
@@ -28,10 +28,7 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div id="navbar" class="collapse navbar-collapse">
 | 
					            <div id="navbar" class="collapse navbar-collapse">
 | 
				
			||||||
                <ul class="nav navbar-nav">
 | 
					                <ul class="nav navbar-nav">
 | 
				
			||||||
                    <li class="{% ifequal request.path '/billard/' %}active{% endifequal %}"><a href="{% url "carom_index" %}">Tische</a></li>
 | 
					                    <li class="{% ifequal request.path '/billard/' %}active{% endifequal %}"><a href="{% url "billard:location_index" %}">Standorte</a></li>
 | 
				
			||||||
{% if perms.billard.change_accounting %}
 | 
					 | 
				
			||||||
                    <li class="{% ifequal request.path '/billard/accounting' %}active{% endifequal %}"><a href="{% url "accounting" %}">Abrechnung</a></li>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
{% if user.is_superuser %}
 | 
					{% if user.is_superuser %}
 | 
				
			||||||
                    <li class="{% ifequal request.path '/logout/' %}active{% endifequal %}"><a href="/admin/">Administration</a></li>
 | 
					                    <li class="{% ifequal request.path '/logout/' %}active{% endifequal %}"><a href="/admin/">Administration</a></li>
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
@@ -47,7 +44,7 @@
 | 
				
			|||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
                </ul>
 | 
					                </ul>
 | 
				
			||||||
                <ul class="nav navbar-nav navbar-right">
 | 
					                <ul class="nav navbar-nav navbar-right">
 | 
				
			||||||
                    <li><a href="#">c@0.0.1</a></li>
 | 
					                    <li><a href="#">rel. c@0.2.0</a></li>
 | 
				
			||||||
                </ul>
 | 
					                </ul>
 | 
				
			||||||
            </div><!--/.nav-collapse -->
 | 
					            </div><!--/.nav-collapse -->
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,17 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div id="desk_data">
 | 
					    <div id="desk_data">
 | 
				
			||||||
{% include 'billard/index_ajax.html' %}
 | 
					{% include 'billard/index_ajax.html' %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div id="modal-wrapper">
 | 
					    <div id="modal-wrapper">
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block js %}
 | 
					{% block js %}
 | 
				
			||||||
    <script type="text/javascript">
 | 
					    <script type="text/javascript">
 | 
				
			||||||
    var interval;
 | 
					    var interval;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								billard/templates/billard/location_detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								billard/templates/billard/location_detail.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					{% extends 'billard/base.html' %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block title %}Standort{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <div id="desk_data">
 | 
				
			||||||
 | 
					{% include 'billard/location_detail_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 'billard:account_modal' loc_pk=pk %}', function() {
 | 
				
			||||||
 | 
					        if ( $('#accountsmodal').length ) {
 | 
				
			||||||
 | 
					            window.clearInterval(interval);
 | 
				
			||||||
 | 
					            $('#accountsmodal').modal('show');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										12
									
								
								billard/templates/billard/location_detail_ajax.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								billard/templates/billard/location_detail_ajax.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					{% load display_client %}
 | 
				
			||||||
 | 
					{% if location.clients.all %}
 | 
				
			||||||
 | 
					{% for cli in location.clients.all %}
 | 
				
			||||||
 | 
					{% for i in "12345678" %}
 | 
				
			||||||
 | 
					    {{ cli|display_client:i }}
 | 
				
			||||||
 | 
					{% endfor %}
 | 
				
			||||||
 | 
					{% endfor %}
 | 
				
			||||||
 | 
					{% else %}
 | 
				
			||||||
 | 
					<div class="col-md-12">
 | 
				
			||||||
 | 
					    <div class="col-md-12 alert alert-danger">Keine Tische angelegt!</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
							
								
								
									
										37
									
								
								billard/templates/billard/location_index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								billard/templates/billard/location_index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					{% extends 'billard/base.html' %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block title %}Standortliste{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if location_list %}
 | 
				
			||||||
 | 
					    <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-primary">{{ 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-primary">Abrechnen</a></td>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					{% endfor %}
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					{% else %}
 | 
				
			||||||
 | 
					    <p>Keine Standorte Zugeordnet.</p>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -1,16 +1,28 @@
 | 
				
			|||||||
from django.conf.urls import url, include
 | 
					from django.conf.urls import url, include
 | 
				
			||||||
 | 
					from django.contrib.auth.decorators import login_required
 | 
				
			||||||
from rest_framework import routers
 | 
					from rest_framework import routers
 | 
				
			||||||
from billard import views
 | 
					from billard import views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = routers.DefaultRouter()
 | 
					router = routers.DefaultRouter()
 | 
				
			||||||
router.register(r'location_data', views.LocationDataViewSet)
 | 
					router.register(r'location_data', views.LocationDataViewSet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app_name = 'billard'
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    url(r'^$', views.index, name='carom_index'),
 | 
					    # ex. /billard/
 | 
				
			||||||
    url(r'^(?P<pk>[0-9]+)/$', views.LocationDataDetailView.as_view(), name='detail'),
 | 
					    url(r'^$', login_required(views.LocationIndexView.as_view()), name='location_index'),
 | 
				
			||||||
 | 
					    # ex. /billard/1/
 | 
				
			||||||
 | 
					    url(r'^(?P<pk>[0-9]+)/$', login_required(views.LocationDetailView.as_view()), name='location_detail'),
 | 
				
			||||||
 | 
					    # ex. /billard/1/accounting/
 | 
				
			||||||
 | 
					    url(r'^(?P<pk>[0-9]+)/accounting/$', views.AccountingView.as_view(), name='accounting_detail'),
 | 
				
			||||||
 | 
					    # ex. /billard/1/accounting/confirm
 | 
				
			||||||
 | 
					    url(r'^(?P<pk>[0-9]+)/accounting/confirm/$', views.accounting_confirm, name='accounting_detail_confirm'),
 | 
				
			||||||
 | 
					    # ex. /billard/1/account_modal/
 | 
				
			||||||
 | 
					    url(r'^(?P<loc_pk>[0-9]+)/account_modal/$', views.account_modal_view, name='account_modal'),
 | 
				
			||||||
 | 
					    # ex. /billard/1/account_modal/confirm/
 | 
				
			||||||
 | 
					    url(r'^(?P<loc_pk>[0-9]+)/account_modal/(?P<pk>[0-9]+)/confirm/$', views.account_modal_confirm_view,
 | 
				
			||||||
 | 
					        name='account_modal_confirm'),
 | 
				
			||||||
 | 
					    # ex. /billard/api/v1/ (rest api)
 | 
				
			||||||
    url(r'api/v1/', include(router.urls)),
 | 
					    url(r'api/v1/', include(router.urls)),
 | 
				
			||||||
    url(r'process_locationdata', views.process_locationdata, name='process_locationdata'),
 | 
					    # ex. /billard/process_location_data/
 | 
				
			||||||
    url(r'accounting', views.accounting, name='accounting'),
 | 
					    url(r'^process_location_data/$', views.process_location_data, name='process_location_data'),
 | 
				
			||||||
    url(r'accountmodal$', views.accountmodalview, name='accountmodal'),
 | 
					 | 
				
			||||||
    url(r'accoutmodal/confirm/(?P<pk>[0-9]+)$', views.accountmodalconfirmview, name="accountmodalconfirm")
 | 
					 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										216
									
								
								billard/views.py
									
									
									
									
									
								
							
							
						
						
									
										216
									
								
								billard/views.py
									
									
									
									
									
								
							@@ -1,13 +1,96 @@
 | 
				
			|||||||
 | 
					import ast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from billard.serializers import LocationDataSerializer
 | 
					from billard.serializers import LocationDataSerializer
 | 
				
			||||||
from billard.models import LocationData, Location, Client, Accounting
 | 
					from billard.models import LocationData, Location, Client, Accounting
 | 
				
			||||||
from billard.tasks import process_location_data
 | 
					from billard.tasks import process_location_data
 | 
				
			||||||
from rest_framework import viewsets
 | 
					from rest_framework import viewsets
 | 
				
			||||||
from django.shortcuts import render, redirect
 | 
					from django.shortcuts import render, redirect
 | 
				
			||||||
from django.views import generic
 | 
					from django.views import generic
 | 
				
			||||||
from django.views.generic.detail import DetailView
 | 
					 | 
				
			||||||
from django.contrib.auth.decorators import login_required, permission_required
 | 
					from django.contrib.auth.decorators import login_required, permission_required
 | 
				
			||||||
from django.db.models import Min, Sum
 | 
					from django.db.models import Sum
 | 
				
			||||||
from django.http import HttpResponse
 | 
					from django.http import HttpResponse
 | 
				
			||||||
 | 
					from django.utils.decorators import method_decorator
 | 
				
			||||||
 | 
					from django.utils import timezone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LocationIndexView(generic.ListView):
 | 
				
			||||||
 | 
					    template_name = 'billard/location_index.html'
 | 
				
			||||||
 | 
					    context_object_name = 'location_list'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_queryset(self):
 | 
				
			||||||
 | 
					        """Return the last five published questions."""
 | 
				
			||||||
 | 
					        return Location.objects.filter(users__id=self.request.user.id).order_by('code')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LocationDetailView(generic.DetailView):
 | 
				
			||||||
 | 
					    model = Location
 | 
				
			||||||
 | 
					    template_name = 'billard/location_detail.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        if request.is_ajax():
 | 
				
			||||||
 | 
					            context = {
 | 
				
			||||||
 | 
					                'location': self.get_object(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return render(request, template_name='billard/location_detail_ajax.html', context=context)
 | 
				
			||||||
 | 
					        result = super(LocationDetailView, self).dispatch(request, *args, **kwargs)
 | 
				
			||||||
 | 
					        result.context_data['pk'] = self.kwargs['pk']
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					class AccountingView(generic.ListView):
 | 
				
			||||||
 | 
					    template_name = 'billard/accounting.html'
 | 
				
			||||||
 | 
					    context_object_name = 'accounting'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_queryset(self):
 | 
				
			||||||
 | 
					        return Accounting.objects.filter(billed=False).exclude(time_to__isnull=True).order_by('time_from')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        result = super(AccountingView, self).dispatch(request, *args, **kwargs)
 | 
				
			||||||
 | 
					        acc_sum = self.get_queryset().aggregate(Sum('prize'))
 | 
				
			||||||
 | 
					        if acc_sum['prize__sum'] is None:
 | 
				
			||||||
 | 
					            result.context_data['acc_sum'] = 0
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            result.context_data['acc_sum'] = acc_sum['prize__sum']
 | 
				
			||||||
 | 
					        result.context_data['acc_ids'] = [acc.id for acc in self.get_queryset().all()]
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					@permission_required('billard.change_accounting')
 | 
				
			||||||
 | 
					def accounting_confirm(request, pk):
 | 
				
			||||||
 | 
					    if request.method == 'POST':
 | 
				
			||||||
 | 
					        if 'accountings' in request.POST:
 | 
				
			||||||
 | 
					            acc_ids = ast.literal_eval(request.POST['accountings'])
 | 
				
			||||||
 | 
					            if len(acc_ids) > 0:
 | 
				
			||||||
 | 
					                Accounting.objects.filter(id__in=acc_ids).update(billed=True)
 | 
				
			||||||
 | 
					                Accounting.objects.filter(id__in=acc_ids).update(account_user=request.user.username)
 | 
				
			||||||
 | 
					                Accounting.objects.filter(id__in=acc_ids).update(account_tst=timezone.now())
 | 
				
			||||||
 | 
					    resp = redirect('billard:accounting_detail', pk=pk)
 | 
				
			||||||
 | 
					    return resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def account_modal_view(request, loc_pk):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        uuids = Client.objects.filter(report_user=request.user).values_list('uuid')
 | 
				
			||||||
 | 
					        account = Accounting.objects.filter(reporter_uuid__in=uuids).first
 | 
				
			||||||
 | 
					        # TODO: support multiple account objects
 | 
				
			||||||
 | 
					    except Client.DoesNotExist:
 | 
				
			||||||
 | 
					        account = None
 | 
				
			||||||
 | 
					    context = {
 | 
				
			||||||
 | 
					        'account': account,
 | 
				
			||||||
 | 
					        'loc_pk': loc_pk,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return render(request, 'billard/accountmodal.html', context=context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def account_modal_confirm_view(request, loc_pk, pk):
 | 
				
			||||||
 | 
					    account = Accounting.objects.get(pk=pk)
 | 
				
			||||||
 | 
					    account.reporter_uuid = None
 | 
				
			||||||
 | 
					    account.save()
 | 
				
			||||||
 | 
					    return redirect('billard:location_detail', pk=loc_pk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LocationDataViewSet(viewsets.ModelViewSet):
 | 
					class LocationDataViewSet(viewsets.ModelViewSet):
 | 
				
			||||||
@@ -15,133 +98,6 @@ class LocationDataViewSet(viewsets.ModelViewSet):
 | 
				
			|||||||
    serializer_class = LocationDataSerializer
 | 
					    serializer_class = LocationDataSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IndexView(generic.ListView):
 | 
					def process_location_data(request):
 | 
				
			||||||
    model = LocationData
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_template_names(self):
 | 
					 | 
				
			||||||
        if self.request.is_ajax():
 | 
					 | 
				
			||||||
            return ('billard/locationdata_list_ajax.html',)
 | 
					 | 
				
			||||||
        return super().get_template_names()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LocationDataDetailView(DetailView):
 | 
					 | 
				
			||||||
    model = LocationData
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_template_names(self):
 | 
					 | 
				
			||||||
        if self.request.is_ajax():
 | 
					 | 
				
			||||||
            return ('billard/locationdata_detail_ajax.html',)
 | 
					 | 
				
			||||||
        return super().get_template_names()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@login_required
 | 
					 | 
				
			||||||
def accountmodalview(request):
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        uuids = Client.objects.filter(report_user=request.user).values_list('uuid')
 | 
					 | 
				
			||||||
        account = Accounting.objects.filter(reporter_uuid__in=uuids).first
 | 
					 | 
				
			||||||
        #TODO: support multiple account objects
 | 
					 | 
				
			||||||
    except Client.DoesNotExist:
 | 
					 | 
				
			||||||
        account = None
 | 
					 | 
				
			||||||
    context = {
 | 
					 | 
				
			||||||
        'account': account
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return render(request, 'billard/accountmodal.html', context=context)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@login_required
 | 
					 | 
				
			||||||
def accountmodalconfirmview(request, pk):
 | 
					 | 
				
			||||||
    account = Accounting.objects.get(pk=pk)
 | 
					 | 
				
			||||||
    account.reporter_uuid = None
 | 
					 | 
				
			||||||
    account.save()
 | 
					 | 
				
			||||||
    return redirect('carom_index')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@login_required
 | 
					 | 
				
			||||||
@permission_required('billard.change_accounting')
 | 
					 | 
				
			||||||
def accounting(request):
 | 
					 | 
				
			||||||
    if request.method == 'GET':
 | 
					 | 
				
			||||||
        template = 'billard/accounting.html'
 | 
					 | 
				
			||||||
        loc = None
 | 
					 | 
				
			||||||
        min_loc = Location.objects.filter(users__id=request.user.id).aggregate(Min('id'))['id__min']
 | 
					 | 
				
			||||||
        if 'loc' in request.GET:
 | 
					 | 
				
			||||||
            loc = request.GET['loc']
 | 
					 | 
				
			||||||
        if not Location.objects.filter(users__id=request.user.id).filter(id=loc).exists():
 | 
					 | 
				
			||||||
            resp = redirect('accounting')
 | 
					 | 
				
			||||||
            if min_loc is not None:
 | 
					 | 
				
			||||||
                resp['Location'] += '?loc={}'.format(str(min_loc))
 | 
					 | 
				
			||||||
                request.session['loc'] = str(min_loc)
 | 
					 | 
				
			||||||
                return resp
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                return render(request, accounting)
 | 
					 | 
				
			||||||
        if loc is None:
 | 
					 | 
				
			||||||
            loc = min_loc
 | 
					 | 
				
			||||||
        locations = Location.objects.filter(users__id=request.user.id).order_by('code')
 | 
					 | 
				
			||||||
        acc = Accounting.objects.filter(billed=False).exclude(time_to__isnull=True).\
 | 
					 | 
				
			||||||
            filter(desk__client__location_id=loc).order_by('-time_from')
 | 
					 | 
				
			||||||
        acc_sum = acc.aggregate(Sum('prize'))
 | 
					 | 
				
			||||||
        acc_ids = list()
 | 
					 | 
				
			||||||
        for a in acc:
 | 
					 | 
				
			||||||
            acc_ids.append(a.id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context = {
 | 
					 | 
				
			||||||
            'location_id': int(loc),
 | 
					 | 
				
			||||||
            'locations': locations,
 | 
					 | 
				
			||||||
            'accounting': acc,
 | 
					 | 
				
			||||||
            'acc_ids': ','.join(str(e) for e in acc_ids),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if acc_sum['prize__sum'] is None:
 | 
					 | 
				
			||||||
            context['acc_sum'] = 0
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            context['acc_sum'] = acc_sum['prize__sum']
 | 
					 | 
				
			||||||
        return render(request, template_name=template, context=context)
 | 
					 | 
				
			||||||
    if request.method == 'POST':
 | 
					 | 
				
			||||||
        loc = request.POST['location-selector']
 | 
					 | 
				
			||||||
        if 'accountings' in request.POST:
 | 
					 | 
				
			||||||
            acc_ids = request.POST['accountings'].split(',')
 | 
					 | 
				
			||||||
            Accounting.objects.filter(id__in=acc_ids).update(billed=True)
 | 
					 | 
				
			||||||
        request.session['loc'] = str(loc)
 | 
					 | 
				
			||||||
        resp = redirect('accounting')
 | 
					 | 
				
			||||||
        resp['Location'] += '?loc={}'.format(str(loc))
 | 
					 | 
				
			||||||
        return resp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@login_required
 | 
					 | 
				
			||||||
def index(request):
 | 
					 | 
				
			||||||
    if request.method == 'GET':
 | 
					 | 
				
			||||||
        template = 'billard/index.html'
 | 
					 | 
				
			||||||
        loc = None
 | 
					 | 
				
			||||||
        if request.is_ajax():
 | 
					 | 
				
			||||||
            template = 'billard/index_ajax.html'
 | 
					 | 
				
			||||||
            loc = request.session.get('loc')
 | 
					 | 
				
			||||||
        min_loc = Location.objects.filter(users__id=request.user.id).aggregate(Min('id'))['id__min']
 | 
					 | 
				
			||||||
        if 'loc' in request.GET:
 | 
					 | 
				
			||||||
            loc = request.GET['loc']
 | 
					 | 
				
			||||||
        if not Location.objects.filter(users__id=request.user.id).filter(id=loc).exists():
 | 
					 | 
				
			||||||
            resp = redirect('carom_index')
 | 
					 | 
				
			||||||
            if min_loc is not None:
 | 
					 | 
				
			||||||
                resp['Location'] += '?loc={}'.format(str(min_loc))
 | 
					 | 
				
			||||||
                request.session['loc'] = str(min_loc)
 | 
					 | 
				
			||||||
                return resp
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                return render(request, template)
 | 
					 | 
				
			||||||
        if loc is None:
 | 
					 | 
				
			||||||
            loc = min_loc
 | 
					 | 
				
			||||||
        locations = Location.objects.filter(users__id=request.user.id).order_by('code')
 | 
					 | 
				
			||||||
        clients = Client.objects.filter(location_id=loc).order_by('id')
 | 
					 | 
				
			||||||
        context = {
 | 
					 | 
				
			||||||
            'range': range(1, 9),
 | 
					 | 
				
			||||||
            'locations': locations,
 | 
					 | 
				
			||||||
            'clients': clients,
 | 
					 | 
				
			||||||
            'location_id': int(loc),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return render(request, template, context=context)
 | 
					 | 
				
			||||||
    if request.method == 'POST':
 | 
					 | 
				
			||||||
        loc = request.POST['location-selector']
 | 
					 | 
				
			||||||
        request.session['loc'] = str(loc)
 | 
					 | 
				
			||||||
        resp = redirect('carom_index')
 | 
					 | 
				
			||||||
        resp['Location'] += '?loc={}'.format(str(loc))
 | 
					 | 
				
			||||||
        return resp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def process_locationdata(request):
 | 
					 | 
				
			||||||
    process_location_data()
 | 
					    process_location_data()
 | 
				
			||||||
    return HttpResponse('DONE')
 | 
					    return HttpResponse('DONE')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -135,8 +135,8 @@ REST_FRAMEWORK = {
 | 
				
			|||||||
CRISPY_TEMPLATE_PACK = 'bootstrap3'
 | 
					CRISPY_TEMPLATE_PACK = 'bootstrap3'
 | 
				
			||||||
LOGIN_URL = 'login'
 | 
					LOGIN_URL = 'login'
 | 
				
			||||||
LOGOUT_URL = 'logout'
 | 
					LOGOUT_URL = 'logout'
 | 
				
			||||||
LOGIN_REDIRECT_URL = 'carom_index'
 | 
					LOGIN_REDIRECT_URL = 'billard:location_index'
 | 
				
			||||||
LOGOUT_REDIRECT_URL = 'carom_index'
 | 
					LOGOUT_REDIRECT_URL = 'billard:location_index'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CELERY STUFF
 | 
					# CELERY STUFF
 | 
				
			||||||
BROKER_URL = 'redis://localhost:6379'
 | 
					BROKER_URL = 'redis://localhost:6379'
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user