3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-11-26 06:32:27 +00:00

Merge branch 'release-3.3.0' into 'master'

Release 3.3.0

Closes #29, #30, #31, #32, #34, #35, #36, #37, #38, and #39

See merge request coope/coopev3!7
This commit is contained in:
Nanoy 2019-01-23 10:59:22 +01:00
commit 9364838c34
50 changed files with 3542 additions and 230 deletions

1
.gitignore vendored
View file

@ -42,3 +42,4 @@ tags
.vscode .vscode
venv venv
static/ static/
Pipfile

View file

@ -1,3 +1,15 @@
## v3.3.0
* Ajout d'icônes
* Le . est utilisé pour les décimaux
* Ajout de liens vers les profils de produits et utilisateurs
* Ajout de cotisations dans les transactions
* Ajout d'une page d'accueil. Les pressions du moment y sont affichées
* Belles couleurs sur le diagramme
* Verouillage automatique de la caisse
* Classement par produit
* Fix invalidation
* Recherche plus intuitive (le startswith devient contains)
* Easter egg sur 404
## v3.2.2 ## v3.2.2
* Fix cotisation cancer * Fix cotisation cancer
## v3.2.1 ## v3.2.1

View file

@ -39,3 +39,9 @@ def global_message():
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
messages = gp.global_message.split("\n") messages = gp.global_message.split("\n")
return random.choice(messages) return random.choice(messages)
@register.simple_tag
def logout_time():
gp, _ = GeneralPreferences.objects.get_or_create(pk=1)
logout_time = gp.automatic_logout_time
return logout_time

View file

@ -20,6 +20,8 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.home, name="home"), path('', views.home, name="home"),
path('home', views.homepage, name="homepage"),
path('coope-runner', views.coope_runner, name="coope-runner"),
path('admin/doc/', include('django.contrib.admindocs.urls')), path('admin/doc/', include('django.contrib.admindocs.urls')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('users/', include('users.urls')), path('users/', include('users.urls')),

View file

@ -1,11 +1,22 @@
from django.shortcuts import redirect from django.shortcuts import redirect, render
from django.urls import reverse from django.urls import reverse
from preferences.models import GeneralPreferences
from gestion.models import Keg
def home(request): def home(request):
if request.user.is_authenticated: if request.user.is_authenticated:
if(request.user.has_perm('gestion.can_manage')): if(request.user.has_perm('gestion.can_manage')):
return redirect(reverse('gestion:manage')) return redirect(reverse('gestion:manage'))
else: else:
return redirect(reverse('users:profile', kwargs={'pk': request.user.pk})) return redirect(reverse('homepage'))
else: else:
return redirect(reverse('users:login')) return redirect(reverse('users:login'))
def homepage(request):
gp, _ = GeneralPreferences.objects.get_or_create(pk=1)
kegs = Keg.objects.filter(is_active=True)
return render(request, "home.html", {"home_text": gp.home_text, "kegs": kegs})
def coope_runner(request):
return render(request, "coope-runner.html")

View file

@ -16,20 +16,21 @@ class ReloadForm(forms.ModelForm):
class Meta: class Meta:
model = Reload model = Reload
fields = ("customer", "amount", "PaymentMethod") fields = ("customer", "amount", "PaymentMethod")
widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2})} widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2}), 'amount': forms.TextInput}
class RefundForm(forms.ModelForm): class RefundForm(forms.ModelForm):
class Meta: class Meta:
model = Refund model = Refund
fields = ("customer", "amount") fields = ("customer", "amount")
widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2})} widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2}), 'amount': forms.TextInput}
class ProductForm(forms.ModelForm): class ProductForm(forms.ModelForm):
class Meta: class Meta:
model = Product model = Product
fields = "__all__" fields = "__all__"
widgets = {'amount': forms.TextInput}
class KegForm(forms.ModelForm): class KegForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -41,11 +42,13 @@ class KegForm(forms.ModelForm):
class Meta: class Meta:
model = Keg model = Keg
exclude = ("is_active", ) exclude = ("is_active", )
widgets = {'amount': forms.TextInput}
class MenuForm(forms.ModelForm): class MenuForm(forms.ModelForm):
class Meta: class Meta:
model = Menu model = Menu
fields = "__all__" fields = "__all__"
widgets = {'amount': forms.TextInput}
class SearchProductForm(forms.Form): class SearchProductForm(forms.Form):
product = forms.ModelChoiceField(queryset=Product.objects.all(), required=True, label="Produit", widget=autocomplete.ModelSelect2(url='gestion:products-autocomplete', attrs={'data-minimum-input-length':2})) product = forms.ModelChoiceField(queryset=Product.objects.all(), required=True, label="Produit", widget=autocomplete.ModelSelect2(url='gestion:products-autocomplete', attrs={'data-minimum-input-length':2}))

View file

