mirror of https://github.com/nanoy42/coope
54 changed files with 2199 additions and 188 deletions
@ -0,0 +1,3 @@ |
|||
{ |
|||
"python.pythonPath": "/home/nanoy/.virtualenvs/coopeV3/bin/python" |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
from django import template |
|||
|
|||
from preferences.models import GeneralPreferences |
|||
|
|||
register = template.Library() |
|||
|
|||
@register.simple_tag |
|||
def president(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.president |
|||
|
|||
@register.simple_tag |
|||
def vice_president(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.vice_president |
|||
|
|||
@register.simple_tag |
|||
def treasurer(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.treasurer |
|||
|
|||
@register.simple_tag |
|||
def secretary(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.secretary |
|||
|
|||
@register.simple_tag |
|||
def brewer(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.brewer |
|||
|
|||
@register.simple_tag |
|||
def grocer(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.grocer |
|||
|
|||
@register.simple_tag |
|||
def global_message(): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
return gp.global_message |
|||
@ -1,13 +1,11 @@ |
|||
from django.forms.widgets import Input |
|||
from django.forms.widgets import Select, Input |
|||
from django.template import Context, Template |
|||
from django.template.loader import get_template |
|||
|
|||
class SearchField: |
|||
def __init__(self, url): |
|||
self.url = url |
|||
class SearchField(Input): |
|||
|
|||
def render(self, name, value, attrs=None): |
|||
super().render(name, value, attrs) |
|||
#super().render(name, value, attrs) |
|||
template = get_template('search_field.html') |
|||
context = Context({}) |
|||
return template.render(context) |
|||
|
|||
@ -1,3 +1,8 @@ |
|||
from django.contrib import admin |
|||
|
|||
# Register your models here. |
|||
from .models import Reload, Refund, Product, Keg |
|||
|
|||
admin.site.register(Reload) |
|||
admin.site.register(Refund) |
|||
admin.site.register(Product) |
|||
admin.site.register(Keg) |
|||
|
|||
@ -0,0 +1,37 @@ |
|||
from django import forms |
|||
from django.contrib.auth.models import User |
|||
|
|||
from dal import autocomplete |
|||
|
|||
from .models import Reload, Refund, Product, Keg, Menu |
|||
from preferences.models import PaymentMethod |
|||
from coopeV3.widgets import SearchField |
|||
|
|||
class ReloadForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Reload |
|||
fields = ("customer", "amount", "PaymentMethod") |
|||
|
|||
class RefundForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Refund |
|||
fields = ("customer", "amount") |
|||
|
|||
class ProductForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Product |
|||
fields = "__all__" |
|||
|
|||
class KegForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Keg |
|||
fields = "__all__" |
|||
|
|||
class MenuForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Menu |
|||
fields = "__all__" |
|||
|
|||
class GestionForm(forms.Form): |
|||
client = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Client", widget=autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2})) |
|||
paymentMethod = forms.ModelChoiceField(queryset=PaymentMethod.objects.all(), required=True, label="Moyen de paiement") |
|||
@ -0,0 +1,212 @@ |
|||
{% extends "base.html" %} |
|||
{% load static %} |
|||
|
|||
{%block entete%}<h1>Gestion de la Coopé™</h1>{%endblock%} |
|||
|
|||
{% block navbar %} |
|||
<ul> |
|||
{% if perms.gestion.can_add_consumption_history %}<li><a href="#first">Commande</a></li>{% endif %} |
|||
{% if perms.gestion.can_add_reload %}<li><a href="#second">Rechargement Client</a></li>{% endif %} |
|||
{% if perms.gestion.can_add_refund %}<li><a href="#third">Remboursement client</a><li>{% endif %} |
|||
</ul> |
|||
{% endblock %} |
|||
|
|||
|
|||
{% block content %} |
|||
<a class="up_button" href="#intro"> |
|||
UP |
|||
</a> |
|||
<style> |
|||
.up_button{ |
|||
display:block; |
|||
background-color:white; |
|||
position:fixed; |
|||
border-radius:100%; |
|||
width:50px; |
|||
height:50px; |
|||
color:black; |
|||
text-align:center; |
|||
line-height:50px; |
|||
right:1em; |
|||
bottom : 1em; |
|||
} |
|||
</style> |
|||
<section id="intro" class="main"> |
|||
<div class="spotlight"> |
|||
<div class="content"> |
|||
<header class="major"> |
|||
<h2>Transaction</h2> |
|||
</header> |
|||
<div class="row uniform"> |
|||
<div class="12u$"> |
|||
{{gestion_form}} |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<h3>Récapitulatif</h3> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="12u$"> |
|||
<table id="sumUpTable"> |
|||
<thead> |
|||
<tr> |
|||
<th>Solde</th> |
|||
<th>Montant total de la commande</th> |
|||
<th>Solde après la commande</th> |
|||
<th>Payer</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr> |
|||
<td id="balance">0€</td> |
|||
<td id="totalAmount">0€</td> |
|||
<td id="totalAfter">0€</td> |
|||
<td><button class="btn small">Payer</button></td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<h3>Produits</h3> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="12u$"> |
|||
<table id="productTable" type="input" name="tableau" class="alt"> |
|||
<thead> |
|||
<tr> |
|||
<th>CodeBarre</th> |
|||
<th>Nom Produit</th> |
|||
<th>Prix Unitaire</th> |
|||
<th>Quantité</th> |
|||
<th>Sous-total</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody id="items"> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="12u$"> |
|||
<div class="boutonProduit"> |
|||
<table> |
|||
<tbody class="actions" id="bouton Produit"> |
|||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bières pression</td></tr> |
|||
{% for produit in bieresPression %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="product" target="{{produit.barcode}}">{{produit.name}}</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 bouteilles</td></tr> |
|||
{% for produit in bieresBouteille %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="boutonsProduit" disabled target="{{produit.codeBarre}}" type="{{produit.typeSaisie}}">{{produit.nom}}</button></td> |
|||
{% if forloop.counter|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% if not bieresBouteille|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Paninis</td></tr> |
|||
{% for produit in panini %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="boutonsProduit" disabled target="{{produit.codeBarre}}" type="{{produit.typeSaisie}}">{{produit.nom}}</button></td> |
|||
{% if forloop.counter|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% if not panini|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Softs</td></tr> |
|||
{% for produit in soft %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="boutonsProduit" disabled target="{{produit.codeBarre}}" type="{{produit.typeSaisie}}">{{produit.nom}}</button></td> |
|||
{% if forloop.counter|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% if not soft|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
|
|||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bouffe</td></tr> |
|||
{% for produit in autreBouffe %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="boutonsProduit" disabled target="{{produit.codeBarre}}" type="{{produit.typeSaisie}}">{{produit.nom}}</button></td> |
|||
{% if forloop.counter|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% if not autreBouffe|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% if menus %} |
|||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Menus</td></tr> |
|||
{% for produit in menus %} |
|||
{% if forloop.counter0|divisibleby:4 %} |
|||
<tr style="text-align:center"> |
|||
{% endif %} |
|||
<td><button class="boutonsProduit" disabled target="{{produit.codeBarre}}" type="MN">{{produit.nom}}</button></td> |
|||
{% if forloop.counter|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% if not menus|divisibleby:4 %} |
|||
</tr> |
|||
{% endif %} |
|||
{% endif %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
{% if perms.gestion.cand_add_reload %} |
|||
<section id="second" class="main"> |
|||
<header class="major"> |
|||
<h2>Rechargement client</h2> |
|||
</header> |
|||
<form method="post" action="{% url 'gestion:reload' %}"> |
|||
{% csrf_token %} |
|||
{{reload_form}} |
|||
<br> |
|||
<button type="submit">Recharger</button> |
|||
</form> |
|||
</section> |
|||
{% endif %} |
|||
{% if perms.gestion.can_refund %} |
|||
<section id="third" class="main"> |
|||
<header class="major"> |
|||
<h2>Remboursement client</h2> |
|||
</header> |
|||
<form method="post" action="{% url 'gestion:refund' %}"> |
|||
{% csrf_token %} |
|||
{{refund_form}} |
|||
<br> |
|||
<button type="submit">Rembourser</button> |
|||
</form> |
|||
</section> |
|||
{% endif %} |
|||
{{gestion_form.media}} |
|||
<script src="{% static 'manage.js' %}"></script> |
|||
{%endblock%} |
|||
@ -0,0 +1,55 @@ |
|||
{% extends 'base.html' %} |
|||
{% block entete %}<h1>Gestion des produits</h1>{% endblock %} |
|||
{% block navbar%} |
|||
<ul> |
|||
<li><a href="#first">Produits</a></li> |
|||
<li><a href="#second">Futs</a></li> |
|||
<li><a href="#third">Menus</a></li> |
|||
<li><a href="#fourth">Stocks</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Produits</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'gestion:addProduct' %}">Créer un produit</a></li> |
|||
<li><a href="{% url 'users:searchUser' %}">Rechercher un produit</a></li> |
|||
<li><a href="{% url 'users:usersIndex' %}">Lister tous les produits</a></li> |
|||
</ul> |
|||
</section> |
|||
<section id="second" class="main"> |
|||
<header class="major"> |
|||
<h2>Futs</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'gestion:addBarrel' %}">Créer un fut</a></li> |
|||
<li><a href="">Percuter un fut</a></li> |
|||
<li><a href="">Lister les futs</a></li> |
|||
</ul> |
|||
</section> |
|||
<section id="third" class="main"> |
|||
<header class="major"> |
|||
<h2>Menus</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'gestion:addMenu' %}">Créer un menu</a></li> |
|||
<li><a href="">Rechercher un menu</a></li> |
|||
<li><a href="{% url 'users:adminsIndex' %}">Lister les menus</a></li> |
|||
</ul> |
|||
</section> |
|||
<section id="fourth" class="main"> |
|||
<header class="major"> |
|||
<h2>Stocks</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'users:addSuperuser' %}">Voir les Stocks</a></li> |
|||
<li><a href="{% url 'users:superusersIndex' %}">Classement sur un produit</a></li> |
|||
</ul> |
|||
</section> |
|||
{% endblock %} |
|||
@ -0,0 +1,55 @@ |
|||
{% extends 'base.html' %} |
|||
{% block entete %}<h1>Gestion des produits</h1>{% endblock %} |
|||
{% block navbar%} |
|||
<ul> |
|||
<li><a href="#first">Produits</a></li> |
|||
<li><a href="#second">Futs</a></li> |
|||
<li><a href="#third">Menus</a></li> |
|||
<li><a href="#fourth">Stocks</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Liste des produits</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'gestion:addProduct' %}">Créer un produit</a></li> |
|||
<li><a href="{% url 'users:searchUser' %}">Rechercher un produit</a></li> |
|||
<li><a href="{% url 'users:usersIndex' %}">Lister tous les produits</a></li> |
|||
</ul> |
|||
</section> |
|||
<section id="second" class="main"> |
|||
<header class="major"> |
|||
<h2>Futs</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'users:createGroup' %}">Créer un fut</a></li> |
|||
<li><a href="">Percuter un fut</a></li> |
|||
<li><a href="">Lister les futs</a><li> |
|||
</ul> |
|||
</section> |
|||
<section id="third" class="main"> |
|||
<header class="major"> |
|||
<h2>Menus</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'users:addAdmin' %}">Créer un menu</a></li> |
|||
<li><a href="">Rechercher un menu</a></li> |
|||
<li><a href="{% url 'users:adminsIndex' %}">Lister les menus</a></li> |
|||
</ul> |
|||
</section> |
|||
<section id="fourth" class="main"> |
|||
<header class="major"> |
|||
<h2>Stocks</h2> |
|||
</header> |
|||
Actions possibles : |
|||
<ul> |
|||
<li><a href="{% url 'users:addSuperuser' %}">Voir les Stocks</a></li> |
|||
<li><a href="{% url 'users:superusersIndex' %}">Classement sur un produit</a></li> |
|||
</ul> |
|||
</section> |
|||
{% endblock %} |
|||
@ -1,4 +1,108 @@ |
|||
from django.shortcuts import render |
|||
from django.shortcuts import render, redirect |
|||
from django.contrib import messages |
|||
from django.urls import reverse |
|||
from django.http import HttpResponse |
|||
from django.contrib.auth.models import User |
|||
|
|||
import json |
|||
from dal import autocomplete |
|||
|
|||
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm |
|||
from .models import Product, Menu, Keg |
|||
|
|||
def manage(request): |
|||
return render(request, "base.html") |
|||
gestion_form = GestionForm(request.POST or None) |
|||
reload_form = ReloadForm(request.POST or None) |
|||
refund_form = RefundForm(request.POST or None) |
|||
bieresPression = [] |
|||
bieresBouteille = Product.objects.filter(category=Product.BOTTLE).filter(is_active=True) |
|||
panini = Product.objects.filter(category=Product.PANINI).filter(is_active=True) |
|||
food = Product.objects.filter(category=Product.FOOD).filter(is_active=True) |
|||
soft = Product.objects.filter(category=Product.SOFT).filter(is_active=True) |
|||
menus = Menu.objects.filter(is_active=True) |
|||
kegs = Keg.objects.filter(is_active=True) |
|||
for keg in kegs: |
|||
if(keg.pinte): |
|||
bieresPression.append(keg.pinte) |
|||
if(keg.demi): |
|||
bieresPression.append(keg.demi) |
|||
if(keg.galopin): |
|||
bieresPression.append(keg.galopin) |
|||
return render(request, "gestion/manage.html", {"gestion_form": gestion_form, "reload_form": reload_form, "refund_form": refund_form, "bieresPression": bieresPression, "bieresBouteille": bieresBouteille, "panini": panini, "food": food, "soft": soft, "menus": menus}) |
|||
|
|||
def reload(request): |
|||
reload_form = ReloadForm(request.POST or None) |
|||
if(reload_form.is_valid()): |
|||
reloadEntry = reload_form.save(commit=False) |
|||
reloadEntry.coopeman = request.user |
|||
reloadEntry.save() |
|||
user = reload_form.cleaned_data['customer'] |
|||
amount = reload_form.cleaned_data['amount'] |
|||
user.profile.credit += amount |
|||
user.save() |
|||
messages.success(request,"Le compte de " + user.username + " a bien été crédité de " + str(amount) + "€") |
|||
else: |
|||
messages.error(request, "Le rechargement a échoué") |
|||
return redirect(reverse('gestion:manage')) |
|||
|
|||
def refund(request): |
|||
refund_form = RefundForm(request.POST or None) |
|||
if(refund_form.is_valid()): |
|||
user = refund_form.cleaned_data['customer'] |
|||
amount = refund_form.cleaned_data['amount'] |
|||
if(amount <= user.profile.balance): |
|||
refundEntry = refund_form.save(commit = False) |
|||
refundEntry.coopeman = request.user |
|||
refundEntry.save() |
|||
user.profile.credit -= amount |
|||
user.save() |
|||
messages.success(request, "Le compte de " + user.username + " a bien été remboursé de " + str(amount) + "€") |
|||
else: |
|||
messages.error(request, "Impossible de rembourser l'utilisateur " + user.username + " de " + str(amount) + "€ : il n'a que " + str(user.profile.balance) + "€ sur son compte.") |
|||
else: |
|||
messages.error(request, "Le remboursement a échoué") |
|||
return redirect(reverse('gestion:manage')) |
|||
|
|||
def productsIndex(request): |
|||
return render(request, "gestion/products_index.html") |
|||
|
|||
def addProduct(request): |
|||
form = ProductForm(request.POST or None) |
|||
if(form.is_valid()): |
|||
form.save() |
|||
messages.success(request, "Le produit a bien été ajouté") |
|||
return redirect(reverse('gestion:productsIndex')) |
|||
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter"}) |
|||
|
|||
def productsList(request): |
|||
products = Product.objects.all() |
|||
return render(request, "gestion/products_list.html", {"products": products}) |
|||
|
|||
def getProduct(request, barcode): |
|||
product = Product.objects.get(barcode=barcode) |
|||
data = json.dumps({"pk": product.pk, "barcode" : product.barcode, "name": product.name, "amount" : float(product.amount)}) |
|||
return HttpResponse(data, content_type='application/json') |
|||
|
|||
|
|||
########## Kegs ########## |
|||
|
|||
def addKeg(request): |
|||
form = KegForm(request.POST or None) |
|||
if(form.is_valid()): |
|||
keg = form.save() |
|||
messages.success(request, "Le fût " + keg.name + " a bien été ajouté") |
|||
return redirect(reverse('gestion:productsIndex')) |
|||
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un fût", "form_button": "Ajouter"}) |
|||
|
|||
|
|||
########## Menus ########## |
|||
|
|||
def addMenu(request): |
|||
form = MenuForm(request.POST or None) |
|||
extra_css = "#id_articles{height:200px;}" |
|||
if(form.is_valid()): |
|||
menu = form.save() |
|||
messages.success(request, "Le menu " + menu.name + " a bien été ajouté") |
|||
return redirect(reverse('gestion:productsIndex')) |
|||
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un menu", "form_button": "Ajouter", "extra_css": extra_css}) |
|||
|
|||
|
|||
@ -1,3 +1,8 @@ |
|||
from django.contrib import admin |
|||
|
|||
from .models import PaymentMethod, GeneralPreferences, Cotisation |
|||
|
|||
admin.site.register(PaymentMethod) |
|||
admin.site.register(GeneralPreferences) |
|||
admin.site.register(Cotisation) |
|||
# Register your models here. |
|||
|
|||
@ -0,0 +1,30 @@ |
|||
from django import forms |
|||
|
|||
from .models import Cotisation, PaymentMethod, GeneralPreferences |
|||
|
|||
class CotisationForm(forms.ModelForm): |
|||
class Meta: |
|||
model = Cotisation |
|||
fields = "__all__" |
|||
|
|||
class PaymentMethodForm(forms.ModelForm): |
|||
class Meta: |
|||
model = PaymentMethod |
|||
fields = "__all__" |
|||
|
|||
|
|||
class GeneralPreferencesForm(forms.ModelForm): |
|||
class Meta: |
|||
model = GeneralPreferences |
|||
fields = "__all__" |
|||
widgets = { |
|||
'global_message': forms.Textarea(attrs={'placeholder': 'Message global à afficher sur le site'}), |
|||
'active_message': forms.Textarea(attrs={'placeholder': 'Ce message s\'affichera si le site n\'est pas actif'}), |
|||
'president': forms.TextInput(attrs={'placeholder': 'Président'}), |
|||
'vice_president': forms.TextInput(attrs={'placeholder': 'Vice-président'}), |
|||
'secretary': forms.TextInput(attrs={'placeholder': 'Secrétaire'}), |
|||
'treasurer': forms.TextInput(attrs={'placeholder': 'Trésorier'}), |
|||
'brewer': forms.TextInput(attrs={'placeholder': 'Maître brasseur'}), |
|||
'grocer': forms.TextInput(attrs={'placeholder': 'Epic épicier'}), |
|||
} |
|||
|
|||
@ -0,0 +1,35 @@ |
|||
{% extends "base.html" %} |
|||
{% block entete %}<h1>Gestion des cotisations</h1>{% endblock %} |
|||
{% block navbar %} |
|||
<ul> |
|||
<li><a href="#first">Liste des cotisations</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Liste des cotisations</h2> |
|||
</header> |
|||
<a class="button" href="{% url 'preferences:addCotisation' %}">Créer une cotisation</a><br><br> |
|||
<div class="table-wrapper"> |
|||
<table> |
|||
<thead> |
|||
<tr> |
|||
<th>Durée de cotisation</th> |
|||
<th>Prix</th> |
|||
<th>Administration</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for cotisation in cotisations %} |
|||
<tr> |
|||
<td>{{ cotisation.duration }} jours</td> |
|||
<td>{{ cotisation.amount }} €</td> |
|||
<td><a class="button small" href="{% url 'preferences:editCotisation' cotisation.pk %}">Modifier</a> <a class="button small" href="{% url 'preferences:deleteCotisation' cotisation.pk %}">Supprimer</a></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</section> |
|||
{% endblock %} |
|||
@ -0,0 +1,89 @@ |
|||
{% extends 'base.html' %} |
|||
{% block entete %} |
|||
<h1>Administration</h1> |
|||
{% endblock %} |
|||
{% block nav %} |
|||
<ul> |
|||
<li><a href="#first" class="active">Message global</a></li> |
|||
<li><a href="#second">Site actif</a></li> |
|||
<li><a href="#third">Bureau</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
|
|||
{% block content %} |
|||
<form class="main" method="post" action=""> |
|||
{% csrf_token %} |
|||
<section id="first" class="main"> |
|||
<div class="spotlight"> |
|||
<div class="content"> |
|||
<header class="major"> |
|||
<h2>Message global</h2> |
|||
</header> |
|||
<div class="row"> |
|||
<div class="12u"> |
|||
{{form.global_message}} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<section id="second" class="main"> |
|||
<div class="spotlight"> |
|||
<div class="content"> |
|||
<header class="major"> |
|||
<h2>Site actif</h2> |
|||
</header> |
|||
<div class="row uniform"> |
|||
<div class="12u"> |
|||
{{form.is_active}} |
|||
<label for="{{form.is_active.id_for_label}}">Site actif ?</label> |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="12u"> |
|||
{{form.active_message}} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<section id="third" class="main"> |
|||
<div class="spotlight"> |
|||
<div class="content"> |
|||
<header class="major"> |
|||
<h2>Bureau</h2> |
|||
</header> |
|||
<div class="row uniform"> |
|||
<div class="6u"> |
|||
{{form.president}} |
|||
</div> |
|||
<div class="6u"> |
|||
{{form.vice_president}} |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="6u"> |
|||
{{form.secretary}} |
|||
</div> |
|||
<div class="6u"> |
|||
{{form.treasurer}} |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="6u"> |
|||
{{form.grocer}} |
|||
</div> |
|||
<div class="6u"> |
|||
{{form.brewer}} |
|||
</div> |
|||
</div> |
|||
<div class="row uniform"> |
|||
<div class="12u"> |
|||
<button type="submit">Enregistrer</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
</form> |
|||
{% endblock %} |
|||
@ -0,0 +1,39 @@ |
|||
{% extends "base.html" %} |
|||
{% block entete %}<h1>Gestion des moyens de paiement</h1>{% endblock %} |
|||
{% block navbar %} |
|||
<ul> |
|||
<li><a href="#first">Liste des moyens de paiement</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Liste des moyens de paiement</h2> |
|||
</header> |
|||
<a class="button" href="{% url 'preferences:addPaymentMethod' %}">Créer un moyen de paiement</a><br><br> |
|||
<div class="table-wrapper"> |
|||
<table> |
|||
<thead> |
|||
<tr> |
|||
<th>Nom</th> |
|||
<th>Actif ?</th> |
|||
<th>Utilisable dans les cotisations</th> |
|||
<th>Affecte le solde</th> |
|||
<th>Administration</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for pm in paymentMethods %} |
|||
<tr> |
|||
<td>{{ pm.name }} </td> |
|||
<td>{{ pm.is_active | yesno:"Oui, Non"}}</td> |
|||
<td>{{ pm.is_usable_in_cotisation | yesno:"Oui, Non" }}</td> |
|||
<td>{{ pm.affect_balance | yesno:"Oui, Non" }}</td> |
|||
<td><a class="button small" href="{% url 'preferences:editPaymentMethod' pm.pk %}">Modifier</a> <a class="button small" href="{% url 'preferences:deletePaymentMethod' pm.pk %}">Supprimer</a></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</section> |
|||
{% endblock %} |
|||
@ -0,0 +1,16 @@ |
|||
from django.urls import path |
|||
|
|||
from . import views |
|||
|
|||
app_name="preferences" |
|||
urlpatterns = [ |
|||
path('generalPreferences', views.generalPreferences, name="generalPreferences"), |
|||
path('cotisationsIndex', views.cotisationsIndex, name="cotisationsIndex"), |
|||
path('addCotisation', views.addCotisation, name="addCotisation"), |
|||
path('editCotisation/<int:pk>', views.editCotisation, name="editCotisation"), |
|||
path('deleteCotisation/<int:pk>', views.deleteCotisation, name="deleteCotisation"), |
|||
path('paymentMethodsIndex', views.paymentMethodsIndex, name="paymentMethodsIndex"), |
|||
path('addPaymentMethod', views.addPaymentMethod, name="addPaymentMethod"), |
|||
path('editPaymentMethod/<int:pk>', views.editPaymentMethod, name="editPaymentMethod"), |
|||
path('deletePaymentMethod/<int:pk>', views.deletePaymentMethod, name="deletePaymentMethod"), |
|||
] |
|||
@ -1,3 +1,75 @@ |
|||
from django.shortcuts import render |
|||
from django.shortcuts import render, redirect, get_object_or_404 |
|||
from django.contrib import messages |
|||
from django.urls import reverse |
|||
|
|||
# Create your views here. |
|||
from .models import GeneralPreferences, Cotisation, PaymentMethod |
|||
|
|||
from .forms import CotisationForm, PaymentMethodForm, GeneralPreferencesForm |
|||
|
|||
def generalPreferences(request): |
|||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1) |
|||
form = GeneralPreferencesForm(request.POST or None, instance=gp) |
|||
if(form.is_valid()): |
|||
form.save() |
|||
return render(request, "preferences/general_preferences.html", {"form": form}) |
|||
|
|||
########## Cotisations ########## |
|||
|
|||
def cotisationsIndex(request): |
|||
cotisations = Cotisation.objects.all() |
|||
return render(request, "preferences/cotisations_index.html", {"cotisations": cotisations}) |
|||
|
|||
def addCotisation(request): |
|||
form = CotisationForm(request.POST or None) |
|||
if(form.is_valid()): |
|||
cotisation = form.save() |
|||
messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été créée") |
|||
return redirect(reverse('preferences:cotisationsIndex')) |
|||
return render(request, "form.html", {"form": form, "form_title": "Création d'une cotisation", "form_button": "Créer"}) |
|||
|
|||
def editCotisation(request, pk): |
|||
cotisation = get_object_or_404(Cotisation, pk=pk) |
|||
form = CotisationForm(request.POST or None, instance=cotisation) |
|||
if(form.is_valid()): |
|||
cotisation = form.save() |
|||
messages.success(request, "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été modifiée") |
|||
return redirect(reverse('preferences:cotisationsIndex')) |
|||
return render(request, "form.html", {"form": form, "form_title": "Modification d'une cotisation", "form_button": "Modifier"}) |
|||
|
|||
def deleteCotisation(request,pk): |
|||
cotisation = get_object_or_404(Cotisation, pk=pk) |
|||
message = "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été supprimée" |
|||
cotisation.delete() |
|||
messages.success(request, message) |
|||
return redirect(reverse('preferences:cotisationsIndex')) |
|||
|
|||
|
|||
########## Payment Methods ########## |
|||
|
|||
def paymentMethodsIndex(request): |
|||
paymentMethods = PaymentMethod.objects.all() |
|||
return render(request, "preferences/payment_methods_index.html", {"paymentMethods": paymentMethods}) |
|||
|
|||
def addPaymentMethod(request): |
|||
form = PaymentMethodForm(request.POST or None) |
|||
if(form.is_valid()): |
|||
paymentMethod = form.save() |
|||
messages.success(request, "Le moyen de paiement " + paymentMethod.name + " a bien été crée") |
|||
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"}) |
|||
|
|||
def editPaymentMethod(request, pk): |
|||
paymentMethod = get_object_or_404(PaymentMethod, pk=pk) |
|||
form = PaymentMethodForm(request.POST or None, instance=paymentMethod) |
|||
if(form.is_valid()): |
|||
paymentMethod = form.save() |
|||
messages.success(request, "Le moyen de paiment " + paymentMethod.name + " a bien été modifié") |
|||
return redirect(reverse('preferences:paymentMethodsIndex')) |
|||
return render(request, "form.html", {"form": form, "form_title": "Modification d'un moyen de paiement", "form_button": "Modifier"}) |
|||
|
|||
def deletePaymentMethod(request,pk): |
|||
paymentMethod = get_object_or_404(PaymentMethod, pk=pk) |
|||
message = "Le moyen de paiement " + paymentMethod.name + " a bien été supprimé" |
|||
paymentMethod.delete() |
|||
messages.success(request, message) |
|||
return redirect(reverse('preferences:paymentMethodsIndex')) |
|||
|
|||
@ -1,2 +1,3 @@ |
|||
Django==2.1 |
|||
django-autocomplete-light==3.3.2 |
|||
pytz==2018.5 |
|||
|
|||
@ -0,0 +1,162 @@ |
|||
/* |
|||
This script garantees that this will be called once in django admin. |
|||
However, its the callback's responsability to clean up if the |
|||
element was cloned with data - which should be the case. |
|||
*/ |
|||
|
|||
;(function ($) { |
|||
$.fn.getFormPrefix = function() { |
|||
/* Get the form prefix for a field. |
|||
* |
|||
* For example: |
|||
* |
|||
* $(':input[name$=owner]').getFormsetPrefix() |
|||
* |
|||
* Would return an empty string for an input with name 'owner' but would return |
|||
* 'inline_model-0-' for an input named 'inline_model-0-owner'. |
|||
*/ |
|||
var parts = $(this).attr('name').split('-'); |
|||
var prefix = ''; |
|||
|
|||
for (var i in parts) { |
|||
var testPrefix = parts.slice(0, -i).join('-'); |
|||
if (! testPrefix.length) continue; |
|||
testPrefix += '-'; |
|||
|
|||
var result = $(':input[name^=' + testPrefix + ']') |
|||
|
|||
if (result.length) { |
|||
return testPrefix; |
|||
} |
|||
} |
|||
|
|||
return ''; |
|||
} |
|||
|
|||
$.fn.getFormPrefixes = function() { |
|||
/* |
|||
* Get the form prefixes for a field, from the most specific to the least. |
|||
* |
|||
* For example: |
|||
* |
|||
* $(':input[name$=owner]').getFormPrefixes() |
|||
* |
|||
* Would return: |
|||
* - [''] for an input named 'owner'. |
|||
* - ['inline_model-0-', ''] for an input named 'inline_model-0-owner' (i.e. nested with a nested inline). |
|||
* - ['sections-0-items-0-', 'sections-0-', ''] for an input named 'sections-0-items-0-product' |
|||
* (i.e. nested multiple time with django-nested-admin). |
|||
*/ |
|||
var parts = $(this).attr('name').split('-').slice(0, -1); |
|||
var prefixes = []; |
|||
|
|||
for (i = 0; i < parts.length; i += 2) { |
|||
var testPrefix = parts.slice(0, -i || parts.length).join('-'); |
|||
if (!testPrefix.length) |
|||
continue; |
|||
|
|||
testPrefix += '-'; |
|||
|
|||
var result = $(':input[name^=' + testPrefix + ']') |
|||
|
|||
if (result.length) |
|||
prefixes.push(testPrefix); |
|||
} |
|||
|
|||
prefixes.push(''); |
|||
|
|||
return prefixes; |
|||
} |
|||
|
|||
var initialized = []; |
|||
|
|||
function initialize(element) { |
|||
if (typeof element === 'undefined' || typeof element === 'number') { |
|||
element = this; |
|||
} |
|||
|
|||
if (window.__dal__initListenerIsSet !== true || initialized.indexOf(element) >= 0) { |
|||
return; |
|||
} |
|||
|
|||
$(element).trigger('autocompleteLightInitialize'); |
|||
initialized.push(element); |
|||
} |
|||
|
|||
if (!window.__dal__initialize) { |
|||
window.__dal__initialize = initialize; |
|||
|
|||
$(document).ready(function () { |
|||
$('[data-autocomplete-light-function=select2]:not([id*="__prefix__"])').each(initialize); |
|||
}); |
|||
|
|||
$(document).bind('DOMNodeInserted', function (e) { |
|||
$(e.target).find('[data-autocomplete-light-function=select2]:not([id*="__prefix__"])').each(initialize); |
|||
}); |
|||
} |
|||
|
|||
// using jQuery
|
|||
function getCookie(name) { |
|||
var cookieValue = null; |
|||
if (document.cookie && document.cookie != '') { |
|||
var cookies = document.cookie.split(';'); |
|||
for (var i = 0; i < cookies.length; i++) { |
|||
var cookie = $.trim(cookies[i]); |
|||
// Does this cookie string begin with the name we want?
|
|||
if (cookie.substring(0, name.length + 1) == (name + '=')) { |
|||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return cookieValue; |
|||
} |
|||
|
|||
document.csrftoken = getCookie('csrftoken'); |
|||
if (document.csrftoken === null) { |
|||
// Try to get CSRF token from DOM when cookie is missing
|
|||
var $csrf = $('form :input[name="csrfmiddlewaretoken"]'); |
|||
if ($csrf.length > 0) { |
|||
document.csrftoken = $csrf[0].value; |
|||
} |
|||
} |
|||
})(yl.jQuery); |
|||
|
|||
// Does the same thing as django's admin/js/autocomplete.js, but uses yl.jQuery.
|
|||
(function($) { |
|||
'use strict'; |
|||
var init = function($element, options) { |
|||
var settings = $.extend({ |
|||
ajax: { |
|||
data: function(params) { |
|||
return { |
|||
term: params.term, |
|||
page: params.page |
|||
}; |
|||
} |
|||
} |
|||
}, options); |
|||
$element.select2(settings); |
|||
}; |
|||
|
|||
$.fn.djangoAdminSelect2 = function(options) { |
|||
var settings = $.extend({}, options); |
|||
$.each(this, function(i, element) { |
|||
var $element = $(element); |
|||
init($element, settings); |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
$(function() { |
|||
// Initialize all autocomplete widgets except the one in the template
|
|||
// form used when a new formset is added.
|
|||
$('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); |
|||
}); |
|||
|
|||
$(document).on('formset:added', (function() { |
|||
return function(event, $newFormset) { |
|||
return $newFormset.find('.admin-autocomplete').djangoAdminSelect2(); |
|||
}; |
|||
})(this)); |
|||
}(yl.jQuery)); |
|||
@ -0,0 +1,183 @@ |
|||
;(function($, yl) { |
|||
yl.forwardHandlerRegistry = yl.forwardHandlerRegistry || {}; |
|||
|
|||
yl.registerForwardHandler = function(name, handler) { |
|||
yl.forwardHandlerRegistry[name] = handler; |
|||
}; |
|||
|
|||
yl.getForwardHandler = function(name) { |
|||
return yl.forwardHandlerRegistry[name]; |
|||
}; |
|||
|
|||
function getForwardStrategy(element) { |
|||
var checkForCheckboxes = function() { |
|||
var all = true; |
|||
$.each(element, function(ix, e) { |
|||
if ($(e).attr("type") !== "checkbox") { |
|||
all = false; |
|||
} |
|||
}); |
|||
return all; |
|||
}; |
|||
|
|||
if (element.length === 1 && |
|||
element.attr("type") === "checkbox" && |
|||
element.attr("value") === undefined) { |
|||
// Single checkbox without 'value' attribute
|
|||
// Boolean field
|
|||
return "exists"; |
|||
} else if (element.length === 1 && |
|||
element.attr("multiple") !== undefined) { |
|||
// Multiple by HTML semantics. E. g. multiple select
|
|||
// Multiple choice field
|
|||
return "multiple"; |
|||
} else if (checkForCheckboxes()) { |
|||
// Multiple checkboxes or one checkbox with 'value' attribute.
|
|||
// Multiple choice field represented by checkboxes
|
|||
return "multiple"; |
|||
} else { |
|||
// Other cases
|
|||
return "single"; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Get fields with name `name` relative to `element` with considering form |
|||
* prefixes. |
|||
* @param element the element |
|||
* @param name name of the field |
|||
* @returns jQuery object with found fields or empty jQuery object if no |
|||
* field was found |
|||
*/ |
|||
yl.getFieldRelativeTo = function(element, name) { |
|||
var prefixes = $(element).getFormPrefixes(); |
|||
|
|||
for (var i = 0; i < prefixes.length; i++) { |
|||
var fieldSelector = "[name=" + prefixes[i] + name + "]"; |
|||
var field = $(fieldSelector); |
|||
|
|||
if (field.length) { |
|||
return field; |
|||
} |
|||
} |
|||
|
|||
return $(); |
|||
}; |
|||
|
|||
/** |
|||
* Get field value which is put to forwarded dictionary |
|||
* @param field the field |
|||
* @returns forwarded value |
|||
*/ |
|||
yl.getValueFromField = function(field) { |
|||
var strategy = getForwardStrategy(field); |
|||
var serializedField = $(field).serializeArray(); |
|||
|
|||
var getSerializedFieldElementAt = function (index) { |
|||
// Return serializedField[index]
|
|||
// or null if something went wrong
|
|||
if (serializedField.length > index) { |
|||
return serializedField[index]; |
|||
} else { |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
var getValueOf = function (elem) { |
|||
// Return elem.value
|
|||
// or null if something went wrong
|
|||
if (elem.hasOwnProperty("value") && |
|||
elem.value !== undefined |
|||
) { |
|||
return elem.value; |
|||
} else { |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
var getSerializedFieldValueAt = function (index) { |
|||
// Return serializedField[index].value
|
|||
// or null if something went wrong
|
|||
var elem = getSerializedFieldElementAt(index); |
|||
if (elem !== null) { |
|||
return getValueOf(elem); |
|||
} else { |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
if (strategy === "multiple") { |
|||
return serializedField.map( |
|||
function (item) { |
|||
return getValueOf(item); |
|||
} |
|||
); |
|||
} else if (strategy === "exists") { |
|||
return serializedField.length > 0; |
|||
} else { |
|||
return getSerializedFieldValueAt(0); |
|||
} |
|||
}; |
|||
|
|||
yl.getForwards = function(element) { |
|||
var forwardElem, |
|||
forwardList, |
|||
forwardedData, |
|||
divSelector, |
|||
form; |
|||
divSelector = "div.dal-forward-conf#dal-forward-conf-for-" + |
|||
element.attr("id"); |
|||
form = element.length > 0 ? $(element[0].form) : $(); |
|||
|
|||
forwardElem = |
|||
form.find(divSelector).find('script'); |
|||
if (forwardElem.length === 0) { |
|||
return; |
|||
} |
|||
try { |
|||
forwardList = JSON.parse(forwardElem.text()); |
|||
} catch (e) { |
|||
return; |
|||
} |
|||
|
|||
if (!Array.isArray(forwardList)) { |
|||
return; |
|||
} |
|||
|
|||
forwardedData = {}; |
|||
|
|||
$.each(forwardList, function(ix, field) { |
|||
var srcName, dstName; |
|||
if (field.type === "const") { |
|||
forwardedData[field.dst] = field.val; |
|||
} else if (field.type === "self") { |
|||
if (field.hasOwnProperty("dst")) { |
|||
dstName = field.dst; |
|||
} else { |
|||
dstName = "self"; |
|||
} |
|||
forwardedData[dstName] = yl.getValueFromField(element); |
|||
} else if (field.type === "field") { |
|||
srcName = field.src; |
|||
if (field.hasOwnProperty("dst")) { |
|||
dstName = field.dst; |
|||
} else { |
|||
dstName = srcName; |
|||
} |
|||
var forwardedField = yl.getFieldRelativeTo(element, srcName); |
|||
|
|||
if (!forwardedField.length) { |
|||
return; |
|||
} |
|||
|
|||
forwardedData[dstName] = yl.getValueFromField(forwardedField); |
|||
} else if (field.type === "javascript") { |
|||
var handler = yl.getForwardHandler(field.handler); |
|||
forwardedData[field.dst || field.handler] = handler(element); |
|||
} |
|||
|
|||
}); |
|||
return JSON.stringify(forwardedData); |
|||
}; |
|||
|
|||
})(yl.jQuery, yl); |
|||
@ -0,0 +1,36 @@ |
|||
var yl = yl || {}; |
|||
if (typeof django !== 'undefined' && typeof django.jQuery !== 'undefined') { |
|||
// If django.jQuery is already defined, use it.
|
|||
yl.jQuery = django.jQuery; |
|||
} |
|||
else { |
|||
// We include jquery itself in our widget's media, because we need it.
|
|||
// Normally, we expect our widget's reference to admin/js/vendor/jquery/jquery.js
|
|||
// to be skipped, because django's own code has already included it.
|
|||
// However, if django.jQuery is NOT defined, we know that jquery was not
|
|||
// included before we did it ourselves. This can happen if we're not being
|
|||
// rendered in a django admin form.
|
|||
// However, someone ELSE'S jQuery may have been included before ours, in
|
|||
// which case we must ensure that our jquery doesn't override theirs, since
|
|||
// it might be a newer version that other code on the page relies on.
|
|||
// Thus, we must run jQuery.noConflict(true) here to move our jQuery out of
|
|||
// the way.
|
|||
yl.jQuery = jQuery.noConflict(true); |
|||
} |
|||
|
|||
// In addition to all of this, we must ensure that the global jQuery and $ are
|
|||
// defined, because Select2 requires that. jQuery will only be undefined at
|
|||
// this point if only we or django included it.
|
|||
if (typeof jQuery === 'undefined') { |
|||
jQuery = yl.jQuery; |
|||
$ = yl.jQuery; |
|||
} |
|||
else { |
|||
// jQuery IS still defined, which means someone else also included jQuery.
|
|||
// In this situation, we need to store the old jQuery in a
|
|||
// temp variable, set the global jQuery to our yl.jQuery, then let select2
|
|||
// set itself up. We restore the global jQuery to its original value in
|
|||
// jquery.post-setup.js.
|
|||
dal_jquery_backup = jQuery.noConflict(true); |
|||
jQuery = yl.jQuery; |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
if (typeof dal_jquery_backup !== 'undefined') { |
|||
// We made a backup of the original global jQuery before forcing it to our
|
|||
// yl.jQuery value. Now that select2 has been set up, we need to restore
|
|||
// our backup to its rightful place.
|
|||
jQuery = dal_jquery_backup; |
|||
$ = dal_jquery_backup; |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
.select2-container { |
|||
min-width: 20em; |
|||
} |
|||
|
|||
ul li.select2-selection__choice, |
|||
ul li.select2-search { |
|||
/* Cancel out django's style */ |
|||
list-style-type: none; |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
;(function ($) { |
|||
if (window.__dal__initListenerIsSet) |
|||
return; |
|||
|
|||
$(document).on('autocompleteLightInitialize', '[data-autocomplete-light-function=select2]', function() { |
|||
var element = $(this); |
|||
|
|||
// Templating helper
|
|||
function template(text, is_html) { |
|||
if (is_html) { |
|||
var $result = $('<span>'); |
|||
$result.html(text); |
|||
return $result; |
|||
} else { |
|||
return text; |
|||
} |
|||
} |
|||
|
|||
function result_template(item) { |
|||
return template(item.text, |
|||
element.attr('data-html') !== undefined || element.attr('data-result-html') !== undefined |
|||
); |
|||
} |
|||
|
|||
function selected_template(item) { |
|||
if (item.selected_text !== undefined) { |
|||
return template(item.selected_text, |
|||
element.attr('data-html') !== undefined || element.attr('data-selected-html') !== undefined |
|||
); |
|||
} else { |
|||
return result_template(item); |
|||
} |
|||
return |
|||
} |
|||
|
|||
var ajax = null; |
|||
if ($(this).attr('data-autocomplete-light-url')) { |
|||
ajax = { |
|||
url: $(this).attr('data-autocomplete-light-url'), |
|||
dataType: 'json', |
|||
delay: 250, |
|||
|
|||
data: function (params) { |
|||
var data = { |
|||
q: params.term, // search term
|
|||
page: params.page, |
|||
create: element.attr('data-autocomplete-light-create') && !element.attr('data-tags'), |
|||
forward: yl.getForwards(element) |
|||
}; |
|||
|
|||
return data; |
|||
}, |
|||
processResults: function (data, page) { |
|||
if (element.attr('data-tags')) { |
|||
$.each(data.results, function(index, value) { |
|||
value.id = value.text; |
|||
}); |
|||
} |
|||
|
|||
return data; |
|||
}, |
|||
cache: true |
|||
}; |
|||
} |
|||
|
|||
$(this).select2({ |
|||
tokenSeparators: element.attr('data-tags') ? [','] : null, |
|||
debug: true, |
|||
containerCssClass: ':all:', |
|||
placeholder: element.attr('data-placeholder') || '', |
|||
language: element.attr('data-autocomplete-light-language'), |
|||
minimumInputLength: element.attr('data-minimum-input-length') || 0, |
|||
allowClear: ! $(this).is('[required]'), |
|||
templateResult: result_template, |
|||
templateSelection: selected_template, |
|||
ajax: ajax, |
|||
tags: Boolean(element.attr('data-tags')), |
|||
}); |
|||
|
|||
$(this).on('select2:selecting', function (e) { |
|||
var data = e.params.args.data; |
|||
|
|||
if (data.create_id !== true) |
|||
return; |
|||
|
|||
e.preventDefault(); |
|||
|
|||
var select = $(this); |
|||
|
|||
$.ajax({ |
|||
url: $(this).attr('data-autocomplete-light-url'), |
|||
type: 'POST', |
|||
dataType: 'json', |
|||
data: { |
|||
text: data.id, |
|||
forward: yl.getForwards($(this)) |
|||
}, |
|||
beforeSend: function(xhr, settings) { |
|||
xhr.setRequestHeader("X-CSRFToken", document.csrftoken); |
|||
}, |
|||
success: function(data, textStatus, jqXHR ) { |
|||
select.append( |
|||
$('<option>', {value: data.id, text: data.text, selected: true}) |
|||
); |
|||
select.trigger('change'); |
|||
select.select2('close'); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
}); |
|||
window.__dal__initListenerIsSet = true; |
|||
$('[data-autocomplete-light-function=select2]:not([id*="__prefix__"])').each(function() { |
|||
window.__dal__initialize(this); |
|||
}); |
|||
})(yl.jQuery); |
|||
@ -1,17 +1,3 @@ |
|||
#listePseudoTransaction { |
|||
} |
|||
|
|||
#listePseudoTransaction .item { |
|||
padding: 3px; |
|||
font-family: Helvetica; |
|||
border: 1px solid #c0c0c0; |
|||
} |
|||
|
|||
#istePseudoTransaction .item:hover { |
|||
background-color: #f2f2f2; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.itemSelected { |
|||
background-color: #dcdcdc; |
|||
.select2-container{ |
|||
color: !black; |
|||
} |
|||
|
|||
File diff suppressed because one or more lines are too long
@ -0,0 +1,58 @@ |
|||
totalAmount = 0 |
|||
products = [] |
|||
paymentMethod = null |
|||
solde = 0 |
|||
|
|||
function get_product(barcode){ |
|||
res = $.get("getProduct/" + barcode, function(data){ |
|||
add_product(data.pk, data.barcode, data.name, data.amount); |
|||
}); |
|||
} |
|||
|
|||
function add_product(pk, barcode, name, amount){ |
|||
exist = false |
|||
index = -1 |
|||
for(k=0;k < products.length; k++){ |
|||
if(products[k].pk == pk){ |
|||
exist = true |
|||
index = k |
|||
} |
|||
} |
|||
if(exist){ |
|||
products[index].quantity += 1; |
|||
}else{ |
|||
products.push({"pk": pk, "barcode": barcode, "name": name, "amount": amount, "quantity": 1}); |
|||
} |
|||
generate_html() |
|||
} |
|||
|
|||
function generate_html(){ |
|||
html ="" |
|||
for(k=0;k<products.length;k++){ |
|||
product = products[k] |
|||
html += "<tr><td>" + product.barcode + "</td><td>" + product.name + "</td><td>" + String(product.amount) + "</td><td>" + String(product.quantity) + "</td><td>" + String(product.quantity * product.amount) + "</td></tr>" |
|||
} |
|||
$("#items").html(html) |
|||
updateTotal() |
|||
} |
|||
|
|||
function updateTotal(){ |
|||
total = 0 |
|||
for(k=0;k<products.length;k++){ |
|||
total += products[k].quantity * products[k].amount |
|||
} |
|||
$("#totalAmount").text(String(total) + "€") |
|||
if(paymentMethod == "compte"){ |
|||
totalAfter = solde - total |
|||
$("#totalAfter").text(totalAfter + "€") |
|||
} |
|||
} |
|||
|
|||
$(document).ready(function(){ |
|||
$(".product").click(function(){ |
|||
product = get_product($(this).attr('target')); |
|||
}); |
|||
$("#id_paymentMethod").on('change', function(){ |
|||
alert('lol') |
|||
}); |
|||
}); |
|||
File diff suppressed because one or more lines are too long
@ -0,0 +1,67 @@ |
|||
totalAmount = 0 |
|||
products = [] |
|||
paymentMethod = null |
|||
balance = 0 |
|||
username = "" |
|||
id = 0 |
|||
|
|||
function get_product(barcode){ |
|||
res = $.get("getProduct/" + barcode, function(data){ |
|||
add_product(data.pk, data.barcode, data.name, data.amount); |
|||
}); |
|||
} |
|||
|
|||
function add_product(pk, barcode, name, amount){ |
|||
exist = false |
|||
index = -1 |
|||
for(k=0;k < products.length; k++){ |
|||
if(products[k].pk == pk){ |
|||
exist = true |
|||
index = k |
|||
} |
|||
} |
|||
if(exist){ |
|||
products[index].quantity += 1; |
|||
}else{ |
|||
products.push({"pk": pk, "barcode": barcode, "name": name, "amount": amount, "quantity": 1}); |
|||
} |
|||
generate_html() |
|||
} |
|||
|
|||
function generate_html(){ |
|||
html ="" |
|||
for(k=0;k<products.length;k++){ |
|||
product = products[k] |
|||
html += "<tr><td>" + product.barcode + "</td><td>" + product.name + "</td><td>" + String(product.amount) + "</td><td>" + String(product.quantity) + "</td><td>" + String(product.quantity * product.amount) + "</td></tr>" |
|||
} |
|||
$("#items").html(html) |
|||
updateTotal() |
|||
} |
|||
|
|||
function updateTotal(){ |
|||
total = 0 |
|||
for(k=0;k<products.length;k++){ |
|||
total += products[k].quantity * products[k].amount |
|||
} |
|||
$("#totalAmount").text(String(total) + "€") |
|||
totalAfter = balance - total |
|||
$("#totalAfter").text(totalAfter + "€") |
|||
} |
|||
|
|||
$(document).ready(function(){ |
|||
$(".product").click(function(){ |
|||
product = get_product($(this).attr('target')); |
|||
}); |
|||
$("#id_client").on('change', function(){ |
|||
id = $("#id_client").val(); |
|||
$.get("/users/getUser/" + id, function(data){ |
|||
balance = data.balance; |
|||
username = data.username; |
|||
$("#balance").html(balance + "€"); |
|||
updateTotal(); |
|||
}).fail(function(){ |
|||
alert("Une erreur inconnue est survenue"); |
|||
window.location.reload() |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,48 @@ |
|||
{% load vip %} |
|||
<section> |
|||
<h2>A propos</h2> |
|||
<p>{% lorem %}</p> |
|||
<ul class="actions"> |
|||
<li> |
|||
<a class="button" href="">En savoir plus</a> |
|||
</li> |
|||
</ul> |
|||
</section> |
|||
<section> |
|||
<h2>Contacts</h2> |
|||
<table> |
|||
<tr> |
|||
<td>Email</td> |
|||
<td>coopemetz@gmail.com</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Prez</td> |
|||
<td>{% president %}</td> |
|||
</tr> |
|||
<tr> |
|||
<td>V-Prez</td> |
|||
<td>{% vice_president %}</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Trésorier</td> |
|||
<td>{% treasurer %}</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Secrétaire</td> |
|||
<td>{% secretary %}</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Maitre brasseur</td> |
|||
<td>{% brewer %}</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Epic Epicier</td> |
|||
<td>{% grocer %}</td> |
|||
</tr> |
|||
</table> |
|||
<ul class="icons"> |
|||
<li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li> |
|||
</ul> |
|||
</section> |
|||
<p class="copyright">coopeV3 © 2016 - 2018. Remi Delannoy - Guillaume Goessel - Yoann Pietri. Design: <a href="https://html5up.net">HTML5 UP</a>.</p> |
|||
|
|||
@ -0,0 +1,37 @@ |
|||
{% if request.user.is_authenticated %} |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'users:profile' request.user.pk %}">Mon profil</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'gestion:manage' %}">Caisse</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'users:index' %}">Gestion des clients</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="">Comptabilité</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="">Classement</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="">Classement sur l'année</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'preferences:generalPreferences' %}">Admin</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'preferences:cotisationsIndex' %}">Cotisations</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'preferences:paymentMethodsIndex' %}">Moyens de paiement</a> |
|||
</span> |
|||
<span class="tabulation2"> |
|||
<a href="{% url 'users:logout' %}">Deconnexion</a> |
|||
</span> |
|||
{% else %} |
|||
<a href="{% url 'users:login' %}">Connexion</a> |
|||
{% endif %} |
|||
@ -0,0 +1,8 @@ |
|||
<input {{attrs}} name="{{name}}" type="text" class="form-control" placeholder="{{placeholder}}"/> |
|||
<script> |
|||
$(document).ready(function(){ |
|||
$("#" + {{attrs.id}}).click(function(){ |
|||
alert('lol') |
|||
}); |
|||
}; |
|||
</script> |
|||
@ -1,7 +1,8 @@ |
|||
from django.contrib import admin |
|||
|
|||
from .models import School, Profile |
|||
from .models import School, Profile, CotisationHistory |
|||
|
|||
admin.site.register(School) |
|||
admin.site.register(Profile) |
|||
admin.site.register(CotisationHistory) |
|||
# Register your models here. |
|||
|
|||
@ -0,0 +1,33 @@ |
|||
{% extends "base.html" %} |
|||
{% block entete %}<h1>Gestion des écoles</h1>{% endblock %} |
|||
{% block navbar %} |
|||
<ul> |
|||
<li><a href="#first">Liste des écoles</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Liste des écoles</h2> |
|||
</header> |
|||
<a class="button" href="{% url 'users:createSchool' %}">Créer une école</a><br><br> |
|||
<div class="table-wrapper"> |
|||
<table> |
|||
<thead> |
|||
<tr> |
|||
<th>Ecole</th> |
|||
<th>Administration</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for school in schools %} |
|||
<tr> |
|||
<td>{{ school }}</td> |
|||
<td><a class="button small" href="{% url 'users:editSchool' school.pk %}">Modifier</a> <a class="button small" href="{% url 'users:deleteSchool' school.pk %}">Supprimer</a></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</section> |
|||
{% endblock %} |
|||
@ -0,0 +1,33 @@ |
|||
{% extends "base.html" %} |
|||
{% block entete %}<h1>Gestion des utilisateurs</h1>{% endblock %} |
|||
{% block navbar %} |
|||
<ul> |
|||
<li><a href="#first">Liste des utilisateurs</a></li> |
|||
</ul> |
|||
{% endblock %} |
|||
{% block content %} |
|||
<section id="first" class="main"> |
|||
<header class="major"> |
|||
<h2>Liste des utilisateurs</h2> |
|||
</header> |
|||
<a class="button" href="{% url 'users:createUser' %}">Créer un utilisateur</a><br><br> |
|||
<div class="table-wrapper"> |
|||
<table> |
|||
<thead> |
|||
<tr> |
|||
<th>Utilisateur</th> |
|||
<th>Profil</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for user in users %} |
|||
<tr> |
|||
<td>{{ user }}</td> |
|||
<td><a class="button small" href="{% url 'users:profile' user.pk %}">Profil</a></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</section> |
|||
{% endblock %} |
|||
Loading…
Reference in new issue