@ -45,6 +45,22 @@ class Product(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
def user_ranking(self, pk):
user = User.objects.get(pk=pk)
consumptions = ConsumptionHistory.objects.filter(customer=user).filter(product=self)
# add menu
nb = 0
for consumption in consumptions:
nb += consumption.quantity
return (user, nb)
@property
def ranking(self):
users = User.objects.all()
ranking = [self.user_ranking(user.pk) for user in users]
ranking.sort(key=lambda x:x[1], reverse=True)
return ranking[0:25]
def isPinte(id): def isPinte(id):
product = Product.objects.get(id=id) product = Product.objects.get(id=id)

View file

@ -13,13 +13,13 @@
<h2>Liste des fûts actifs</h2> <h2>Liste des fûts actifs</h2>
</header> </header>
{% if perms.gestion.add_keg %} {% if perms.gestion.add_keg %}
<a class="button" href="{% url 'gestion:addKeg' %}">Créer un fût</a> <a class="button" href="{% url 'gestion:addKeg' %}"><i class="fa fa-plus-square"></i> Créer un fût</a>
{% endif %} {% endif %}
{% if perms.gestion.open_keg %} {% if perms.gestion.open_keg %}
<a class="button" href="{% url 'gestion:openKeg' %}">Percuter un fût</a> <a class="button" href="{% url 'gestion:openKeg' %}"><i class="fa fa-fill-drip"></i> Percuter un fût</a>
{% endif %} {% endif %}
{% if perms.gestion.close_keg %} {% if perms.gestion.close_keg %}
<a class="button" href="{% url 'gestion:closeKeg' %}">Fermer un fût</a> <a class="button" href="{% url 'gestion:closeKeg' %}"><i class="fa fa-fill"></i> Fermer un fût</a>
{% endif %} {% endif %}
<br><br> <br><br>
<div class="table-wrapper"> <div class="table-wrapper">
@ -33,6 +33,7 @@
<th>Quantité vendue</th> <th>Quantité vendue</th>
<th>Montant vendu</th> <th>Montant vendu</th>
<th>Prix du fût</th> <th>Prix du fût</th>
<th>Degré</th>
<th>Historique</th> <th>Historique</th>
<th>Administrer</th> <th>Administrer</th>
</tr> </tr>
@ -47,8 +48,9 @@
<td>{{ kegH.quantitySold }} L</td> <td>{{ kegH.quantitySold }} L</td>
<td>{{ kegH.amountSold }} €</td> <td>{{ kegH.amountSold }} €</td>
<td>{{ kegH.keg.amount }} €</td> <td>{{ kegH.keg.amount }} €</td>
<td>{{ kegH.keg.pinte.deg }}°</td>
<td><a href="{% url 'gestion:kegH' kegH.keg.pk %}">Voir</a></td> <td><a href="{% url 'gestion:kegH' kegH.keg.pk %}">Voir</a></td>
<td>{% if perms.gestion.close_keg %}<a href="{% url 'gestion:closeDirectKeg' kegH.keg.pk %}" class="button small">Fermer</a> {% endif %}{% if perms.gestion.change_keg %}<a href="{% url 'gestion:editKeg' kegH.keg.pk %}" class="button small">Modifier</a>{% endif %}</td> <td>{% if perms.gestion.close_keg %}<a href="{% url 'gestion:closeDirectKeg' kegH.keg.pk %}" class="button small"><i class="fa fa-fill"></i> Fermer</a> {% endif %}{% if perms.gestion.change_keg %}<a href="{% url 'gestion:editKeg' kegH.keg.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -60,13 +62,13 @@
<h2>Liste des fûts inactifs</h2> <h2>Liste des fûts inactifs</h2>
</header> </header>
{% if perms.gestion.add_keg %} {% if perms.gestion.add_keg %}
<a class="button" href="{% url 'gestion:addKeg' %}">Créer un fût</a> <a class="button" href="{% url 'gestion:addKeg' %}"><i class="fa fa-plus-square"></i> Créer un fût</a>
{% endif %} {% endif %}
{% if perms.gestion.open_keg %} {% if perms.gestion.open_keg %}
<a class="button" href="{% url 'gestion:openKeg' %}">Percuter un fût</a> <a class="button" href="{% url 'gestion:openKeg' %}"><i class="fa fa-fill-drip"></i> Percuter un fût</a>
{% endif %} {% endif %}
{% if perms.gestion.close_keg %} {% if perms.gestion.close_keg %}
<a class="button" href="{% url 'gestion:closeKeg' %}">Fermer un fût</a> <a class="button" href="{% url 'gestion:closeKeg' %}"><i class="fa fa-fill"></i> Fermer un fût</a>
{% endif %} {% endif %}
<br><br> <br><br>
<div class="table-wrapper"> <div class="table-wrapper">
@ -78,6 +80,7 @@
<th>Code barre</th> <th>Code barre</th>
<th>Capacité</th> <th>Capacité</th>
<th>Prix du fût</th> <th>Prix du fût</th>
<th>Degré</th>
<th>Historique</th> <th>Historique</th>
<th>Administrer</th> <th>Administrer</th>
</tr> </tr>
@ -90,8 +93,9 @@
<td>{{ keg.barcode }}</td> <td>{{ keg.barcode }}</td>
<td>{{ keg.capacity }} L</td> <td>{{ keg.capacity }} L</td>
<td>{{ keg.amount }} €</td> <td>{{ keg.amount }} €</td>
<td>{{ keg.pinte.deg }}°</td>
<td><a href="{% url 'gestion:kegH' keg.pk %}">Voir</a></td> <td><a href="{% url 'gestion:kegH' keg.pk %}">Voir</a></td>
<td>{% if perms.gestion.open_keg %}{% if keg.stockHold > 0 %}<a href="{% url 'gestion:openDirectKeg' keg.pk %}" class="button small">Percuter</a> {% endif %}{% endif %}{% if perms.gestion.change_keg %}<a href="{% url 'gestion:editKeg' keg.pk %}" class="button small">Modifier</a>{% endif %}</td> <td>{% if perms.gestion.open_keg %}{% if keg.stockHold > 0 %}<a href="{% url 'gestion:openDirectKeg' keg.pk %}" class="button small"><i class="fa fa-fill-drip"></i> Percuter</a> {% endif %}{% endif %}{% if perms.gestion.change_keg %}<a href="{% url 'gestion:editKeg' keg.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -61,7 +61,7 @@
</header> </header>
<div class="row uniform"> <div class="row uniform">
<div class="12u$"> <div class="12u$">
<a class="button small" href="">Annuler</a><br><br> <a class="button small" href=""><i class="fa fa-times"></i> Annuler</a><br><br>
{{gestion_form}} {{gestion_form}}
</div> </div>
</div> </div>
@ -115,6 +115,19 @@
<div class="boutonProduit"> <div class="boutonProduit">
<table> <table>
<tbody class="actions" id="bouton Produit"> <tbody class="actions" id="bouton Produit">
<tr class="cotisation-hidden" style="text-align:center; font-weight:bold;"><td colspan="4">Cotisations</td></tr>
{% for cotisation in cotisations %}
{% if forloop.counter0|divisibleby:4 %}
<tr class="cotisation-hidden" style="text-align:center">
{% endif %}
<td class="cotisation-hidden"><button class="cotisation" target="{{cotisation.pk}}">Cotisation {{cotisation.duration}} jours ({{cotisation.amount}} €)</button></td>
{% if forloop.counter|divisibleby:4 %}
</tr>
{% endif %}
{% endfor %}
{% if not bieresPression|divisibleby:4 %}
</tr>
{% endif %}
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bières pression</td></tr> <tr style="text-align:center; font-weight:bold;"><td colspan="4">Bières pression</td></tr>
{% for product in bieresPression %} {% for product in bieresPression %}
{% if forloop.counter0|divisibleby:4 %} {% if forloop.counter0|divisibleby:4 %}
@ -214,7 +227,7 @@
{% csrf_token %} {% csrf_token %}
{{reload_form}} {{reload_form}}
<br> <br>
<button type="submit">Recharger</button> <button type="submit"><i class="fa fa-hand-holding-usd"></i> Recharger</button>
</form> </form>
</section> </section>
{% endif %} {% endif %}
@ -227,7 +240,7 @@
{% csrf_token %} {% csrf_token %}
{{refund_form}} {{refund_form}}
<br> <br>
<button type="submit">Rembourser</button> <button type="submit"><i class="fa fa-file-invoice-dollar"></i> Rembourser</button>
</form> </form>
</section> </section>
{% endif %} {% endif %}

View file

@ -10,7 +10,7 @@
<header class="major"> <header class="major">
<h2>Liste des menus</h2> <h2>Liste des menus</h2>
</header> </header>
<a class="button" href="{% url 'gestion:addMenu' %}">Créer un menu</a><br><br> <a class="button" href="{% url 'gestion:addMenu' %}"><i class="fa fa-plus-square"></i> Créer un menu</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -29,9 +29,9 @@
<td>{{ menu.name }}</td> <td>{{ menu.name }}</td>
<td>{{ menu.amount}} €</td> <td>{{ menu.amount}} €</td>
<td>{{ menu.barcode }}</td> <td>{{ menu.barcode }}</td>
<td>{% for art in menu.articles.all %}{{art}},{% endfor %}</td> <td>{% for art in menu.articles.all %}<a href="{% url 'gestion:productProfile' art.pk %}">{{art}}</a>,{% endfor %}</td>
<td>{{ menu.is_active | yesno:"Oui, Non"}}</td> <td>{{ menu.is_active | yesno:"Oui, Non"}}</td>
<td>{% if perms.gestion.change_menu %}<a href="{% url 'gestion:switchActivateMenu' menu.pk %}" class="button small">{% if menu.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editMenu' menu.pk %}" class="button small">Modifier</a>{% endif %}</td> <td>{% if perms.gestion.change_menu %}<a href="{% url 'gestion:switchActivateMenu' menu.pk %}" class="button small">{% if menu.is_active %}<i class="fa fa-times-cirlce"></i> Désa{% else %}<i class="fa fa-check-circle"></i> A{% endif %}ctiver</a> <a href="{% url 'gestion:editMenu' menu.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -14,7 +14,7 @@
<h2>Général</h2> <h2>Général</h2>
</header> </header>
{% if perms.gestion.add_pinte %} {% if perms.gestion.add_pinte %}
<a class="button" href="{% url 'gestion:addPintes' %}">Créer une ou plusieurs pintes</a><br><br> <a class="button" href="{% url 'gestion:addPintes' %}"><i class="fa fa-glass-whiskey"></i> Créer une ou plusieurs pintes</a><br><br>
{% endif %} {% endif %}
Il a y actuellement {{ taken_pintes.count|add:free_pintes.count }} pintes, parmis lesquelles <strong>{{ free_pintes.count }} sont rendues</strong> et <strong>{{ taken_pintes.count }} ne sont pas rendues</strong>. Il a y actuellement {{ taken_pintes.count|add:free_pintes.count }} pintes, parmis lesquelles <strong>{{ free_pintes.count }} sont rendues</strong> et <strong>{{ taken_pintes.count }} ne sont pas rendues</strong>.
</section> </section>
@ -37,10 +37,10 @@
{% for pinte in taken_pintes %} {% for pinte in taken_pintes %}
<tr> <tr>
<td>{{ pinte.pk }}</td> <td>{{ pinte.pk }}</td>
<td>{{ pinte.current_owner }}</td> <td>{% if pinte.current_owner %}<a href="{% url 'users:profile' pinte.current_owner.pk %}">{{ pinte.current_owner }}</a>{% endif %}</td>
<td>{{ pinte.previous_owner }}</td> <td>{% if pinte.previous_owner %}<a href="{% url 'users:profile' pinte.previous_owner.pk %}">{{ pinte.previous_owner }}</a>{% endif %}</td>
<td>{{ pinte.last_update_date }}</td> <td>{{ pinte.last_update_date }}</td>
<td>{% if perms.gestion.change_pinte %} <a href="{% url 'gestion:release' pinte.pk %}" class="button small">Libérer</a>{% endif %}</td> <td>{% if perms.gestion.change_pinte %} <a href="{% url 'gestion:release' pinte.pk %}" class="button small"><i class="fa fa-glass-whiskey"></i> Libérer</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -64,7 +64,7 @@
{% for pinte in free_pintes %} {% for pinte in free_pintes %}
<tr> <tr>
<td>{{ pinte.pk }}</td> <td>{{ pinte.pk }}</td>
<td>{{ pinte.previous_owner }}</td> <td>{% if pinte.previous_owner %}<a href="{% url 'users:profile' pinte.previous_owner.pk %}">{{ pinte.previous_owner }}</a>{% endif %}</td>
<td>{{ pinte.last_update_date }}</td> <td>{{ pinte.last_update_date }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -22,8 +22,8 @@
<tbody> <tbody>
{% for user in users %} {% for user in users %}
<tr> <tr>
<td>{{ user }}</td> <td><a href="{% url 'users:profile' user.pk">{{user}}</a></td>
<td><a href="{% url 'users:profile' user.pk %}" class="button small">Profil</a></td> <td><a href="{% url 'users:profile' user.pk %}" class="button small"><i class="fa fa-user"></i> Profil</a></td>
<td>{{ user.pintes_owned_currently.count }}</td> <td>{{ user.pintes_owned_currently.count }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -11,7 +11,7 @@
<h2>Liste des produits</h2> <h2>Liste des produits</h2>
</header> </header>
{% if perms.gestion.add_product %} {% if perms.gestion.add_product %}
<a class="button" href="{% url 'gestion:addProduct' %}">Créer un produit</a><br><br> <a class="button" href="{% url 'gestion:addProduct' %}"><i class="fa fa-boxes"></i> Créer un produit</a><br><br>
{% endif %} {% endif %}
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
@ -32,7 +32,7 @@
<tbody> <tbody>
{% for product in products %} {% for product in products %}
<tr> <tr>
<td>{{ product.name }}</td> <td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
<td>{{ product.amount}}</td> <td>{{ product.amount}}</td>
<td>{{ product.stockHold }}</td> <td>{{ product.stockHold }}</td>
<td>{{ product.stockBar }}</td> <td>{{ product.stockBar }}</td>
@ -41,7 +41,7 @@
<td>{{ product.is_active | yesno:"Oui, Non"}}</td> <td>{{ product.is_active | yesno:"Oui, Non"}}</td>
<td>{{ product.deg }}</td> <td>{{ product.deg }}</td>
<td>{{ product.volume }} cl</td> <td>{{ product.volume }} cl</td>
<td><a href="{% url 'gestion:productProfile' product.pk %}" class="button small">Profil</a> {% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small">Modifier</a>{% endif %}</td> <td><a href="{% url 'gestion:productProfile' product.pk %}" class="button small"><i class="fa fa-eye"></i> Profil</a> {% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}<i class="fa fa-times-circle"></i> Désa{% else %}<i class="fa fa-check-circle"></i> A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -1,10 +1,11 @@
{% extends "base.html" %} {% extends "base.html" %}
{%load static %} {%load static %}
{%block entete%}Classement{%endblock%} {%block entete%}Classement{%endblock%}
{% block nav %} {% block navbar %}
<ul> <ul>
<li><a href="#first">Meilleurs consommateurs (débit)</a></li> <li><a href="#first">Meilleurs consommateurs (débit)</a></li>
<li><a href="#second">Meilleurs consommateurs (alcool)</a></li> <li><a href="#second">Meilleurs consommateurs (alcool)</a></li>
<li><a href="#third">Classement par produit</a></li>
</ul> </ul>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -28,7 +29,7 @@
{%for customer in bestBuyers%} {%for customer in bestBuyers%}
<tr> <tr>
<th>{{ forloop.counter }}</th> <th>{{ forloop.counter }}</th>
<th>{{ customer.username }}</th> <th><a href="{% url 'users:profile' customer.pk %}">{{ customer.username }}</a></th>
<th>{{ customer.profile.debit }}€</th> <th>{{ customer.profile.debit }}€</th>
</tr> </tr>
{%endfor%} {%endfor%}
@ -59,7 +60,7 @@
{% for customer in bestDrinkers %} {% for customer in bestDrinkers %}
<tr> <tr>
<th>{{ forloop.counter }}</th> <th>{{ forloop.counter }}</th>
<th>{{ customer.0.username }}</th> <th><a href="{% url 'users:profile' customer.0.pk %}">{{ customer.0.username }}</a></th>
<th>{{ customer.1 }}</th> <th>{{ customer.1 }}</th>
</tr> </tr>
{%endfor%} {%endfor%}
@ -70,4 +71,44 @@
</div> </div>
</div> </div>
</section> </section>
<section id="third" class="main">
<div class="spotlight">
<div class="content">
<header class="major">
<h2>Classement par produit</h2>
</header>
<div class="row">
<div class="8u 12u$(medium)">
<form action="" method="POST">
{% csrf_token %}
{{form}}
<br><br>
<button type="submit" class="button">Afficher</button>
</form>
{% if product_ranking %}
<table>
<thead>
<tr>
<th>Place</th>
<th>Pseudo</th>
<th>Quantités consommées</th>
</tr>
</thead>
<tbody>
{% for customer in product_ranking %}
<tr>
<th>{{ forloop.counter }}</th>
<th><a href="{% url 'users:profile' customer.0.pk %}">{{ customer.0.username }}</a></th>
<th>{{ customer.1 }}</th>
</tr>
{%endfor%}
</tbody>
</table>
{% endif %}
</div>
</div>
</div>
</div>
</section>
{{form.media}}
{%endblock%} {%endblock%}

View file

@ -7,19 +7,20 @@ from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.utils import timezone from django.utils import timezone
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.db import transaction
from datetime import datetime, timedelta
from django_tex.views import render_to_pdf from django_tex.views import render_to_pdf
from coopeV3.acl import active_required, acl_or, admin_required from coopeV3.acl import active_required, acl_or, admin_required
import simplejson as json import simplejson as json
from dal import autocomplete from dal import autocomplete
from decimal import * from decimal import *
import datetime
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm
from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund
from preferences.models import PaymentMethod, GeneralPreferences from preferences.models import PaymentMethod, GeneralPreferences, Cotisation
from users.models import CotisationHistory from users.models import CotisationHistory
@active_required @active_required
@ -77,6 +78,7 @@ def manage(request):
menus = Menu.objects.filter(is_active=True) menus = Menu.objects.filter(is_active=True)
kegs = Keg.objects.filter(is_active=True) kegs = Keg.objects.filter(is_active=True)
gp, _ = GeneralPreferences.objects.get_or_create(pk=1) gp, _ = GeneralPreferences.objects.get_or_create(pk=1)
cotisations = Cotisation.objects.all()
floating_buttons = gp.floating_buttons floating_buttons = gp.floating_buttons
for keg in kegs: for keg in kegs:
if(keg.pinte): if(keg.pinte):
@ -97,6 +99,7 @@ def manage(request):
"menus": menus, "menus": menus,
"pay_buttons": pay_buttons, "pay_buttons": pay_buttons,
"floating_buttons": floating_buttons, "floating_buttons": floating_buttons,
"cotisations": cotisations
}) })
@csrf_exempt @csrf_exempt
@ -107,8 +110,11 @@ def order(request):
""" """
Process the given order. Called by a js/JQuery script. Process the given order. Called by a js/JQuery script.
""" """
error_message = "Impossible d'effectuer la transaction. Toute opération abandonnée. Veuillez contacter le président ou le trésorier"
try:
with transaction.atomic():
if("user" not in request.POST or "paymentMethod" not in request.POST or "amount" not in request.POST or "order" not in request.POST): if("user" not in request.POST or "paymentMethod" not in request.POST or "amount" not in request.POST or "order" not in request.POST):
return HttpResponse("Erreur du POST") raise Exception("Erreur du post")
else: else:
user = get_object_or_404(User, pk=request.POST['user']) user = get_object_or_404(User, pk=request.POST['user'])
paymentMethod = get_object_or_404(PaymentMethod, pk=request.POST['paymentMethod']) paymentMethod = get_object_or_404(PaymentMethod, pk=request.POST['paymentMethod'])
@ -116,9 +122,34 @@ def order(request):
order = json.loads(request.POST["order"]) order = json.loads(request.POST["order"])
menus = json.loads(request.POST["menus"]) menus = json.loads(request.POST["menus"])
listPintes = json.loads(request.POST["listPintes"]) listPintes = json.loads(request.POST["listPintes"])
cotisations = json.loads(request.POST['cotisations'])
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
if (not order) and (not menus): if (not order) and (not menus) and (not cotisations):
return HttpResponse("Pas de commande") error_message = "Pas de commande"
raise Exception(error_message)
if(cotisations):
for co in cotisations:
cotisation = Cotisation.objects.get(pk=co['pk'])
for i in range(co['quantity']):
cotisation_history = CotisationHistory(cotisation=cotisation)
if(paymentMethod.affect_balance):
if(user.profile.balance >= cotisation_history.cotisation.amount):
user.profile.debit += cotisation_history.cotisation.amount
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
cotisation_history.user = user
cotisation_history.coopeman = request.user
cotisation_history.amount = cotisation.amount
cotisation_history.duration = cotisation.duration
cotisation_history.paymentMethod = paymentMethod
if(user.profile.cotisationEnd and user.profile.cotisationEnd > timezone.now()):
cotisation_history.endDate = user.profile.cotisationEnd + timedelta(days=cotisation.duration)
else:
cotisation_history.endDate = timezone.now() + timedelta(days=cotisation.duration)
user.profile.cotisationEnd = cotisation_history.endDate
user.save()
cotisation_history.save()
adherentRequired = False adherentRequired = False
for o in order: for o in order:
product = get_object_or_404(Product, pk=o["pk"]) product = get_object_or_404(Product, pk=o["pk"])
@ -127,18 +158,21 @@ def order(request):
menu = get_object_or_404(Menu, pk=m["pk"]) menu = get_object_or_404(Menu, pk=m["pk"])
adherentRequired = adherentRequired or menu.adherent_required adherentRequired = adherentRequired or menu.adherent_required
if(adherentRequired and not user.profile.is_adherent): if(adherentRequired and not user.profile.is_adherent):
return HttpResponse("N'est pas adhérent et devrait l'être") error_message = "N'est pas adhérent et devrait l'être."
raise Exception(error_message)
# Partie un peu complexe : je libère toutes les pintes de la commande, puis je test # Partie un peu complexe : je libère toutes les pintes de la commande, puis je test
# s'il a trop de pintes non rendues, puis je réalloue les pintes # s'il a trop de pintes non rendues, puis je réalloue les pintes
for pinte in listPintes: for pinte in listPintes:
allocate(pinte, None) allocate(pinte, None)
if(gp.lost_pintes_allowed and user.profile.nb_pintes >= gp.lost_pintes_allowed): if(gp.use_pinte_monitoring and gp.lost_pintes_allowed and user.profile.nb_pintes >= gp.lost_pintes_allowed):
return HttpResponse("Impossible de réaliser la commande : l'utilisateur a perdu trop de pintes.") error_message = "Impossible de réaliser la commande : l'utilisateur a perdu trop de pintes."
raise Exception(error_message)
for pinte in listPintes: for pinte in listPintes:
allocate(pinte, user) allocate(pinte, user)
if(paymentMethod.affect_balance): if(paymentMethod.affect_balance):
if(user.profile.balance < amount): if(user.profile.balance < amount):
return HttpResponse("Solde inférieur au prix de la commande") error_message = "Solde inférieur au prix de la commande"
raise Exception(error_message)
else: else:
user.profile.debit += amount user.profile.debit += amount
user.save() user.save()
@ -148,7 +182,7 @@ def order(request):
if(product.category == Product.P_PRESSION): if(product.category == Product.P_PRESSION):
keg = get_object_or_404(Keg, pinte=product) keg = get_object_or_404(Keg, pinte=product)
if(not keg.is_active): if(not keg.is_active):
return HttpResponse("Une erreur inconnue s'est produite. Veuillez contacter le trésorier ou le président") raise Exception("Fût non actif")
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True) kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.5) kegHistory.quantitySold += Decimal(quantity * 0.5)
kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.amountSold += Decimal(quantity * product.amount)
@ -156,7 +190,7 @@ def order(request):
elif(product.category == Product.D_PRESSION): elif(product.category == Product.D_PRESSION):
keg = get_object_or_404(Keg, demi=product) keg = get_object_or_404(Keg, demi=product)
if(not keg.is_active): if(not keg.is_active):
return HttpResponse("Une erreur inconnue s'est produite. Veuillez contacter le trésorier ou le président") raise Exception("Fût non actif")
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True) kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.25) kegHistory.quantitySold += Decimal(quantity * 0.25)
kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.amountSold += Decimal(quantity * product.amount)
@ -164,7 +198,7 @@ def order(request):
elif(product.category == Product.G_PRESSION): elif(product.category == Product.G_PRESSION):
keg = get_object_or_404(Keg, galopin=product) keg = get_object_or_404(Keg, galopin=product)
if(not keg.is_active): if(not keg.is_active):
return HttpResponse("Une erreur inconnue s'est produite. Veuillez contacter le trésorier ou le président") raise Exception("Fût non actif")
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True) kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.125) kegHistory.quantitySold += Decimal(quantity * 0.125)
kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.amountSold += Decimal(quantity * product.amount)
@ -178,11 +212,21 @@ def order(request):
consumption.save() consumption.save()
ch = ConsumptionHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, product=product, amount=Decimal(quantity*product.amount), coopeman=request.user) ch = ConsumptionHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, product=product, amount=Decimal(quantity*product.amount), coopeman=request.user)
ch.save() ch.save()
if(user.profile.balance > Decimal(product.amount * quantity)):
user.profile.debit += Decimal(product.amount*quantity)
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
for m in menus: for m in menus:
menu = get_object_or_404(Menu, pk=m["pk"]) menu = get_object_or_404(Menu, pk=m["pk"])
quantity = int(m["quantity"]) quantity = int(m["quantity"])
mh = MenuHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, menu=menu, amount=int(quantity*menu.amount), coopeman=request.user) mh = MenuHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, menu=menu, amount=int(quantity*menu.amount), coopeman=request.user)
mh.save() mh.save()
if(user.profile.balance > Decimal(menu.amount * quantity)):
user.profile.debit += Decimal(menu.amount*quantity)
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
for article in menu.articles.all(): for article in menu.articles.all():
consumption, _ = Consumption.objects.get_or_create(customer=user, product=article) consumption, _ = Consumption.objects.get_or_create(customer=user, product=article)
consumption.quantity += quantity consumption.quantity += quantity
@ -191,6 +235,10 @@ def order(request):
article.stockHold -= 1 article.stockHold -= 1
article.save() article.save()
return HttpResponse("La commande a bien été effectuée") return HttpResponse("La commande a bien été effectuée")
except Exception as e:
print(e)
print("test")
return HttpResponse(error_message)
@active_required @active_required
@login_required @login_required
@ -341,7 +389,7 @@ def addProduct(request):
product = form.save() product = form.save()
messages.success(request, "Le produit a bien été ajouté") messages.success(request, "Le produit a bien été ajouté")
return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk})) return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk}))
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter"}) return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -374,7 +422,7 @@ def editProduct(request, pk):
form.save() form.save()
messages.success(request, "Le produit a bien été modifié") messages.success(request, "Le produit a bien été modifié")
return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk})) return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk}))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un produit", "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Modification d'un produit", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -420,7 +468,7 @@ def searchProduct(request):
form = SearchProductForm(request.POST or None) form = SearchProductForm(request.POST or None)
if(form.is_valid()): if(form.is_valid()):
return redirect(reverse('gestion:productProfile', kwargs={'pk': form.cleaned_data['product'].pk })) return redirect(reverse('gestion:productProfile', kwargs={'pk': form.cleaned_data['product'].pk }))
return render(request, "form.html", {"form": form, "form_title":"Rechercher un produit", "form_button": "Rechercher"}) return render(request, "form.html", {"form": form, "form_title":"Rechercher un produit", "form_button": "Rechercher", "form_button_icon": "search"})
@active_required @active_required
@login_required @login_required
@ -484,7 +532,7 @@ class ProductsAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = Product.objects.all() qs = Product.objects.all()
if self.q: if self.q:
qs = qs.filter(name__istartswith=self.q) qs = qs.filter(name__contains=self.q)
return qs return qs
class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView): class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
@ -494,7 +542,7 @@ class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = Product.objects.filter(is_active=True) qs = Product.objects.filter(is_active=True)
if self.q: if self.q:
qs = qs.filter(name__istartswith=self.q) qs = qs.filter(name__contains=self.q)
return qs return qs
########## Kegs ########## ########## Kegs ##########
@ -526,7 +574,7 @@ def addKeg(request):
keg = form.save() keg = form.save()
messages.success(request, "Le fût " + keg.name + " a bien été ajouté") messages.success(request, "Le fût " + keg.name + " a bien été ajouté")
return redirect(reverse('gestion:kegsList')) return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un fût", "form_button": "Ajouter"}) return render(request, "form.html", {"form":form, "form_title": "Ajout d'un fût", "form_button": "Ajouter", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -559,7 +607,7 @@ def editKeg(request, pk):
form.save() form.save()
messages.success(request, "Le fût a bien été modifié") messages.success(request, "Le fût a bien été modifié")
return redirect(reverse('gestion:kegsList')) return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un fût", "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Modification d'un fût", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -598,7 +646,7 @@ def openKeg(request):
keg.save() keg.save()
messages.success(request, "Le fut a bien été percuté") messages.success(request, "Le fut a bien été percuté")
return redirect(reverse('gestion:kegsList')) return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title":"Percutage d'un fût", "form_button":"Percuter"}) return render(request, "form.html", {"form": form, "form_title":"Percutage d'un fût", "form_button":"Percuter", "form_button_icon": "fill-drip"})
@active_required @active_required
@login_required @login_required
@ -660,7 +708,7 @@ def closeKeg(request):
keg.save() keg.save()
messages.success(request, "Le fût a bien été fermé") messages.success(request, "Le fût a bien été fermé")
return redirect(reverse('gestion:kegsList')) return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title":"Fermeture d'un fût", "form_button":"Fermer le fût"}) return render(request, "form.html", {"form": form, "form_title":"Fermeture d'un fût", "form_button":"Fermer le fût", "form_button_icon": "fill"})
@active_required @active_required
@login_required @login_required
@ -742,7 +790,7 @@ class KegActiveAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = Keg.objects.filter(is_active = True) qs = Keg.objects.filter(is_active = True)
if self.q: if self.q:
qs = qs.filter(name__istartswith=self.q) qs = qs.filter(name__contains=self.q)
return qs return qs
class KegPositiveAutocomplete(autocomplete.Select2QuerySetView): class KegPositiveAutocomplete(autocomplete.Select2QuerySetView):
@ -752,7 +800,7 @@ class KegPositiveAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = Keg.objects.filter(stockHold__gt = 0) qs = Keg.objects.filter(stockHold__gt = 0)
if self.q: if self.q:
qs = qs.filter(name__istartswith=self.q) qs = qs.filter(name__contains=self.q)
return qs return qs
########## Menus ########## ########## Menus ##########
@ -785,7 +833,7 @@ def addMenu(request):
menu = form.save() menu = form.save()
messages.success(request, "Le menu " + menu.name + " a bien été ajouté") messages.success(request, "Le menu " + menu.name + " a bien été ajouté")
return redirect(reverse('gestion:menusList')) return redirect(reverse('gestion:menusList'))
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un menu", "form_button": "Ajouter", "extra_css": extra_css}) return render(request, "form.html", {"form":form, "form_title": "Ajout d'un menu", "form_button": "Ajouter", "form_button_icon": "plus-square", "extra_css": extra_css})
@active_required @active_required
@login_required @login_required
@ -819,7 +867,7 @@ def edit_menu(request, pk):
form.save() form.save()
messages.success(request, "Le menu a bien été modifié") messages.success(request, "Le menu a bien été modifié")
return redirect(reverse('gestion:menusList')) return redirect(reverse('gestion:menusList'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un menu", "form_button": "Modifier", "extra_css": extra_css}) return render(request, "form.html", {"form": form, "form_title": "Modification d'un menu", "form_button": "Modifier", "form_button_icon": "pencil-alt", "extra_css": extra_css})
@active_required @active_required
@login_required @login_required
@ -847,7 +895,7 @@ def searchMenu(request):
if(form.is_valid()): if(form.is_valid()):
menu = form.cleaned_data['menu'] menu = form.cleaned_data['menu']
return redirect(reverse('gestion:editMenu', kwargs={'pk':menu.pk})) return redirect(reverse('gestion:editMenu', kwargs={'pk':menu.pk}))
return render(request, "form.html", {"form": form, "form_title": "Recherche d'un menu", "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Recherche d'un menu", "form_button": "Modifier", "form_button_icon": "search"})
@active_required @active_required
@login_required @login_required
@ -899,7 +947,7 @@ def get_menu(request, pk):
for article in menu.articles: for article in menu.articles:
if article.category == Product.P_PRESSION: if article.category == Product.P_PRESSION:
nb_pintes +=1 nb_pintes +=1
data = json.dumps({"pk": menu.pk, "barcode" : menu.barcode, "name": menu.name, "amount" : menu.amount, needQuantityButton: False, "nb_pintes": nb_pintes}) data = json.dumps({"pk": menu.pk, "barcode" : menu.barcode, "name": menu.name, "amount" : menu.amount, "needQuantityButton": False, "nb_pintes": nb_pintes})
return HttpResponse(data, content_type='application/json') return HttpResponse(data, content_type='application/json')
class MenusAutocomplete(autocomplete.Select2QuerySetView): class MenusAutocomplete(autocomplete.Select2QuerySetView):
@ -909,7 +957,7 @@ class MenusAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = Menu.objects.all() qs = Menu.objects.all()
if self.q: if self.q:
qs = qs.filter(name__istartswith=self.q) qs = qs.filter(name__contains=self.q)
return qs return qs
########## Ranking ########## ########## Ranking ##########
@ -939,7 +987,12 @@ def ranking(request):
alcohol = customer.profile.alcohol alcohol = customer.profile.alcohol
list.append([customer, alcohol]) list.append([customer, alcohol])
bestDrinkers = sorted(list, key=lambda x: x[1], reverse=True)[:25] bestDrinkers = sorted(list, key=lambda x: x[1], reverse=True)[:25]
return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers}) form = SearchProductForm(request.POST or None)
if(form.is_valid()):
product_ranking = form.cleaned_data['product'].ranking
else:
product_ranking = None
return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers, "product_ranking": product_ranking, "form": form})
########## Pinte monitoring ########## ########## Pinte monitoring ##########
@ -989,7 +1042,7 @@ def add_pintes(request):
i += 1 i += 1
messages.success(request, str(i) + " pinte(s) a(ont) été ajoutée(s)") messages.success(request, str(i) + " pinte(s) a(ont) été ajoutée(s)")
return redirect(reverse('gestion:productsIndex')) return redirect(reverse('gestion:productsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Ajouter des pintes", "form_button": "Ajouter"}) return render(request, "form.html", {"form": form, "form_title": "Ajouter des pintes", "form_button": "Ajouter", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -1008,7 +1061,7 @@ def release_pintes(request):
i += 1 i += 1
messages.success(request, str(i) + " pinte(s) a(ont) été libérée(s)") messages.success(request, str(i) + " pinte(s) a(ont) été libérée(s)")
return redirect(reverse('gestion:productsIndex')) return redirect(reverse('gestion:productsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Libérer des pintes", "form_button": "Libérer"}) return render(request, "form.html", {"form": form, "form_title": "Libérer des pintes", "form_button": "Libérer", "form_button_icon": "glass-whiskey"})
@active_required @active_required
@login_required @login_required
@ -1069,7 +1122,7 @@ def gen_releve(request):
value_lydia += cot.amount value_lydia += cot.amount
elif pm == cheque: elif pm == cheque:
value_cheque += cot.amount value_cheque += cot.amount
now = datetime.datetime.now() now = datetime.now()
return render_to_pdf(request, 'gestion/releve.tex', {"consumptions": consumptions, "reloads": reloads, "refunds": refunds, "cotisations": cotisations, "begin": begin, "end": end, "now": now, "value_especes": value_especes, "value_lydia": value_lydia, "value_cheque": value_cheque}, filename="releve.pdf") return render_to_pdf(request, 'gestion/releve.tex', {"consumptions": consumptions, "reloads": reloads, "refunds": refunds, "cotisations": cotisations, "begin": begin, "end": end, "now": now, "value_especes": value_especes, "value_lydia": value_lydia, "value_cheque": value_cheque}, filename="releve.pdf")
else: else:
return render(request, "form.html", {"form": form, "form_title": "Génération d'un relevé", "form_button": "Générer"}) return render(request, "form.html", {"form": form, "form_title": "Génération d'un relevé", "form_button": "Générer", "form_button_icon": "file-pdf"})

View file

@ -36,5 +36,6 @@ class GeneralPreferencesForm(forms.ModelForm):
'treasurer': forms.TextInput(attrs={'placeholder': 'Trésorier'}), 'treasurer': forms.TextInput(attrs={'placeholder': 'Trésorier'}),
'brewer': forms.TextInput(attrs={'placeholder': 'Maître brasseur'}), 'brewer': forms.TextInput(attrs={'placeholder': 'Maître brasseur'}),
'grocer': forms.TextInput(attrs={'placeholder': 'Epic épicier'}), 'grocer': forms.TextInput(attrs={'placeholder': 'Epic épicier'}),
'home_text': forms.Textarea(attrs={'placeholder': 'Ce message sera affiché sur la page d\'accueil'})
} }

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-01-19 22:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0005_auto_20190106_0513'),
]
operations = [
migrations.AddField(
model_name='generalpreferences',
name='home_text',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='historicalgeneralpreferences',
name='home_text',
field=models.TextField(blank=True),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-01-20 11:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0006_auto_20190119_2326'),
]
operations = [
migrations.AddField(
model_name='generalpreferences',
name='automatic_logout_time',
field=models.PositiveIntegerField(null=True),
),
migrations.AddField(
model_name='historicalgeneralpreferences',
name='automatic_logout_time',
field=models.PositiveIntegerField(null=True),
),
]

View file

@ -34,6 +34,8 @@ class GeneralPreferences(models.Model):
use_pinte_monitoring = models.BooleanField(default=False) use_pinte_monitoring = models.BooleanField(default=False)
lost_pintes_allowed = models.PositiveIntegerField(default=0) lost_pintes_allowed = models.PositiveIntegerField(default=0)
floating_buttons = models.BooleanField(default=False) floating_buttons = models.BooleanField(default=False)
home_text = models.TextField(blank=True)
automatic_logout_time = models.PositiveIntegerField(null=True)
history = HistoricalRecords() history = HistoricalRecords()
class Cotisation(models.Model): class Cotisation(models.Model):

View file

@ -11,7 +11,7 @@
<h2>Liste des cotisations</h2> <h2>Liste des cotisations</h2>
</header> </header>
{% if perms.preferences.add_cotisation %} {% if perms.preferences.add_cotisation %}
<a class="button" href="{% url 'preferences:addCotisation' %}">Créer une cotisation</a><br><br> <a class="button" href="{% url 'preferences:addCotisation' %}"><i class="fa fa-plus-square"></i> Créer une cotisation</a><br><br>
{% endif %} {% endif %}
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
@ -27,7 +27,7 @@
<tr> <tr>
<td>{{ cotisation.duration }} jours</td> <td>{{ cotisation.duration }} jours</td>
<td>{{ cotisation.amount }} €</td> <td>{{ cotisation.amount }} €</td>
<td>{% if perms.preferences.change_cotisation %}<a class="button small" href="{% url 'preferences:editCotisation' cotisation.pk %}">Modifier</a> {% endif %}{% if perms.preferences.delete_cotisation %}<a class="button small" href="{% url 'preferences:deleteCotisation' cotisation.pk %}">Supprimer</a>{% endif %}</td> <td>{% if perms.preferences.change_cotisation %}<a class="button small" href="{% url 'preferences:editCotisation' cotisation.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a> {% endif %}{% if perms.preferences.delete_cotisation %}<a class="button small" href="{% url 'preferences:deleteCotisation' cotisation.pk %}"><i class="fa fa-trash"></i> Supprimer</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -26,7 +26,7 @@
</div> </div>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
<button type="submit">Enregistrer</button> <button type="submit"><i class="fa fa-save"></i> Enregistrer</button>
</div> </div>
</div> </div>
</div> </div>
@ -51,7 +51,7 @@
</div> </div>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
<button type="submit">Enregistrer</button> <button type="submit"><i class="fa fa-save"></i> Enregistrer</button>
</div> </div>
</div> </div>
</div> </div>
@ -89,7 +89,7 @@
</div> </div>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
<button type="submit">Enregistrer</button> <button type="submit"><i class="fa fa-save"></i> Enregistrer</button>
</div> </div>
</div> </div>
</div> </div>
@ -115,7 +115,7 @@
</div> </div>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
<button type="submit">Enregistrer</button> <button type="submit"><i class="fa fa-save"></i> Enregistrer</button>
</div> </div>
</div> </div>
</div> </div>
@ -127,15 +127,32 @@
<header class="major"> <header class="major">
<h2>Autre</h2> <h2>Autre</h2>
</header> </header>
<br>
<h3>Boutons flottants</h3>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
{{form.floating_buttons}} {{form.floating_buttons}}
<label for="{{form.floating_buttons.id_for_label}}">Utiliser les boutons de paiement flottants ?</label> <label for="{{form.floating_buttons.id_for_label}}">Utiliser les boutons de paiement flottants ?</label>
</div> </div>
</div> </div>
<br>
<h3>Déconnexion automatique</h3>
<div class="row uniform"> <div class="row uniform">
<div class="12u"> <div class="12u">
<button type="submit">Enregistrer</button> {{form.automatic_logout_time}}
<label for="{{form.automatic_logout_time.id_for_label}}">Temps (en minutes) au bout duquel l'utilisateur est déconnecté automatiquement (0 pour qu'il reste connecté)</label>
</div>
</div>
<br>
<h3>Texte de la page d'accueil</h3>
<div class="row uniform">
<div class="12u">
{{form.home_text}}
</div>
</div>
<div class="row uniform">
<div class="12u">
<button type="submit"><i class="fa fa-save"></i> Enregistrer</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -11,7 +11,7 @@
<h2>Liste des moyens de paiement</h2> <h2>Liste des moyens de paiement</h2>
</header> </header>
{% if perms.preferences.add_paymentmethod %} {% if perms.preferences.add_paymentmethod %}
<a class="button" href="{% url 'preferences:addPaymentMethod' %}">Créer un moyen de paiement</a><br><br> <a class="button" href="{% url 'preferences:addPaymentMethod' %}"><i class="fa fa-plus-square"></i> Créer un moyen de paiement</a><br><br>
{% endif %} {% endif %}
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
@ -35,7 +35,7 @@
<td>{{ pm.is_usable_in_reload | yesno:"Oui, Non" }}</td> <td>{{ pm.is_usable_in_reload | yesno:"Oui, Non" }}</td>
<td>{{ pm.affect_balance | yesno:"Oui, Non" }}</td> <td>{{ pm.affect_balance | yesno:"Oui, Non" }}</td>
<td><i class="fa fa-{{ pm.icon }}"></i></td> <td><i class="fa fa-{{ pm.icon }}"></i></td>
<td>{% if perms.preferences.change_paymentmethod %}<a class="button small" href="{% url 'preferences:editPaymentMethod' pm.pk %}">Modifier</a> {% endif %}{% if perms.preferences.delete_paymentmethod %}<a class="button small" href="{% url 'preferences:deletePaymentMethod' pm.pk %}">Supprimer</a>{% endif %}</td> <td>{% if perms.preferences.change_paymentmethod %}<a class="button small" href="{% url 'preferences:editPaymentMethod' pm.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a> {% endif %}{% if perms.preferences.delete_paymentmethod %}<a class="button small" href="{% url 'preferences:deletePaymentMethod' pm.pk %}"><i class="fa fa-trash"></i> Supprimer</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -15,4 +15,5 @@ urlpatterns = [
path('deletePaymentMethod/<int:pk>', views.deletePaymentMethod, name="deletePaymentMethod"), path('deletePaymentMethod/<int:pk>', views.deletePaymentMethod, name="deletePaymentMethod"),
path('inactive', views.inactive, name="inactive"), path('inactive', views.inactive, name="inactive"),
path('getConfig', views.get_config, name="getConfig"), path('getConfig', views.get_config, name="getConfig"),
] path('getCotisation/<int:pk>', views.get_cotisation, name="getCotisation")
,]

View file

@ -1,4 +1,4 @@
import json import simplejson as json
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages from django.contrib import messages
@ -84,7 +84,7 @@ def addCotisation(request):
cotisation = form.save() cotisation = form.save()
messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été créée") messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été créée")
return redirect(reverse('preferences:cotisationsIndex')) return redirect(reverse('preferences:cotisationsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Création d'une cotisation", "form_button": "Créer"}) return render(request, "form.html", {"form": form, "form_title": "Création d'une cotisation", "form_button": "Créer", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -117,7 +117,7 @@ def editCotisation(request, pk):
cotisation = form.save() cotisation = form.save()
messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été modifiée") messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été modifiée")
return redirect(reverse('preferences:cotisationsIndex')) return redirect(reverse('preferences:cotisationsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'une cotisation", "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Modification d'une cotisation", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -135,6 +135,19 @@ def deleteCotisation(request,pk):
messages.success(request, message) messages.success(request, message)
return redirect(reverse('preferences:cotisationsIndex')) return redirect(reverse('preferences:cotisationsIndex'))
@active_required
@login_required
@permission_required('preferences.view_cotisation')
def get_cotisation(request, pk):
"""
Get a cotisation by pk
``pk``
The primary key of the cotisation
"""
cotisation = get_object_or_404(Cotisation, pk=pk)
data = json.dumps({"pk": cotisation.pk, "duration": cotisation.duration, "amount" : cotisation.amount, "needQuantityButton": False})
return HttpResponse(data, content_type='application/json')
########## Payment Methods ########## ########## Payment Methods ##########
@ -184,7 +197,7 @@ def addPaymentMethod(request):
paymentMethod = form.save() paymentMethod = form.save()
messages.success(request, "Le moyen de paiement " + paymentMethod.name + " a bien été crée") messages.success(request, "Le moyen de paiement " + paymentMethod.name + " a bien été crée")
return redirect(reverse('preferences:paymentMethodsIndex')) return redirect(reverse('preferences:paymentMethodsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Création d'un moyen de paiement", "form_button": "Créer"}) return render(request, "form.html", {"form": form, "form_title": "Création d'un moyen de paiement", "form_button": "Créer", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -217,7 +230,7 @@ def editPaymentMethod(request, pk):
paymentMethod = form.save() paymentMethod = form.save()
messages.success(request, "Le moyen de paiment " + paymentMethod.name + " a bien été modifié") messages.success(request, "Le moyen de paiment " + paymentMethod.name + " a bien été modifié")
return redirect(reverse('preferences:paymentMethodsIndex')) return redirect(reverse('preferences:paymentMethodsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un moyen de paiement", "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Modification d'un moyen de paiement", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required

136
staticfiles/css/runner.css Normal file
View file

@ -0,0 +1,136 @@
/* Copyright 2013 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
.icon {
-webkit-user-select: none;
user-select: none;
display: inline-block;
}
.icon-offline {
content: -webkit-image-set( url(../runner-assets/default_100_percent/100-error-offline.png) 1x, url(../runner-assets/default_200_percent/200-error-offline.png) 2x);
position: relative;
}
.hidden {
display: none;
}
/* Offline page */
.offline .interstitial-wrapper {
color: #2b2b2b;
font-size: 1em;
line-height: 1.55;
margin: 0 auto;
max-width: 600px;
padding-top: 100px;
width: 100%;
}
.offline .runner-container {
height: 150px;
max-width: 600px;
overflow: hidden;
position: absolute;
top: 35px;
width: 44px;
}
.offline .runner-canvas {
height: 150px;
max-width: 600px;
opacity: 1;
overflow: hidden;
position: absolute;
top: 0;
z-index: 2;
}
.offline .controller {
background: rgba(247, 247, 247, .1);
height: 100vh;
left: 0;
position: absolute;
top: 0;
width: 100vw;
z-index: 1;
}
#offline-resources {
display: none;
}
@media (max-width: 420px) {
.suggested-left > #control-buttons, .suggested-right > #control-buttons {
float: none;
}
.snackbar {
left: 0;
bottom: 0;
width: 100%;
border-radius: 0;
}
}
@media (max-height: 350px) {
h1 {
margin: 0 0 15px;
}
.icon-offline {
margin: 0 0 10px;
}
.interstitial-wrapper {
margin-top: 5%;
}
.nav-wrapper {
margin-top: 30px;
}
}
@media (min-width: 600px) and (max-width: 736px) and (orientation: landscape) {
.offline .interstitial-wrapper {
margin-left: 0;
margin-right: 0;
}
}
@media (min-width: 420px) and (max-width: 736px) and (min-height: 240px) and (max-height: 420px) and (orientation:landscape) {
.interstitial-wrapper {
margin-bottom: 100px;
}
}
@media (min-height: 240px) and (orientation: landscape) {
.offline .interstitial-wrapper {
margin-bottom: 90px;
}
.icon-offline {
margin-bottom: 20px;
}
}
@media (max-height: 320px) and (orientation: landscape) {
.icon-offline {
margin-bottom: 0;
}
.offline .runner-container {
top: 10px;
}
}
@media (max-width: 240px) {
.interstitial-wrapper {
overflow: inherit;
padding: 0 8px;
}
}

View file

@ -1,10 +1,11 @@
total = 0 total = 0
products = [] products = []
menus = [] menus = []
cotisations = []
paymentMethod = null paymentMethod = null
balance = 0 balance = 0
username = "" username = ""
id = 0 id_user = 0
listPintes = [] listPintes = []
nbPintes = 0; nbPintes = 0;
use_pinte_monitoring = false; use_pinte_monitoring = false;
@ -29,9 +30,15 @@ function get_menu(id){
}); });
} }
function get_cotisation(id){
res = $.get("../preferences/getCotisation/" + id, function(data){
add_cotisation(data.pk, "", data.duration, data.amount, data.needQuantityButton);
});
}
function add_product(pk, barcode, name, amount, needQuantityButton){ function add_product(pk, barcode, name, amount, needQuantityButton){
exist = false exist = false
index = -1 index = -1;
for(k=0;k < products.length; k++){ for(k=0;k < products.length; k++){
if(products[k].pk == pk){ if(products[k].pk == pk){
exist = true exist = true
@ -71,15 +78,36 @@ function add_menu(pk, barcode, name, amount){
generate_html(); generate_html();
} }
function add_cotisation(pk, barcode, duration, amount){
exist = false;
index = -1;
for(k=0; k < cotisations.length; k++){
if(cotisations[k].pk == pk){
exist = true;
index = k;
}
}
if(exist){
cotisations[index].quantity += 1;
}else{
cotisations.push({"pk": pk, "barcode": barcode, "duration": duration, "amount": amount, "quantity":1});
}
generate_html();
}
function generate_html(){ function generate_html(){
html = ""; html = "";
for(k=0;k<cotisations.length;k++){
cotisation = cotisations[k];
html += '<tr><td></td><td>Cotisation ' + String(cotisation.duration) + ' jours</td><td>' + String(cotisation.amount) + ' €</td><td><input type="number" data-target="' + String(k) + '" onChange="updateCotisationInput(this)" value="' + String(cotisation.quantity) + '"/></td><td>' + String(Number((cotisation.quantity * cotisation.amount).toFixed(2))) + ' €</td></tr>';
}
for(k=0;k<products.length;k++){ for(k=0;k<products.length;k++){
product = products[k] product = products[k]
html += '<tr><td>' + product.barcode + '</td><td>' + product.name + '</td><td>' + String(product.amount) + '</td><td><input type="number" data-target="' + String(k) + '" onChange="updateInput(this)" value="' + String(product.quantity) + '"/></td><td>' + String(Number((product.quantity * product.amount).toFixed(2))) + '</td></tr>'; html += '<tr><td>' + product.barcode + '</td><td>' + product.name + '</td><td>' + String(product.amount) + '</td><td><input type="number" data-target="' + String(k) + '" onChange="updateInput(this)" value="' + String(product.quantity) + '"/></td><td>' + String(Number((product.quantity * product.amount).toFixed(2))) + '</td></tr>';
} }
for(k=0; k<menus.length;k++){ for(k=0; k<menus.length;k++){
menu = menus[k] menu = menus[k]
html += '<tr><td>' + menu.barcode + '</td><td>' + menu.name + '</td><td>' + String(menu.amount) + '</td><td><input type="number" data-target="' + String(k) + '" onChange="updateMenuInput(this)" value="' + String(menu.quantity) + '"/></td><td>' + String(Number((menu.quantity * menu.amount).toFixed(2))) + '</td></tr>'; html += '<tr><td>' + menu.barcode + '</td><td>' + menu.name + '</td><td>' + String(menu.amount) + '</td><td><input type="number" data-target="' + String(k) + '" onChange="updateMenuInput(this)" value="' + String(menu.quantity) + '"/></td><td>' + String(Number((menu.quantity * menu.amount).toFixed(2))) + '</td></tr>';
} }
$("#items").html(html) $("#items").html(html)
updateTotal(); updateTotal();
@ -93,6 +121,9 @@ function updateTotal(){
for(k=0; k<menus.length;k++){ for(k=0; k<menus.length;k++){
total += menus[k].quantity * menus[k].amount; total += menus[k].quantity * menus[k].amount;
} }
for(k=0; k<cotisations.length;k++){
total += cotisations[k].quantity * cotisations[k].amount;
}
$("#totalAmount").text(String(Number(total.toFixed(2))) + "€") $("#totalAmount").text(String(Number(total.toFixed(2))) + "€")
totalAfter = balance - total totalAfter = balance - total
$("#totalAfter").text(String(Number(totalAfter.toFixed(2))) + "€") $("#totalAfter").text(String(Number(totalAfter.toFixed(2))) + "€")
@ -112,7 +143,15 @@ function updateMenuInput(a){
generate_html(); generate_html();
} }
function updateCotisationInput(a){
quantity = parseInt(a.value);
k = parseInt(a.getAttribute("data-target"));
cotisations[k].quantity = quantity;
generate_html();
}
$(document).ready(function(){ $(document).ready(function(){
$(".cotisation-hidden").hide();
get_config(); get_config();
$(".product").click(function(){ $(".product").click(function(){
@ -123,12 +162,20 @@ $(document).ready(function(){
menu = get_menu($(this).attr('target')); menu = get_menu($(this).attr('target'));
}); });
$(".cotisation").click(function(){
cotisation = get_cotisation($(this).attr('target'));
});
$("#id_client").on('change', function(){ $("#id_client").on('change', function(){
id = $("#id_client").val(); id_user = $("#id_client").val();
$.get("/users/getUser/" + id, function(data){ $.get("/users/getUser/" + id_user, function(data){
balance = data.balance; balance = data.balance;
username = data.username; username = data.username;
is_adherent = data.is_adherent;
$("#balance").html(balance + "€"); $("#balance").html(balance + "€");
if(!is_adherent){
$(".cotisation-hidden").show();
}
updateTotal(); updateTotal();
}).fail(function(){ }).fail(function(){
alert("Une erreur inconnue est survenue"); alert("Une erreur inconnue est survenue");
@ -159,7 +206,7 @@ $(document).ready(function(){
} }
} }
} }
$.post("order", {"user":id, "paymentMethod": $(this).attr('data-payment'), "order_length": products.length + menus.length, "order": JSON.stringify(products), "amount": total, "menus": JSON.stringify(menus), "listPintes": JSON.stringify(listPintes)}, function(data){ $.post("order", {"user":id_user, "paymentMethod": $(this).attr('data-payment'), "order_length": products.length + menus.length + cotisations.length, "order": JSON.stringify(products), "amount": total, "menus": JSON.stringify(menus), "listPintes": JSON.stringify(listPintes), "cotisations": JSON.stringify(cotisations)}, function(data){
alert(data); alert(data);
location.reload(); location.reload();
}).fail(function(data){ }).fail(function(data){

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

2715
staticfiles/runner.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %}
{% block entete %}Page introuvable{% endblock %} {% block entete %}Page introuvable{% endblock %}
{% block navbar %} {% block navbar %}
<ul> <ul>
@ -6,6 +7,30 @@
</ul> </ul>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<script>
onkeydown = function(e)
{
var touche = e.keyCode;
var touche_lettre = String.fromCharCode(touche);
gauche = false;
haut = false;
bas = false;
droite = false;
if(touche == 37 || touche_lettre == "Q") //Le déplacement à gauche
gauche = true;
if(touche == 38 || touche_lettre == "Z")
haut = true;
if(touche == 39 || touche_lettre == "D") //Le déplacement à droite
droite = true;
if(touche == 40 || touche_lettre == "S") //Le déplacement en bas
bas = true;
if(gauche || droite || haut || bas) // Bloquer le défilement
e.preventDefault()
return false;
}
</script>
<section id="first" class="main"> <section id="first" class="main">
<header class="major"> <header class="major">
<h2>Erreur 404</h2> <h2>Erreur 404</h2>
@ -13,5 +38,6 @@
<section> <section>
Une erreur s'est produite lors de l'accès à cette page (la page que vous demandez n'existe pas). Vous pouvez revenir à l'accueil en cliquant <a href="{% url 'home' %}">ici</a>. Une erreur s'est produite lors de l'accès à cette page (la page que vous demandez n'existe pas). Vous pouvez revenir à l'accueil en cliquant <a href="{% url 'home' %}">ici</a>.
</section> </section>
<object type="text/html" data="{% url 'coope-runner' %}" width="100%" height="200">
</section> </section>
{% endblock %} {% endblock %}

View file

@ -8,7 +8,9 @@
<link rel="icon" sizes="16x16" href="{% static 'favicon16.ico' %}" type="image/x-icon"> <link rel="icon" sizes="16x16" href="{% static 'favicon16.ico' %}" type="image/x-icon">
<link rel="icon" sizes="32x32" href="{% static 'favicon32.ico' %}" type="image/x-icon"> <link rel="icon" sizes="32x32" href="{% static 'favicon32.ico' %}" type="image/x-icon">
<link rel="icon" sizes="96x96" href="{% static 'favicon96.ico' %}" type="image/x-icon"> <link rel="icon" sizes="96x96" href="{% static 'favicon96.ico' %}" type="image/x-icon">
<link rel="stylesheet" href="{%static 'css/main.css' %}" /> <link rel="stylesheet" href="{% static 'css/main.css' %}" />
{% block extra_css %}{% endblock %}
{% block extra_script %}{% endblock %}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
@ -42,5 +44,16 @@
{% include 'footer.html'%} {% include 'footer.html'%}
</footer> </footer>
</div> </div>
{% if request.user.is_authenticated %}
<script>
time = {% logout_time %};
function logout(){
window.location.replace("{% url 'users:logout' %}");
}
if(time != 0){
setTimeout(logout, 60000 * time);
}
</script>
{% endif %}
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -39,6 +39,6 @@
<li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li> <li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li>
</ul> </ul>
</section> </section>
<p class="copyright">coope.rez v3.2.2 (release stable) &copy; 2018 Yoann Pietri.</p> <p class="copyright">coope.rez v3.3.0 (release stable) &copy; 2018 Yoann Pietri.</p>

View file

@ -16,7 +16,7 @@
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}
<br> <br>
<button type="submit">{{form_button}}</button> <button type="submit"><i class="fa fa-{{form_button_icon}}"></i> {{form_button}}</button>
</form> </form>
</section> </section>
</section> </section>

31
templates/home.html Normal file
View file

@ -0,0 +1,31 @@
{% extends 'base.html' %}
{% block entete %}Accueil{% endblock %}
{% block navbar %}
<ul>
<li><a href="#first">Accueil</a></li>
<li><a href="#second">Les pressions du moment</a></li>
</ul>
{% endblock %}
{% block content %}
<section id="first" class="main">
<header class="major">
<h2>Accueil</h2>
</header>
<section>
{{ home_text }}
</section>
</section>
<section id="second" class="main">
<header class="major">
<h2>Les pressions du moment</h2>
</header>
<section>
Les bières pressions actuellement en Coopé :
<ul>
{% for keg in kegs %}
<li>{{keg}} ({% if keg.pinte %} Pinte : {{keg.pinte.amount}}€,{% endif %}{% if keg.demi %} Demi : {{keg.demi.amount}}€,{% endif %}{% if keg.galopin %} Galopin : {{keg.galopin.amount}}€{% endif %}) : {{keg.pinte.deg}}°</li>
{% endfor %}
</ul>
</section>
</section>
{% endblock %}

View file

@ -1,3 +1,6 @@
<span class="tabulation2">
<i class="fa fa-home"></i> <a href="{% url 'homepage' %}">Accueil</a>
</span>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<span class="tabulation2"> <span class="tabulation2">
<i class="fa fa-user"></i> <a href="{% url 'users:profile' request.user.pk %}">Mon profil</a> <i class="fa fa-user"></i> <a href="{% url 'users:profile' request.user.pk %}">Mon profil</a>
@ -18,11 +21,11 @@
</span> </span>
{% endif %} {% endif %}
<span class="tabulation2"> <span class="tabulation2">
<br>
<i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a> <i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a>
</span> </span>
{% if perms.preferences.change_generalpreferences %} {% if perms.preferences.change_generalpreferences %}
<span class="tabulation2"> <span class="tabulation2">
<br>
<i class="fa fa-tools"></i> <a href="{% url 'preferences:generalPreferences' %}">Admin</a> <i class="fa fa-tools"></i> <a href="{% url 'preferences:generalPreferences' %}">Admin</a>
</span> </span>
{% endif %} {% endif %}
@ -45,5 +48,7 @@
<i class="fa fa-bed"></i> <a href="{% url 'users:logout' %}">Deconnexion</a> <i class="fa fa-bed"></i> <a href="{% url 'users:logout' %}">Deconnexion</a>
</span> </span>
{% else %} {% else %}
<i class="fa fa-sign-in"></i> <a href="{% url 'users:login' %}">Connexion</a> <span class="tabulation2">
<i class="fa fa-sign-in-alt"></i> <a href="{% url 'users:login' %}">Connexion</a>
</span>
{% endif %} {% endif %}

View file

@ -10,7 +10,7 @@
<header class="major"> <header class="major">
<h2>Liste des admins</h2> <h2>Liste des admins</h2>
</header> </header>
<a class="button" href="{% url 'users:addAdmin' %}">Ajouter un admin</a><br><br> <a class="button" href="{% url 'users:addAdmin' %}"><i class="fa fa-user-plus"></i> Ajouter un admin</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -23,9 +23,9 @@
<tbody> <tbody>
{% for user in admins %} {% for user in admins %}
<tr> <tr>
<td>{{ user }} {% if user.is_superuser %}(superuser){% endif %}</td> <td><a href="{% url 'users:profile' user.pk %}">{{ user }}</a>{ {% if user.is_superuser %}(superuser){% endif %}</td>
<td><a class="button small" href="{% url 'users:profile' user.pk %}">Profil</a></td> <td><a class="button small" href="{% url 'users:profile' user.pk %}"><i class="fa fa-user"></i> Profil</a></td>
<td>{% if not user.is_superuser %}<a class="button small" href="{% url 'users:removeAdmin' user.pk %}">Retirer des admins</a>{% endif %}</td> <td>{% if not user.is_superuser %}<a class="button small" href="{% url 'users:removeAdmin' user.pk %}"><i class="fa fa-minus-square"></i> Retirer des admins</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -4,7 +4,7 @@
{% block navbar %} {% block navbar %}
<ul> <ul>
<li><a href="#first">Rechargements ({{user}})</a></li> <li><a href="#first">Rechargements (<a href="{% url 'profile:users' user.pk %}">{{user}}</a>)</a></li>
</ul> </ul>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View file

@ -10,7 +10,7 @@
{% block content %} {% block content %}
<section id="first" class="main special"> <section id="first" class="main special">
<header class="major"> <header class="major">
<h2>Consommations ({{user}})</h2> <h2>Consommations (<a href="{% url 'users:profile' user.pk %}">{{user}}</a>)</h2>
</header> </header>
<section id="rechargements"> <section id="rechargements">
<div class="table-wrapper"> <div class="table-wrapper">
@ -28,7 +28,7 @@
<tbody id="bodyTransaction"> <tbody id="bodyTransaction">
{% for c in consumptions %} {% for c in consumptions %}
<tr> <tr>
<td>{{c.product}}</td> <td>{% if perms.gestion.view_product %}<a href="{% url 'gestion:productProfile' c.product.pk %}">{{ c.product.name }}{% else %}{{c.product.name}}{% endif %}</a></td>
<td>{{c.quantity}}</td> <td>{{c.quantity}}</td>
<td>{{c.amount}}</td> <td>{{c.amount}}</td>
<td>{{c.paymentMethod}}</td> <td>{{c.paymentMethod}}</td>

View file

@ -10,7 +10,7 @@
{% block content %} {% block content %}
<section id="first" class="main special"> <section id="first" class="main special">
<header class="major"> <header class="major">
<h2>Consommations de menus ({{user}})</h2> <h2>Consommations de menus (<a href="{% url 'profile:users' user.pk %}">{{user}}</a>)</h2>
</header> </header>
<section id="rechargements"> <section id="rechargements">
<div class="table-wrapper"> <div class="table-wrapper">

View file

@ -21,12 +21,12 @@
<div class="row"> <div class="row">
{% if perms.auth.change_group %} {% if perms.auth.change_group %}
<div class="6u"> <div class="6u">
<a class="button" href="{% url 'users:editGroup' group.pk %}">Éditer</a> <a class="button" href="{% url 'users:editGroup' group.pk %}"><i class="fa fa-pencil-alt"></i> Éditer</a>
</div> </div>
{% endif %} {% endif %}
{% if perms.auth.delete_group %} {% if perms.auth.delete_group %}
<div class="6u"> <div class="6u">
<a class="button" href="{% url 'users:deleteGroup' group.pk %}">Supprimer</a> <a class="button" href="{% url 'users:deleteGroup' group.pk %}"><i class="fa fa-trash"></i> Supprimer</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
@ -49,7 +49,7 @@
<tr> <tr>
<td>{{perm.codename}}</td> <td>{{perm.codename}}</td>
<td>{{perm.name}}</td> <td>{{perm.name}}</td>
<td><a class="button small" href="{% url 'users:removeRight' group.pk perm.pk %}">Enlever le droit</a></td> <td><a class="button small" href="{% url 'users:removeRight' group.pk perm.pk %}"><i class="fa fa-minus-square"></i> Enlever le droit</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -72,9 +72,9 @@
<tbody> <tbody>
{% for user in group.user_set.all %} {% for user in group.user_set.all %}
<tr> <tr>
<td>{{ user }}</td> <td><a href="{% url 'users:profile' user.pk %}">{{user}}</a></td>
<td><a class="button small" href="{% url 'users:profile' user.pk %}">Profil</a></td> <td><a class="button small" href="{% url 'users:profile' user.pk %}"><i class="fa fa-user"></i> Profil</a></td>
<td><a class="button small" href="{% url 'users:removeUser' group.pk user.pk %}">Retirer</a></td> <td><a class="button small" href="{% url 'users:removeUser' group.pk user.pk %}"><i class="fa fa-minus-square"></i> Retirer</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -11,7 +11,7 @@
<h2>Liste des groupes de droit</h2> <h2>Liste des groupes de droit</h2>
</header> </header>
{% if perms.auth.add_group %} {% if perms.auth.add_group %}
<a href="{% url 'users:createGroup' %}" class="button">Ajouter un groupe de droit</a><br><br> <a href="{% url 'users:createGroup' %}" class="button"><i class="fa fa-plus-square"></i> Ajouter un groupe de droit</a><br><br>
{% endif %} {% endif %}
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
@ -29,7 +29,7 @@
<td>{{ group.name }}</td> <td>{{ group.name }}</td>
<td>{{ group.permissions.count }}</td> <td>{{ group.permissions.count }}</td>
<td>{{ group.user_set.count }}</td> <td>{{ group.user_set.count }}</td>
<td><a href="{% url 'users:groupProfile' group.pk %}" class="button small">Voir</a> {% if perms.auth.change_group %}<a href="{% url 'users:editGroup' group.pk %}" class="button small">Éditer</a> {% endif %}{% if perms.auth.delete_group %}<a href="{% url 'users:deleteGroup' group.pk %}" class="button small">Supprimer</a>{% endif %}</td> <td><a href="{% url 'users:groupProfile' group.pk %}" class="button small"><i class="fa fa-eye"></i> Voir</a> {% if perms.auth.change_group %}<a href="{% url 'users:editGroup' group.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Éditer</a> {% endif %}{% if perms.auth.delete_group %}<a href="{% url 'users:deleteGroup' group.pk %}" class="button small"><i class="fa fa-trash"></i> Supprimer</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -107,7 +107,7 @@
{% csrf_token %} {% csrf_token %}
{{export_form}} {{export_form}}
<br> <br>
<button class="button" target="_blank">Exporter au format csv</button> <button class="button" target="_blank"><i class="fa fa-file-csv"></i> Exporter au format csv</button>
</form> </form>
</section> </section>
{% endif %} {% endif %}

View file

@ -2,7 +2,7 @@
{% load static %} {% load static %}
{% load users_extra %} {% load users_extra %}
{% block entete %}{% if self %}Mon Profil{% else %}Profil de {{user}}{% endif %}{%endblock%} {% block entete %}{% if self %}Mon Profil{% else %}Profil de {{user}}{% endif %}{%endblock%}
{% block extra_script %}<script src="{% static 'jquery.js' %}"></script>{% endblock %}
{% block navbar %} {% block navbar %}
<ul> <ul>
<li><a href="#first">{% if self %}Mes informations {% else %} Informations {% endif %}</a> <li><a href="#first">{% if self %}Mes informations {% else %} Informations {% endif %}</a>
@ -52,19 +52,19 @@
<ul class="alt"> <ul class="alt">
<li> <li>
{% if self or perms.users.can_change_user %} {% if self or perms.users.can_change_user %}
<span><a href="{% url 'users:editUser' user.pk %}">Modifier {{self | yesno:"mes,les"}} informations</a></span> <span><a href="{% url 'users:editUser' user.pk %}"><i class="fa fa-pencil-alt"></i> Modifier {{self | yesno:"mes,les"}} informations</a></span>
{% endif %} {% endif %}
{% if self %} {% if self %}
<span class="tabulation"><a href="{% url 'users:editPassword' user.pk %}">Changer mon mot de passe</a></span> <span class="tabulation"><a href="{% url 'users:editPassword' user.pk %}"><i class="fa fa-user-lock"></i> Changer mon mot de passe</a></span>
{% endif %} {% endif %}
{% if perms.users.can_reset_password %} {% if perms.users.can_reset_password %}
<span class="tabulation"><a href="{% url 'users:resetPassword' user.pk %}">Réinitialiser le mot de passe</a></span> <span class="tabulation"><a href="{% url 'users:resetPassword' user.pk %}"><i class="fa fa-lock-open"></i> Réinitialiser le mot de passe</a></span>
{% endif %} {% endif %}
{% if perms.users.can_change_user_perm %} {% if perms.users.can_change_user_perm %}
<span class="tabulation"><a href="{% url 'users:editGroups' user.pk %}">Changer les groupes</a></span> <span class="tabulation"><a href="{% url 'users:editGroups' user.pk %}"><i class="fa fa-layer-group"></i> Changer les groupes</a></span>
{% endif %} {% endif %}
{% if perms.auth.change_user %} {% if perms.auth.change_user %}
<span class="tabulation"><a href="{% url 'users:switchActivateUser' user.pk %}">{{ user.is_active | yesno:"Désa,A"}}ctiver</a></span> <span class="tabulation"><a href="{% url 'users:switchActivateUser' user.pk %}"><i class="fa fa-check-circle"></i> {{ user.is_active | yesno:"Désa,A"}}ctiver</a></span>
{% endif %} {% endif %}
</li> </li>
</ul> </ul>
@ -76,6 +76,15 @@
<script src="{% static 'chart.min.js' %}"></script> <script src="{% static 'chart.min.js' %}"></script>
<script> <script>
var ctx = document.getElementById("myChart").getContext('2d'); var ctx = document.getElementById("myChart").getContext('2d');
baseColor = Math.round(Math.random()*255) + "," + Math.round(Math.random()*255) + "," + Math.round(Math.random()*255);
console.log(baseColor)
$.get("http://www.thecolorapi.com/scheme?rgb=" + baseColor + "&mode=analogic&count={{products | length}}", function( data ) {
colors = data.colors
var bgColor = []
for(var i = 0; i < colors.length; i++){
color = colors[i]
bgColor.push("rgb(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + ")")
}
var myChart = new Chart(ctx, { var myChart = new Chart(ctx, {
type: 'pie', type: 'pie',
data: { data: {
@ -83,11 +92,7 @@
datasets: [{ datasets: [{
label: '# of Votes', label: '# of Votes',
data: [{% for q in quantities %}{{q}}, {% endfor %}], data: [{% for q in quantities %}{{q}}, {% endfor %}],
backgroundColor: [ backgroundColor: bgColor
{% for q in products %}
'rgb({% random_filter 0 255 %}, {% random_filter 0 255 %}, {% random_filter 0 255 %})',
{% endfor %}
],
}] }]
}, },
options: { options: {
@ -100,6 +105,7 @@
} }
} }
}); });
}, "json" );
</script> </script>
</section> </section>
</section> </section>
@ -124,12 +130,12 @@
<tbody id="bodyTransaction"> <tbody id="bodyTransaction">
{% for c in lastConsumptions %} {% for c in lastConsumptions %}
<tr> <tr>
<td>{{c.product}}</td> <td>{% if perms.gestion.view_product %}<a href="{% url 'gestion:productProfile' c.product.pk %}">{{ c.product.name }}</a>{% else %}{{c.product}}{% endif %}</td>
<td>{{c.quantity}}</td> <td>{{c.quantity}}</td>
<td>{{c.amount}} €</td> <td>{{c.amount}} €</td>
<td>{{c.paymentMethod}}</td> <td>{{c.paymentMethod}}</td>
<td>{{c.date}}</td> <td>{{c.date}}</td>
<td>{% if perms.gestion.delete_consumptionhistory %}<a href="{% url 'gestion:cancelConsumption' c.pk %}" class="button small">Annuler</a>{% endif %}</td> <td>{% if perms.gestion.delete_consumptionhistory %}<a href="{% url 'gestion:cancelConsumption' c.pk %}" class="button small"><i class="fa fa-times"></i> Annuler</a>{% endif %}</td>
</tr> </tr>
{%endfor%} {%endfor%}
</tbody> </tbody>
@ -163,7 +169,7 @@
<td>{{m.amount}} €</td> <td>{{m.amount}} €</td>
<td>{{m.paymentMethod}}</td> <td>{{m.paymentMethod}}</td>
<td>{{m.date}}</td> <td>{{m.date}}</td>
<td>{% if perms.gestion.delete_menuhistory %}<a href="{% url 'gestion:cancelMenu' m.pk %}" class="button small">Annuler</a>{% endif %}</td> <td>{% if perms.gestion.delete_menuhistory %}<a href="{% url 'gestion:cancelMenu' m.pk %}" class="button small"><i class="fa fa-times"></i> Annuler</a>{% endif %}</td>
</tr> </tr>
{%endfor%} {%endfor%}
</tbody> </tbody>
@ -196,7 +202,7 @@
<td>{{reload.PaymentMethod}}</td> <td>{{reload.PaymentMethod}}</td>
<td>{{reload.date}}</td> <td>{{reload.date}}</td>
{% if perms.gestion.delete_reload %} {% if perms.gestion.delete_reload %}
<th><a href="{% url 'gestion:cancelReload' reload.pk %}" class="button small">Annuler</a></th> <th><a href="{% url 'gestion:cancelReload' reload.pk %}" class="button small"><i class="fa fa-times"></i> Annuler</a></th>
{% endif %} {% endif %}
</tr> </tr>
{% endfor %} {% endfor %}
@ -211,7 +217,7 @@
<h2>{{ self | yesno:"Mes cotisations,Cotisations"}}</h2> <h2>{{ self | yesno:"Mes cotisations,Cotisations"}}</h2>
</header> </header>
<section> <section>
<a class="button" href="{% url 'users:addCotisationHistory' user.pk %}">Ajouter une cotisation</a><br><br> <a class="button" href="{% url 'users:addCotisationHistory' user.pk %}"><i class="fa fa-comments-dollar"></i> Ajouter une cotisation</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -234,7 +240,7 @@
<td>{{cotisation.paymentMethod}}</td> <td>{{cotisation.paymentMethod}}</td>
<td>{{cotisation.endDate}}</td> <td>{{cotisation.endDate}}</td>
<td>{{cotisation.valid}}</td> <td>{{cotisation.valid}}</td>
<td>{% if perms.users.validate_cotisationHistory %}<a class="button small" href="{% url 'users:validateCotisationHistory' cotisation.pk %}">Valider</a> <a class="button small" href="{% url 'users:invalidateCotisationHistory' cotisation.pk %}">Invalider</a>{% endif %}</td> <td>{% if perms.users.validate_cotisationHistory %}<a class="button small" href="{% url 'users:validateCotisationHistory' cotisation.pk %}"><i class="fa fa-check-circle"></i> Valider</a> <a class="button small" href="{% url 'users:invalidateCotisationHistory' cotisation.pk %}"><i class="fa fa-times-circle"></i> Invalider</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -248,7 +254,7 @@
<h2>{{ self | yesno:"Mes accès gracieux,Accès gracieux"}}</h2> <h2>{{ self | yesno:"Mes accès gracieux,Accès gracieux"}}</h2>
</header> </header>
<section> <section>
<a class="button" href="{% url 'users:addWhiteListHistory' user.pk %}">Ajouter un accès à titre gracieux</a><br><br> <a class="button" href="{% url 'users:addWhiteListHistory' user.pk %}"><i class="fa fa-handshake"></i> Ajouter un accès à titre gracieux</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>

View file

@ -10,7 +10,7 @@
<header class="major"> <header class="major">
<h2>Liste des écoles</h2> <h2>Liste des écoles</h2>
</header> </header>
<a class="button" href="{% url 'users:createSchool' %}">Créer une école</a><br><br> <a class="button" href="{% url 'users:createSchool' %}"><i class="fa fa-school"></i> Créer une école</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -23,7 +23,7 @@
{% for school in schools %} {% for school in schools %}
<tr> <tr>
<td>{{ school }}</td> <td>{{ school }}</td>
<td>{% if perms.gestion.change_school %}<a class="button small" href="{% url 'users:editSchool' school.pk %}">Modifier</a> {% endif %}{% if perms.gestion.delete_school %}<a class="button small" href="{% url 'users:deleteSchool' school.pk %}">Supprimer</a>{% endif %}</td> <td>{% if perms.gestion.change_school %}<a class="button small" href="{% url 'users:editSchool' school.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a> {% endif %}{% if perms.gestion.delete_school %}<a class="button small" href="{% url 'users:deleteSchool' school.pk %}"><i class="fa fa-trash"></i> Supprimer</a>{% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -10,7 +10,7 @@
<header class="major"> <header class="major">
<h2>Liste des superusers</h2> <h2>Liste des superusers</h2>
</header> </header>
<a class="button" href="{% url 'users:addSuperuser' %}">Ajouter un superuser</a><br><br> <a class="button" href="{% url 'users:addSuperuser' %}"><i class="fa fa-user-plus"></i> Ajouter un superuser</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -23,9 +23,9 @@
<tbody> <tbody>
{% for user in superusers %} {% for user in superusers %}
<tr> <tr>
<td>{{ user }}</td> <td><a href="{% url 'users:profile' user.pk %}">{{user}}</a></td>
<td><a class="button small" href="{% url 'users:profile' user.pk %}">Profil</a></td> <td><a class="button small" href="{% url 'users:profile' user.pk %}"><i class="fa fa-user"></i> Profil</a></td>
<td><a class="button small" href="{% url 'users:removeSuperuser' user.pk %}">Retirer des superusers</a></td> <td><a class="button small" href="{% url 'users:removeSuperuser' user.pk %}"><i class="fa fa-minus-square"></i> Retirer des superusers</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -10,7 +10,7 @@
<header class="major"> <header class="major">
<h2>Liste des utilisateurs</h2> <h2>Liste des utilisateurs</h2>
</header> </header>
<a class="button" href="{% url 'users:createUser' %}">Créer un utilisateur</a><br><br> <a class="button" href="{% url 'users:createUser' %}"><i class="fa fa-user-plus"></i> Créer un utilisateur</a><br><br>
<div class="table-wrapper"> <div class="table-wrapper">
<table> <table>
<thead> <thead>
@ -25,10 +25,10 @@
<tbody> <tbody>
{% for user in users %} {% for user in users %}
<tr> <tr>
<td>{{ user }}</td> <td><a href="{% url 'users:profile' user.pk %}">{{user}}</a></td>
<td><a class="button small" href="{% url 'users:profile' user.pk %}">Profil</a></td> <td><a class="button small" href="{% url 'users:profile' user.pk %}"><i class="fa fa-user"></i> Profil</a></td>
{% if perms.auth.change_user %} {% if perms.auth.change_user %}
<td><a class="button small" href="{% url 'users:switchActivateUser' user.pk %}">{{ user.is_active | yesno:"Désa,A"}}ctiver</a></td> <td><a class="button small" href="{% url 'users:switchActivateUser' user.pk %}">{% if user.is_active %}<i class="fa fa-times-circle"></i> Désactiver{% else %}<i class="fa fa-check-circle"></i> Activer{% endif %}</a></td>
{% endif %} {% endif %}
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -52,7 +52,7 @@ def loginView(request):
return redirect(reverse('users:profile', kwargs={'pk':request.user.pk})) return redirect(reverse('users:profile', kwargs={'pk':request.user.pk}))
else: else:
messages.error(request, "Nom d'utilisateur et/ou mot de passe invalide") messages.error(request, "Nom d'utilisateur et/ou mot de passe invalide")
return render(request, "form.html", {"form_entete": "Connexion", "form": form, "form_title": "Connexion", "form_button": "Se connecter"}) return render(request, "form.html", {"form_entete": "Connexion", "form": form, "form_title": "Connexion", "form_button": "Se connecter", "form_button_icon": "sign-in-alt"})
@active_required @active_required
@login_required @login_required
@ -225,7 +225,7 @@ def createUser(request):
user.save() user.save()
messages.success(request, "L'utilisateur a bien été créé") messages.success(request, "L'utilisateur a bien été créé")
return redirect(reverse('users:profile', kwargs={'pk':user.pk})) return redirect(reverse('users:profile', kwargs={'pk':user.pk}))
return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form":form, "form_title":"Création d'un nouvel utilisateur", "form_button":"Créer l'utilisateur"}) return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form":form, "form_title":"Création d'un nouvel utilisateur", "form_button":"Créer l'utilisateur", "form_button_icon": "user-plus"})
@active_required @active_required
@login_required @login_required
@ -252,7 +252,7 @@ def searchUser(request):
form = SelectUserForm(request.POST or None) form = SelectUserForm(request.POST or None)
if(form.is_valid()): if(form.is_valid()):
return redirect(reverse('users:profile', kwargs={"pk":form.cleaned_data['user'].pk})) return redirect(reverse('users:profile', kwargs={"pk":form.cleaned_data['user'].pk}))
return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form": form, "form_title": "Rechercher un utilisateur", "form_button": "Afficher le profil"}) return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form": form, "form_title": "Rechercher un utilisateur", "form_button": "Afficher le profil", "form_button_icon": "search"})
@active_required @active_required
@login_required @login_required
@ -305,7 +305,7 @@ def editGroups(request, pk):
messages.success(request, "Les groupes de l'utilisateur " + user.username + " ont bien été enregistrés.") messages.success(request, "Les groupes de l'utilisateur " + user.username + " ont bien été enregistrés.")
return redirect(reverse('users:profile', kwargs={'pk':pk})) return redirect(reverse('users:profile', kwargs={'pk':pk}))
extra_css = "#id_groups{height:200px;}" extra_css = "#id_groups{height:200px;}"
return render(request, "form.html", {"form_entete": "Gestion de l'utilisateur " + user.username, "form": form, "form_title": "Modification des groupes", "form_button": "Enregistrer", "extra_css": extra_css}) return render(request, "form.html", {"form_entete": "Gestion de l'utilisateur " + user.username, "form": form, "form_title": "Modification des groupes", "form_button": "Enregistrer", "form_button_icon": "pencil-alt", "extra_css": extra_css})
@active_required @active_required
@login_required @login_required
@ -345,7 +345,7 @@ def editPassword(request, pk):
return redirect(reverse('users:profile', kwargs={'pk':pk})) return redirect(reverse('users:profile', kwargs={'pk':pk}))
else: else:
messages.error(request, "Le mot de passe actuel est incorrect") messages.error(request, "Le mot de passe actuel est incorrect")
return render(request, "form.html", {"form_entete": "Modification de mon compte", "form": form, "form_title": "Modification de mon mot de passe", "form_button": "Modifier mon mot de passe"}) return render(request, "form.html", {"form_entete": "Modification de mon compte", "form": form, "form_title": "Modification de mon mot de passe", "form_button": "Modifier mon mot de passe", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -379,7 +379,7 @@ def editUser(request, pk):
user.save() user.save()
messages.success(request, "Les modifications ont bien été enregistrées") messages.success(request, "Les modifications ont bien été enregistrées")
return redirect(reverse('users:profile', kwargs={'pk': pk})) return redirect(reverse('users:profile', kwargs={'pk': pk}))
return render(request, "form.html", {"form_entete":"Modification du compte " + user.username, "form": form, "form_title": "Modification des informations", "form_button": "Modifier"}) return render(request, "form.html", {"form_entete":"Modification du compte " + user.username, "form": form, "form_title": "Modification des informations", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -413,7 +413,7 @@ def getUser(request, pk):
The pk of the user The pk of the user
""" """
user = get_object_or_404(User, pk=pk) user = get_object_or_404(User, pk=pk)
data = json.dumps({"username": user.username, "balance": user.profile.balance}) data = json.dumps({"username": user.username, "balance": user.profile.balance, "is_adherent": user.profile.is_adherent})
return HttpResponse(data, content_type='application/json') return HttpResponse(data, content_type='application/json')
@active_required @active_required
@ -583,7 +583,7 @@ def createGroup(request):
group = form.save() group = form.save()
messages.success(request, "Le groupe " + form.cleaned_data['name'] + " a bien été crée.") messages.success(request, "Le groupe " + form.cleaned_data['name'] + " a bien été crée.")
return redirect(reverse('users:groupProfile', kwargs={'pk': group.pk})) return redirect(reverse('users:groupProfile', kwargs={'pk': group.pk}))
return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form":form, "form_title": "Création d'un groupe de droit", "form_button": "Créer le groupe de droit"}) return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form":form, "form_title": "Création d'un groupe de droit", "form_button": "Créer le groupe de droit", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -617,7 +617,7 @@ def editGroup(request, pk):
form.save() form.save()
messages.success(request, "Le groupe " + group.name + " a bien été modifié.") messages.success(request, "Le groupe " + group.name + " a bien été modifié.")
return redirect(reverse('users:groupProfile', kwargs={'pk': group.pk})) return redirect(reverse('users:groupProfile', kwargs={'pk': group.pk}))
return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form": form, "form_title": "Modification du groupe de droit " + group.name, "form_button": "Modifier le groupe de droit", "extra_css":extra_css}) return render(request, "form.html", {"form_entete": "Gestion des utilisateurs", "form": form, "form_title": "Modification du groupe de droit " + group.name, "form_button": "Modifier le groupe de droit", "form_button_icon": "pencil-alt", "extra_css":extra_css})
@active_required @active_required
@login_required @login_required
@ -736,7 +736,7 @@ def addAdmin(request):
user.save() user.save()
messages.success(request, "L'utilisateur " + user.username + " a bien été rajouté aux admins") messages.success(request, "L'utilisateur " + user.username + " a bien été rajouté aux admins")
return redirect(reverse('users:adminsIndex')) return redirect(reverse('users:adminsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un admin", "form_button":"Ajouter l'utilisateur aux admins"}) return render(request, "form.html", {"form": form, "form_title": "Ajout d'un admin", "form_button": "Ajouter l'utilisateur aux admins", "form_button_icon": "user-plus"})
@active_required @active_required
@login_required @login_required
@ -814,7 +814,7 @@ def addSuperuser(request):
user.save() user.save()
messages.success(request, "L'utilisateur " + user.username + " a bien été rajouté aux superusers") messages.success(request, "L'utilisateur " + user.username + " a bien été rajouté aux superusers")
return redirect(reverse('users:superusersIndex')) return redirect(reverse('users:superusersIndex'))
return render(request, "form.html", {"form_entete": "Gestion des superusers", "form": form, "form_title": "Ajout d'un superuser", "form_button":"Ajouter l'utilisateur aux superusers"}) return render(request, "form.html", {"form_entete": "Gestion des superusers", "form": form, "form_title": "Ajout d'un superuser", "form_button":"Ajouter l'utilisateur aux superusers", "form_button_icon": "user-plus"})
@active_required @active_required
@login_required @login_required
@ -888,7 +888,7 @@ def addCotisationHistory(request, pk):
cotisation.save() cotisation.save()
messages.success(request, "La cotisation a bien été ajoutée") messages.success(request, "La cotisation a bien été ajoutée")
return redirect(reverse('users:profile',kwargs={'pk':user.pk})) return redirect(reverse('users:profile',kwargs={'pk':user.pk}))
return render(request, "form.html",{"form": form, "form_title": "Ajout d'une cotisation pour l'utilisateur " + str(user), "form_button": "Ajouter"}) return render(request, "form.html",{"form": form, "form_title": "Ajout d'une cotisation pour l'utilisateur " + str(user), "form_button": "Ajouter", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -922,7 +922,7 @@ def invalidateCotisationHistory(request, pk):
user = cotisationHistory.user user = cotisationHistory.user
user.profile.cotisationEnd = user.profile.cotisationEnd - timedelta(days=cotisationHistory.duration) user.profile.cotisationEnd = user.profile.cotisationEnd - timedelta(days=cotisationHistory.duration)
if(cotisationHistory.paymentMethod.affect_balance): if(cotisationHistory.paymentMethod.affect_balance):
user.profile.balance += cotisation.amount user.profile.debit -= cotisationHistory.cotisation.amount
user.save() user.save()
messages.success(request, "La cotisation a bien été invalidée") messages.success(request, "La cotisation a bien été invalidée")
return HttpResponseRedirect(request.META.get('HTTP_REFERER')) return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
@ -969,7 +969,7 @@ def addWhiteListHistory(request, pk):
whiteList.save() whiteList.save()
messages.success(request, "L'accès gracieux a bien été ajouté") messages.success(request, "L'accès gracieux a bien été ajouté")
return redirect(reverse('users:profile', kwargs={'pk':user.pk})) return redirect(reverse('users:profile', kwargs={'pk':user.pk}))
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un accès gracieux pour " + user.username, "form_button": "Ajouter"}) return render(request, "form.html", {"form": form, "form_title": "Ajout d'un accès gracieux pour " + user.username, "form_button": "Ajouter", "form_button_icon": "plus-square"})
########## Schools ########## ########## Schools ##########
@ -1019,7 +1019,7 @@ def createSchool(request):
form.save() form.save()
messages.success(request, "L'école a bien été créée") messages.success(request, "L'école a bien été créée")
return redirect(reverse('users:schoolsIndex')) return redirect(reverse('users:schoolsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Création d'une école", "form_button": "Créer"}) return render(request, "form.html", {"form": form, "form_title": "Création d'une école", "form_button": "Créer", "form_button_icon": "plus-square"})
@active_required @active_required
@login_required @login_required
@ -1052,7 +1052,7 @@ def editSchool(request, pk):
form.save() form.save()
messages.success(request, "L'école a bien été modifiée") messages.success(request, "L'école a bien été modifiée")
return redirect(reverse('users:schoolsIndex')) return redirect(reverse('users:schoolsIndex'))
return render(request, "form.html", {"form": form, "form_title": "Modification de l'école " + str(school), "form_button": "Modifier"}) return render(request, "form.html", {"form": form, "form_title": "Modification de l'école " + str(school), "form_button": "Modifier", "form_button": "pencil-alt"})
@active_required @active_required
@login_required @login_required
@ -1079,7 +1079,7 @@ class AllUsersAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = User.objects.all() qs = User.objects.all()
if self.q: if self.q:
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q)) qs = qs.filter(Q(username__contains=self.q) | Q(first_name__contains=self.q) | Q(last_name__contains=self.q))
return qs return qs
class ActiveUsersAutocomplete(autocomplete.Select2QuerySetView): class ActiveUsersAutocomplete(autocomplete.Select2QuerySetView):
@ -1089,7 +1089,7 @@ class ActiveUsersAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = User.objects.filter(is_active=True) qs = User.objects.filter(is_active=True)
if self.q: if self.q:
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q)) qs = qs.filter(Q(username__contains=self.q) | Q(first_name__contains=self.q) | Q(last_name__contains=self.q))
return qs return qs
class AdherentAutocomplete(autocomplete.Select2QuerySetView): class AdherentAutocomplete(autocomplete.Select2QuerySetView):
@ -1098,8 +1098,13 @@ class AdherentAutocomplete(autocomplete.Select2QuerySetView):
""" """
def get_queryset(self): def get_queryset(self):
qs = User.objects.all() qs = User.objects.all()
pks = [x.pk for x in qs if x.is_adherent]
qs = User.objects.filter(pk__in=pks)
if self.q:
qs = qs.filter(Q(username__contains=self.q) | Q(first_name__contains=self.q) | Q(last_name__contains=self.q))
return qs return qs
class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView): class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView):
""" """
Autocomplete for non-superuser users Autocomplete for non-superuser users
@ -1107,7 +1112,7 @@ class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = User.objects.filter(is_superuser=False) qs = User.objects.filter(is_superuser=False)
if self.q: if self.q:
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q)) qs = qs.filter(Q(username__contains=self.q) | Q(first_name__contains=self.q) | Q(last_name__contains=self.q))
return qs return qs
class NonAdminUserAutocomplete(autocomplete.Select2QuerySetView): class NonAdminUserAutocomplete(autocomplete.Select2QuerySetView):
@ -1117,5 +1122,5 @@ class NonAdminUserAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self): def get_queryset(self):
qs = User.objects.filter(is_staff=False) qs = User.objects.filter(is_staff=False)
if self.q: if self.q:
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q)) qs = qs.filter(Q(username__contains=self.q) | Q(first_name__contains=self.q) | Q(last_name__contains=self.q))
return qs return qs