mirror of
https://github.com/nanoy42/coope
synced 2024-12-23 15:33:45 +00:00
Commit
This commit is contained in:
parent
15e13f978c
commit
23eb8776a8
26 changed files with 748 additions and 112 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -39,3 +39,4 @@ tags
|
|||
|
||||
# End of https://www.gitignore.io/api/vim,git,django
|
||||
|
||||
.vscode
|
|
@ -37,12 +37,13 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.admindocs',
|
||||
'gestion',
|
||||
'users',
|
||||
'preferences',
|
||||
'coopeV3',
|
||||
'dal',
|
||||
'dal_select2',
|
||||
'dal_select2',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -129,4 +130,4 @@ STATICFILES_DIRS = [
|
|||
]
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
|
||||
|
||||
LOGIN_URL = '/users/login'
|
|
@ -20,8 +20,9 @@ from . import views
|
|||
|
||||
urlpatterns = [
|
||||
path('', views.home, name="home"),
|
||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('users/', include('users.urls')),
|
||||
path('gestion/', include('gestion.urls')),
|
||||
path('preferences/', include('preferences.urls')),
|
||||
path('preferences/', include('preferences.urls')),
|
||||
]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Reload, Refund, Product, Keg
|
||||
from .models import Reload, Refund, Product, Keg, ConsumptionHistory
|
||||
|
||||
admin.site.register(Reload)
|
||||
admin.site.register(Refund)
|
||||
admin.site.register(Product)
|
||||
admin.site.register(Keg)
|
||||
admin.site.register(ConsumptionHistory)
|
|
@ -1,4 +1,5 @@
|
|||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from dal import autocomplete
|
||||
|
@ -8,14 +9,38 @@ from preferences.models import PaymentMethod
|
|||
from coopeV3.widgets import SearchField
|
||||
|
||||
class ReloadForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ReloadForm, self).__init__(*args, **kwargs)
|
||||
self.fields['PaymentMethod'].queryset = PaymentMethod.objects.filter(is_usable_in_reload=True)
|
||||
|
||||
class Meta:
|
||||
model = Reload
|
||||
fields = ("customer", "amount", "PaymentMethod")
|
||||
widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2})}
|
||||
|
||||
def clean_amount(self):
|
||||
if self.cleaned_data['amount'] <= 0:
|
||||
raise ValidationError(
|
||||
"Le montant doit être strictement positif"
|
||||
)
|
||||
else:
|
||||
return self.cleaned_data['amount']
|
||||
|
||||
|
||||
class RefundForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Refund
|
||||
fields = ("customer", "amount")
|
||||
widgets = {'customer': autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2})}
|
||||
|
||||
def clean_amount(self):
|
||||
if self.cleaned_data['amount'] <= 0:
|
||||
raise ValidationError(
|
||||
"Le montant doit être strictement positif"
|
||||
)
|
||||
else:
|
||||
return self.cleaned_data['amount']
|
||||
|
||||
|
||||
class ProductForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
@ -32,6 +57,11 @@ class MenuForm(forms.ModelForm):
|
|||
model = Menu
|
||||
fields = "__all__"
|
||||
|
||||
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}))
|
||||
|
||||
class SearchMenuForm(forms.Form):
|
||||
menu = forms.ModelChoiceField(queryset=Menu.objects.all(), required=True, label="Menu", widget=autocomplete.ModelSelect2(url='gestion:menus-autocomplete', attrs={'data-minimum-input-length':2}))
|
||||
|
||||
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")
|
||||
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}))
|
|
@ -138,7 +138,7 @@ class MenuHistory(models.Model):
|
|||
coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="menu_selled")
|
||||
|
||||
def __str__(self):
|
||||
return "{2} a consommé {0} {1}".format(self.quantite, self.menu, self.client)
|
||||
return "{2} a consommé {0} {1}".format(self.quantity, self.menu, self.customer)
|
||||
|
||||
class ConsumptionHistory(models.Model):
|
||||
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_taken")
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
<td id="balance">0€</td>
|
||||
<td id="totalAmount">0€</td>
|
||||
<td id="totalAfter">0€</td>
|
||||
<td><button class="btn small">Payer</button></td>
|
||||
<td>{% for pm in pay_buttons %}<button class="btn small pay_button" data-payment="{{pm.pk}}">{{pm.name}}</button> {% endfor %}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -93,11 +93,11 @@
|
|||
<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 %}
|
||||
{% for product in bieresPression %}
|
||||
{% if forloop.counter0|divisibleby:4 %}
|
||||
<tr style="text-align:center">
|
||||
{% endif %}
|
||||
<td><button class="product" target="{{produit.barcode}}">{{produit.name}}</button></td>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -106,11 +106,11 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bières bouteilles</td></tr>
|
||||
{% for produit in bieresBouteille %}
|
||||
{% for product 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>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -119,11 +119,11 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Paninis</td></tr>
|
||||
{% for produit in panini %}
|
||||
{% for product 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>
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -132,11 +132,11 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Softs</td></tr>
|
||||
{% for produit in soft %}
|
||||
{% for product 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>
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -146,11 +146,11 @@
|
|||
{% endif %}
|
||||
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bouffe</td></tr>
|
||||
{% for produit in autreBouffe %}
|
||||
{% for product 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>
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -160,11 +160,11 @@
|
|||
{% endif %}
|
||||
{% if menus %}
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Menus</td></tr>
|
||||
{% for produit in menus %}
|
||||
{% for product 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>
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="MN">{{product.nom}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -208,5 +208,7 @@
|
|||
</section>
|
||||
{% endif %}
|
||||
{{gestion_form.media}}
|
||||
{{reload_form.media}}
|
||||
{{refund_form.media}}
|
||||
<script src="{% static 'manage.js' %}"></script>
|
||||
{%endblock%}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
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>
|
||||
<li><a href="{% url 'gestion:searchProduct' %}">Rechercher un produit</a></li>
|
||||
<li><a href="{% url 'gestion:productsList' %}">Lister tous les produits</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="second" class="main">
|
||||
|
@ -26,9 +26,10 @@
|
|||
</header>
|
||||
Actions possibles :
|
||||
<ul>
|
||||
<li><a href="{% url 'gestion:addBarrel' %}">Créer un fut</a></li>
|
||||
<li><a href="{% url 'gestion:addKeg' %}">Créer un fut</a></li>
|
||||
<li><a href="">Percuter un fut</a></li>
|
||||
<li><a href="">Lister les futs</a></li>
|
||||
<li><a href="">Historique des futs</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="third" class="main">
|
||||
|
|
|
@ -13,43 +13,40 @@
|
|||
<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>
|
||||
<a class="button" href="{% url 'gestion:addProduct' %}">Créer un produit</a><br><br>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Prix</th>
|
||||
<th>Stock (soute)</th>
|
||||
<th>Stock (bar)</th>
|
||||
<th>Code barre</th>
|
||||
<th>Catégorie</th>
|
||||
<th>Actif</th>
|
||||
<th>Degré</th>
|
||||
<th>Volume</th>
|
||||
<th>Administrer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for product in products %}
|
||||
<tr>
|
||||
<td>{{ product.name }}</td>
|
||||
<td>{{ product.amount}}</td>
|
||||
<td>{{ product.stockHold }}</td>
|
||||
<td>{{ product.stockBar }}</td>
|
||||
<td>{{ product.barcode }}</td>
|
||||
<td>{{ product.category }}</td>
|
||||
<td>{{ product.is_active }}</td>
|
||||
<td>{{ product.degree }}</td>
|
||||
<td>{{ product.volume }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -8,8 +8,15 @@ urlpatterns = [
|
|||
path('reload', views.reload, name="reload"),
|
||||
path('refund', views.refund, name="refund"),
|
||||
path('productsIndex', views.productsIndex, name="productsIndex"),
|
||||
path('productsList', views.productsList, name="productsList"),
|
||||
path('addProduct', views.addProduct, name="addProduct"),
|
||||
path('addKeg', views.addKeg, name="addKeg"),
|
||||
path('addMenu', views.addMenu, name="addMenu"),
|
||||
path('getProduct/<str:barcode>', views.getProduct, name="getProduct"),
|
||||
]
|
||||
path('order', views.order, name="order"),
|
||||
path('ranking', views.ranking, name="ranking"),
|
||||
path('annualRanking', views.annualRanking, name="annualRanking"),
|
||||
path('searchProduct', views.searchProduct, name="searchProduct"),
|
||||
path('productProfile/<int:pk>', views.productProfile, name="productProfile"),
|
||||
path('products-autocomplete', views.ProductsAutocomplete.as_view(), name="products-autocomplete"),
|
||||
]
|
138
gestion/views.py
138
gestion/views.py
|
@ -1,16 +1,26 @@
|
|||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
|
||||
import json
|
||||
from coopeV3.acl import active_required, acl_or
|
||||
|
||||
import simplejson as json
|
||||
from dal import autocomplete
|
||||
from decimal import *
|
||||
|
||||
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm
|
||||
from .models import Product, Menu, Keg
|
||||
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm
|
||||
from .models import Product, Menu, Keg, ConsumptionHistory
|
||||
from preferences.models import PaymentMethod
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@acl_or('gestion.add_consumptionhistory', 'gestion.add_reload', 'gestion.add_refund')
|
||||
def manage(request):
|
||||
pay_buttons = PaymentMethod.objects.filter(is_active=True)
|
||||
gestion_form = GestionForm(request.POST or None)
|
||||
reload_form = ReloadForm(request.POST or None)
|
||||
refund_form = RefundForm(request.POST or None)
|
||||
|
@ -28,8 +38,37 @@ def manage(request):
|
|||
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})
|
||||
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, "pay_buttons": pay_buttons})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_consumptionhistory')
|
||||
@csrf_exempt
|
||||
def order(request):
|
||||
print(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):
|
||||
raise Http404("Erreur du POST")
|
||||
else:
|
||||
user = get_object_or_404(User, pk=request.POST['user'])
|
||||
paymentMethod = get_object_or_404(PaymentMethod, pk=request.POST['paymentMethod'])
|
||||
amount = Decimal(request.POST['amount'])
|
||||
order = json.loads(request.POST["order"])
|
||||
if(len(order) == 0 or amount == 0):
|
||||
raise Http404("Pas de commande")
|
||||
if(paymentMethod.affect_balance):
|
||||
if(user.profile.balance < amount):
|
||||
raise Http404("Solde inférieur au prix de la commande")
|
||||
else:
|
||||
user.profile.debit += amount
|
||||
user.save()
|
||||
for o in order:
|
||||
print(o)
|
||||
product = get_object_or_404(Product, pk=o["pk"])
|
||||
ch = ConsumptionHistory(customer = user, quantity = int(o["quantity"]), paymentMethod=paymentMethod, product=product, amount=int(o["quantity"])*product.amount, coopeman=request.user)
|
||||
ch.save()
|
||||
return HttpResponse("La commande a bien été effectuée")
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_reload')
|
||||
def reload(request):
|
||||
reload_form = ReloadForm(request.POST or None)
|
||||
if(reload_form.is_valid()):
|
||||
|
@ -45,6 +84,8 @@ def reload(request):
|
|||
messages.error(request, "Le rechargement a échoué")
|
||||
return redirect(reverse('gestion:manage'))
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_refund')
|
||||
def refund(request):
|
||||
refund_form = RefundForm(request.POST or None)
|
||||
if(refund_form.is_valid()):
|
||||
|
@ -63,9 +104,15 @@ def refund(request):
|
|||
messages.error(request, "Le remboursement a échoué")
|
||||
return redirect(reverse('gestion:manage'))
|
||||
|
||||
########## Products ##########
|
||||
|
||||
@login_required
|
||||
@acl_or('gestion.add_product', 'gestion.view_product', 'gestion.add_keg', 'gestion.view_keg', 'gestion.change_keg', 'gestion.view_menu', 'gestion.add_menu')
|
||||
def productsIndex(request):
|
||||
return render(request, "gestion/products_index.html")
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_product')
|
||||
def addProduct(request):
|
||||
form = ProductForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -74,18 +121,43 @@ def addProduct(request):
|
|||
return redirect(reverse('gestion:productsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter"})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_product')
|
||||
def productsList(request):
|
||||
products = Product.objects.all()
|
||||
return render(request, "gestion/products_list.html", {"products": products})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_product')
|
||||
def searchProduct(request):
|
||||
form = SearchProductForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
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"})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_product')
|
||||
def productProfile(request, pk):
|
||||
product = get_object_or_404(Product, pk=pk)
|
||||
return render(request, "gestion/product_profile.html", {"product": product})
|
||||
|
||||
@login_required
|
||||
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)})
|
||||
data = json.dumps({"pk": product.pk, "barcode" : product.barcode, "name": product.name, "amount" : product.amount})
|
||||
return HttpResponse(data, content_type='application/json')
|
||||
|
||||
class ProductsAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = Product.objects.all()
|
||||
if self.q:
|
||||
qs = qs.filter(name__istartswith=self.q)
|
||||
return qs
|
||||
|
||||
########## Kegs ##########
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_keg')
|
||||
def addKeg(request):
|
||||
form = KegForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -97,6 +169,8 @@ def addKeg(request):
|
|||
|
||||
########## Menus ##########
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.add_menu')
|
||||
def addMenu(request):
|
||||
form = MenuForm(request.POST or None)
|
||||
extra_css = "#id_articles{height:200px;}"
|
||||
|
@ -106,3 +180,53 @@ def addMenu(request):
|
|||
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})
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_menu')
|
||||
def searchMenu(request):
|
||||
"""
|
||||
Search a menu via SearchMenuForm instance
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The SearchMenuForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
form = SearchMenuForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
menu = form.menu
|
||||
return redirect(reverse('gestion:changeMenu', kwargs={'pk':menu.pk}))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Recherche d'un menu", "form_button": "Modifier"})
|
||||
|
||||
class MenusAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = Menu.objects.all()
|
||||
if self.q:
|
||||
qs = qs.filter(name__istartswith=self.q)
|
||||
return qs
|
||||
########## Ranking ##########
|
||||
|
||||
@login_required
|
||||
def ranking(request):
|
||||
bestBuyers = User.objects.order_by('-profile__debit')[:25]
|
||||
customers = User.objects.all()
|
||||
list = []
|
||||
for customer in customers:
|
||||
alcohol = customer.profile.alcohol
|
||||
list.append([customer, alcohol])
|
||||
bestDrinkers = sorted(list, key=lambda x: x[1], reverse=True)[:25]
|
||||
return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers})
|
||||
|
||||
@login_required
|
||||
def annualRanking(request):
|
||||
return render(request, "gestion/annual_ranking.html")
|
|
@ -1,4 +1,5 @@
|
|||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from .models import Cotisation, PaymentMethod, GeneralPreferences
|
||||
|
||||
|
@ -6,6 +7,14 @@ class CotisationForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = Cotisation
|
||||
fields = "__all__"
|
||||
|
||||
def clean_amount(self):
|
||||
if self.cleaned_data['amount'] <= 0:
|
||||
raise ValidationError(
|
||||
"Le montant doit être strictement positif"
|
||||
)
|
||||
else:
|
||||
return self.cleaned_data['amount']
|
||||
|
||||
class PaymentMethodForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
|
|
@ -3,7 +3,8 @@ from django.db import models
|
|||
class PaymentMethod(models.Model):
|
||||
name = models.CharField(max_length=255, verbose_name="Nom")
|
||||
is_active = models.BooleanField(default=True, verbose_name="Actif")
|
||||
is_usable_in_cotisation = models.BooleanField(default=True, verbose_name="Utilisable pour les cotisations")
|
||||
is_usable_in_cotisation = models.BooleanField(default=True, verbose_name="Cotisations ?")
|
||||
is_usable_in_reload = models.BooleanField(default=True, verbose_name="Rechargements ?")
|
||||
affect_balance = models.BooleanField(default=False, verbose_name="Affecte le solde")
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Actif ?</th>
|
||||
<th>Utilisable dans les cotisations</th>
|
||||
<th>Cotisations ?</th>
|
||||
<th>Rechargements ?</th>
|
||||
<th>Affecte le solde</th>
|
||||
<th>Administration</th>
|
||||
</tr>
|
||||
|
@ -28,6 +29,7 @@
|
|||
<td>{{ pm.name }} </td>
|
||||
<td>{{ pm.is_active | yesno:"Oui, Non"}}</td>
|
||||
<td>{{ pm.is_usable_in_cotisation | yesno:"Oui, Non" }}</td>
|
||||
<td>{{ pm.is_usable_in_reload | 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>
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
|
||||
from coopeV3.acl import active_required
|
||||
|
||||
from .models import GeneralPreferences, Cotisation, PaymentMethod
|
||||
|
||||
from .forms import CotisationForm, PaymentMethodForm, GeneralPreferencesForm
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.add_generalpreferences')
|
||||
def generalPreferences(request):
|
||||
gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
|
||||
form = GeneralPreferencesForm(request.POST or None, instance=gp)
|
||||
|
@ -15,10 +21,16 @@ def generalPreferences(request):
|
|||
|
||||
########## Cotisations ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.view_cotisation')
|
||||
def cotisationsIndex(request):
|
||||
cotisations = Cotisation.objects.all()
|
||||
return render(request, "preferences/cotisations_index.html", {"cotisations": cotisations})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.add_cotisation')
|
||||
def addCotisation(request):
|
||||
form = CotisationForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -27,6 +39,9 @@ def addCotisation(request):
|
|||
return redirect(reverse('preferences:cotisationsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Création d'une cotisation", "form_button": "Créer"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.change_cotisation')
|
||||
def editCotisation(request, pk):
|
||||
cotisation = get_object_or_404(Cotisation, pk=pk)
|
||||
form = CotisationForm(request.POST or None, instance=cotisation)
|
||||
|
@ -36,6 +51,9 @@ def editCotisation(request, pk):
|
|||
return redirect(reverse('preferences:cotisationsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Modification d'une cotisation", "form_button": "Modifier"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.delete_cotisation')
|
||||
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"
|
||||
|
@ -46,10 +64,16 @@ def deleteCotisation(request,pk):
|
|||
|
||||
########## Payment Methods ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.view_paymentmethod')
|
||||
def paymentMethodsIndex(request):
|
||||
paymentMethods = PaymentMethod.objects.all()
|
||||
return render(request, "preferences/payment_methods_index.html", {"paymentMethods": paymentMethods})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.add_paymentmethod')
|
||||
def addPaymentMethod(request):
|
||||
form = PaymentMethodForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -58,6 +82,9 @@ def addPaymentMethod(request):
|
|||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.change_paymentmethod')
|
||||
def editPaymentMethod(request, pk):
|
||||
paymentMethod = get_object_or_404(PaymentMethod, pk=pk)
|
||||
form = PaymentMethodForm(request.POST or None, instance=paymentMethod)
|
||||
|
@ -67,9 +94,12 @@ def editPaymentMethod(request, pk):
|
|||
return redirect(reverse('preferences:paymentMethodsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Modification d'un moyen de paiement", "form_button": "Modifier"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('preferences.delete_paymentmethod')
|
||||
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'))
|
||||
return redirect(reverse('preferences:paymentMethodsIndex'))
|
|
@ -1,3 +1,5 @@
|
|||
Django==2.1
|
||||
django-autocomplete-light==3.3.2
|
||||
pytz==2018.5
|
||||
simplejson==3.16.0
|
||||
docutils==0.14
|
|
@ -1,4 +1,4 @@
|
|||
totalAmount = 0
|
||||
total = 0
|
||||
products = []
|
||||
paymentMethod = null
|
||||
balance = 0
|
||||
|
@ -64,4 +64,16 @@ $(document).ready(function(){
|
|||
window.location.reload()
|
||||
});
|
||||
});
|
||||
$(".pay_button").click(function(){
|
||||
alert('Tentative de paiment avec le moyen ' + $(this).attr('data-payment'));
|
||||
console.log(products)
|
||||
$.post("order", {"user":id, "paymentMethod": $(this).attr('data-payment'), "order_length": products.length, "order": JSON.stringify(products), "amount": total}, function(data){
|
||||
alert(data);
|
||||
location.reload();
|
||||
}).fail(function(data){
|
||||
alert("Impossible d'effectuer la transaction");
|
||||
location.reload();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
{% load vip %}
|
||||
<section>
|
||||
<h2>A propos</h2>
|
||||
<p>{% lorem %}</p>
|
||||
<ul class="actions">
|
||||
<li>
|
||||
<a class="button" href="">En savoir plus</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>L'association Coopé Technopole Metz est une association de droit local dont le siège social est établi à la résidence Edouard Branly. Son but est d'entretenir un lieu convivial sous la forme d'un bar associatif. Les membres actifs sont les coopemen (ou coopewomen).</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Contacts</h2>
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
<a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="">Comptabilité</a>
|
||||
<a href="{% url 'gestion:annualRanking' %}">Comptabilité</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="">Classement</a>
|
||||
<a href="{% url 'gestion:ranking' %}">Classement</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="">Classement sur l'année</a>
|
||||
<a href="{% url 'gestion:annualRanking' %}">Classement sur l'année</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="{% url 'preferences:generalPreferences' %}">Admin</a>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.models import Permission
|
||||
|
||||
from .models import School, Profile, CotisationHistory
|
||||
|
||||
admin.site.register(Permission)
|
||||
admin.site.register(School)
|
||||
admin.site.register(Profile)
|
||||
admin.site.register(CotisationHistory)
|
||||
# Register your models here.
|
||||
admin.site.register(CotisationHistory)
|
|
@ -25,14 +25,13 @@ class EditGroupForm(forms.ModelForm):
|
|||
fields = "__all__"
|
||||
|
||||
class SelectUserForm(forms.Form):
|
||||
user = forms.ModelChoiceField(queryset=User.objects.all(), label="Utilisateur")
|
||||
user = forms.ModelChoiceField(queryset=User.objects.all(), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:all-users-autocomplete', attrs={'data-minimum-input-length':2}))
|
||||
|
||||
class SelectNonSuperUserForm(forms.Form):
|
||||
user = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:non-super-users-autocomplete', attrs={'data-minimum-input-length':2}))
|
||||
|
||||
class SelectNonAdminUserForm(forms.Form):
|
||||
user = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:active-users-autocomplete', attrs={'data-minimum-input-length':2}))
|
||||
|
||||
user = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:non-admin-users-autocomplete', attrs={'data-minimum-input-length':2}))
|
||||
|
||||
class GroupsEditForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.db.models.signals import post_save
|
|||
from django.dispatch import receiver
|
||||
|
||||
from preferences.models import PaymentMethod, Cotisation
|
||||
from gestion.models import ConsumptionHistory
|
||||
|
||||
class School(models.Model):
|
||||
name = models.CharField(max_length=255, verbose_name="Nom")
|
||||
|
@ -12,6 +13,11 @@ class School(models.Model):
|
|||
return self.name
|
||||
|
||||
class CotisationHistory(models.Model):
|
||||
class Meta:
|
||||
permissions = (
|
||||
("validate_consumptionhistory", "Peut (in)valider les cotisations"),
|
||||
)
|
||||
|
||||
WAITING = 0
|
||||
VALID = 1
|
||||
INVALID = 2
|
||||
|
@ -57,12 +63,12 @@ class Profile(models.Model):
|
|||
|
||||
@property
|
||||
def alcohol(self):
|
||||
#consos = Consommation.objects.filter(client=self).select_related('produit')
|
||||
#alcool = 0
|
||||
#for conso in consos:
|
||||
#produit = conso.produit
|
||||
#alcool += conso.nombre * float(produit.deg) * produit.volume * 0.79 /10 /1000
|
||||
return 0
|
||||
consumptions = ConsumptionHistory.objects.filter(customer=self.user).select_related('product')
|
||||
alcohol = 0
|
||||
for consumption in consumptions:
|
||||
product = consumption.product
|
||||
alcohol += consumption.quantity * float(product.deg) * product.volume * 0.79 /10 /1000
|
||||
return alcohol
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user)
|
||||
|
@ -74,4 +80,9 @@ def create_user_profile(sender, instance, created, **kwargs):
|
|||
|
||||
@receiver(post_save, sender=User)
|
||||
def save_user_profile(sender, instance, **kwargs):
|
||||
instance.profile.save()
|
||||
instance.profile.save()
|
||||
|
||||
def str_user(self):
|
||||
return self.username + " (" + self.first_name + " " + self.last_name + ", " + str(self.profile.balance) + "€)"
|
||||
|
||||
User.add_to_class("__str__", str_user)
|
|
@ -10,6 +10,7 @@
|
|||
<header class="major">
|
||||
<h2>Liste des groupes de droit</h2>
|
||||
</header>
|
||||
<a href="{% url 'users:createGroup' %}" class="button">Ajouter un groupe de droit</a><br><br>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
|
|
|
@ -130,13 +130,13 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody id="bodyRechargement">
|
||||
{%for reload in lastReloads%}
|
||||
{% for reload in reloads %}
|
||||
<tr>
|
||||
<th>{{reload.amount}}</th>
|
||||
<th>{{reload.paymentMethod}}</th>
|
||||
<th>{{reload.amount}}€</th>
|
||||
<th>{{reload.PaymentMethod}}</th>
|
||||
<th>{{reload.date}}</th>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -208,11 +208,4 @@
|
|||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
{%endblock%}
|
||||
{%block addScript %}
|
||||
<script src="{%static 'js/canvasjs.min.js'%}"></script>
|
||||
<script src="{%static 'js/profil.js'%}"></script>
|
||||
{%endblock%}
|
||||
{%endblock%}
|
|
@ -30,6 +30,7 @@ urlpatterns = [
|
|||
path('all-users-autocomplete', views.AllUsersAutocomplete.as_view(), name="all-users-autocomplete"),
|
||||
path('active-users-autcocomplete', views.ActiveUsersAutocomplete.as_view(), name="active-users-autocomplete"),
|
||||
path('non-super-users-autocomplete', views.NonSuperUserAutocomplete.as_view(), name="non-super-users-autocomplete"),
|
||||
path('non-admin-users-autocomplete', views.NonAdminUserAutocomplete.as_view(), name="non-admin-users-autocomplete"),
|
||||
path('getUser/<int:pk>', views.getUser, name="getUser"),
|
||||
path('addCotisationHistory/<int:pk>', views.addCotisationHistory, name="addCotisationHistory"),
|
||||
path('validateCotisationHistory/<int:pk>', views.validateCotisationHistory, name="validateCotisationHistory"),
|
||||
|
@ -39,4 +40,5 @@ urlpatterns = [
|
|||
path('createSchool', views.createSchool, name="createSchool"),
|
||||
path('editSchool/<int:pk>', views.editSchool, name="editSchool"),
|
||||
path('deleteSchool/<int:pk>', views.deleteSchool, name="deleteSchool"),
|
||||
path('allReloads/<int:pk>/<int:page>', views.allReloads, name="allReloads"),
|
||||
]
|
||||
|
|
425
users/views.py
425
users/views.py
|
@ -5,16 +5,38 @@ from django.contrib.auth import authenticate, login, logout
|
|||
from django.contrib import messages
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
|
||||
import json
|
||||
import simplejson as json
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from dal import autocomplete
|
||||
|
||||
from coopeV3.acl import admin_required, superuser_required, self_or_has_perm, active_required
|
||||
from .models import CotisationHistory, WhiteListHistory, School
|
||||
from .forms import CreateUserForm, LoginForm, CreateGroupForm, EditGroupForm, SelectUserForm, GroupsEditForm, EditPasswordForm, addCotisationHistoryForm, addCotisationHistoryForm, addWhiteListHistoryForm, SelectNonAdminUserForm, SelectNonSuperUserForm, SchoolForm
|
||||
from gestion.models import Reload
|
||||
|
||||
@active_required
|
||||
def loginView(request):
|
||||
"""
|
||||
Display the login form for :model:`User`.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
Title of the form.
|
||||
|
||||
``form``
|
||||
The login form.
|
||||
|
||||
``form_button``
|
||||
Content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
form = LoginForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'])
|
||||
|
@ -29,26 +51,91 @@ def loginView(request):
|
|||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
def logoutView(request):
|
||||
"""
|
||||
Logout the logged user
|
||||
"""
|
||||
logout(request)
|
||||
messages.success(request, "Vous êtes à présent déconnecté")
|
||||
return redirect(reverse('home'))
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_user')
|
||||
def index(request):
|
||||
return render(request, "users/index.html")
|
||||
"""
|
||||
Display the index for user related actions
|
||||
|
||||
########## schools ##########
|
||||
**Template**
|
||||
|
||||
:template:`users/index.html`
|
||||
"""
|
||||
return render(request, "users/index.html")
|
||||
|
||||
########## users ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@self_or_has_perm('pk', 'auth.view_user')
|
||||
def profile(request, pk):
|
||||
"""
|
||||
Display the profile for the requested user
|
||||
|
||||
``pk``
|
||||
The primary key for user
|
||||
|
||||
**Context**
|
||||
|
||||
``user``
|
||||
The instance of User
|
||||
|
||||
``self``
|
||||
Boolean value wich indicates if the current logged user and the request user are the same
|
||||
|
||||
``cotisations``
|
||||
List of the user's cotisations
|
||||
|
||||
``whitelists``
|
||||
List of the user's whitelists
|
||||
|
||||
``reloads``
|
||||
List of the last 5 reloads of the user
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`users/profile.html`
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
self = request.user == user
|
||||
cotisations = CotisationHistory.objects.filter(user=user)
|
||||
whitelists = WhiteListHistory.objects.filter(user=user)
|
||||
return render(request, "users/profile.html", {"user":user, "self":self, "cotisations":cotisations, "whitelists": whitelists})
|
||||
reloads = Reload.objects.filter(customer=user).order_by('-date')
|
||||
return render(request, "users/profile.html", {"user":user, "self":self, "cotisations":cotisations, "whitelists": whitelists, "reloads": reloads})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.add_user')
|
||||
def createUser(request):
|
||||
"""
|
||||
Display a CreateUserForm instance.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The CreateUserForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
form = CreateUserForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
user = form.save(commit=False)
|
||||
|
@ -58,17 +145,77 @@ def createUser(request):
|
|||
user.save()
|
||||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_user')
|
||||
def searchUser(request):
|
||||
"""
|
||||
Display a simple searchForm for User.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The searchForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
form = SelectUserForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_user')
|
||||
def usersIndex(request):
|
||||
"""
|
||||
Display the list of all users.
|
||||
|
||||
**Context**
|
||||
|
||||
``users``
|
||||
The list of all users
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`users/users_index.html`
|
||||
"""
|
||||
users = User.objects.all()
|
||||
return render(request, "users/users_index.html", {"users":users})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_user')
|
||||
def editGroups(request, pk):
|
||||
"""
|
||||
Edit the groups of a user.
|
||||
|
||||
``pk``
|
||||
The pk of the user.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The GroupsEditForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
form = GroupsEditForm(request.POST or None, instance=user)
|
||||
if(form.is_valid()):
|
||||
|
@ -78,7 +225,30 @@ def editGroups(request, pk):
|
|||
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})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_user')
|
||||
def editPassword(request, pk):
|
||||
"""
|
||||
Change the password of a user.
|
||||
|
||||
``pk``
|
||||
The pk of the user.
|
||||
|
||||
**Context**
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The EditPasswordForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
if user != request.user:
|
||||
messages.error(request, "Vous ne pouvez modifier le mot de passe d'un autre utilisateur")
|
||||
|
@ -95,7 +265,31 @@ def editPassword(request, pk):
|
|||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_user')
|
||||
def editUser(request, pk):
|
||||
"""
|
||||
Edit a user and user profile
|
||||
|
||||
``pk``
|
||||
The pk of the user.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The CreateUserForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
form = CreateUserForm(request.POST or None, instance=user, initial = {'school': user.profile.school})
|
||||
if(form.is_valid()):
|
||||
|
@ -105,7 +299,17 @@ def editUser(request, 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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_user')
|
||||
def resetPassword(request, pk):
|
||||
"""
|
||||
Reset the password of a user.
|
||||
|
||||
``pk``
|
||||
The pk of the user
|
||||
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
if user.is_superuser:
|
||||
messages.error(request, "Impossible de réinitialiser le mot de passe de " + user.username + " : il est superuser.")
|
||||
|
@ -116,22 +320,114 @@ def resetPassword(request, pk):
|
|||
messages.success(request, "Le mot de passe de " + user.username + " a bien été réinitialisé.")
|
||||
return redirect(reverse('users:profile', kwargs={'pk': pk}))
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_user')
|
||||
def getUser(request, pk):
|
||||
"""
|
||||
Return username and balance of the requested user (pk)
|
||||
|
||||
``pk``
|
||||
The pk of the user
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
data = json.dumps({"username": user.username, "balance": float(user.profile.balance)})
|
||||
data = json.dumps({"username": user.username, "balance": user.profile.balance})
|
||||
return HttpResponse(data, content_type='application/json')
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@self_or_has_perm('pk', 'auth.view_user')
|
||||
def allReloads(request, pk, page):
|
||||
"""
|
||||
Display all the reloads of the requested user.
|
||||
|
||||
``pk``
|
||||
The pk of the user.
|
||||
``page``
|
||||
The page number.
|
||||
|
||||
**Context**
|
||||
|
||||
``reloads``
|
||||
The reloads of the page.
|
||||
``user``
|
||||
The requested user
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`users/allReloads.html`
|
||||
"""
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
allReloads = Reload.objects.filter(customer=user).order_by('-date')
|
||||
paginator = Paginator(allReloads, 2)
|
||||
reloads = paginator.get_page(page)
|
||||
return render(request, "users/allReloads.html", {"reloads": reloads, "user":user})
|
||||
|
||||
########## Groups ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_group')
|
||||
def groupsIndex(request):
|
||||
"""
|
||||
Display all the groups.
|
||||
|
||||
**Context**
|
||||
|
||||
``groups``
|
||||
List of all groups.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`users/groups_index.html`
|
||||
"""
|
||||
groups = Group.objects.all()
|
||||
return render(request, "users/groups_index.html", {"groups": groups})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.view_group')
|
||||
def groupProfile(request, pk):
|
||||
"""
|
||||
Display the profile of a group.
|
||||
|
||||
``pk``
|
||||
The pk of the group.
|
||||
|
||||
**Context**
|
||||
|
||||
``group``
|
||||
The requested group.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`users/group_profile.html`
|
||||
"""
|
||||
group = get_object_or_404(Group, pk=pk)
|
||||
return render(request, "users/group_profile.html", {"group": group})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.add_group')
|
||||
def createGroup(request):
|
||||
"""
|
||||
Create a group with a CreateGroupForm instance.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The CreateGroupForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
form = CreateGroupForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
group = form.save()
|
||||
|
@ -139,7 +435,31 @@ def createGroup(request):
|
|||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_group')
|
||||
def editGroup(request, pk):
|
||||
"""
|
||||
Edit a group with a EditGroupForm instance.
|
||||
|
||||
``pk``
|
||||
The pk of the group.
|
||||
|
||||
**Context**
|
||||
|
||||
``form_entete``
|
||||
The form title.
|
||||
|
||||
``form``
|
||||
The EditGroupForm instance.
|
||||
|
||||
``form_button``
|
||||
The content of the form button.
|
||||
|
||||
**Template**
|
||||
|
||||
:template:`form.html`
|
||||
"""
|
||||
group = get_object_or_404(Group, pk=pk)
|
||||
form = EditGroupForm(request.POST or None, instance=group)
|
||||
extra_css = "#id_permissions{height:200px;}"
|
||||
|
@ -149,7 +469,17 @@ def editGroup(request, 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})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.delete_group')
|
||||
def deleteGroup(request, pk):
|
||||
"""
|
||||
Delete the requested group.
|
||||
|
||||
``pk``
|
||||
The pk of the group
|
||||
|
||||
"""
|
||||
group = get_object_or_404(Group, pk=pk)
|
||||
if group.user_set.count() == 0:
|
||||
name = group.name
|
||||
|
@ -160,7 +490,20 @@ def deleteGroup(request, pk):
|
|||
messages.error(request, "Impossible de supprimer le groupe " + group.name + " : il y a encore des utilisateurs")
|
||||
return redirect(reverse('users:groupProfile', kwargs={'pk': group.pk}))
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_group')
|
||||
def removeRight(request, groupPk, permissionPk):
|
||||
"""
|
||||
Remove a right from a given group.
|
||||
|
||||
``groupPk``
|
||||
The pk of the group.
|
||||
|
||||
``permissionPk``
|
||||
The pk of the right.
|
||||
|
||||
"""
|
||||
group = get_object_or_404(Group, pk=groupPk)
|
||||
perm = get_object_or_404(Permission, pk=permissionPk)
|
||||
if perm in group.permissions.all():
|
||||
|
@ -170,7 +513,20 @@ def removeRight(request, groupPk, permissionPk):
|
|||
messages.error(request, "Impossible de retirer la permission " + perm.codename + " du groupe " + group.name)
|
||||
return redirect(reverse('users:groupProfile', kwargs={'pk': groupPk}) + "#second")
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('auth.change_user')
|
||||
def removeUser(request, groupPk, userPk):
|
||||
"""
|
||||
Remove a user from a given group.
|
||||
|
||||
``groupPk``
|
||||
The pk of the group.
|
||||
|
||||
``userPk``
|
||||
The pk of the user.
|
||||
|
||||
"""
|
||||
group = get_object_or_404(Group, pk=groupPk)
|
||||
user = get_object_or_404(User, pk=userPk)
|
||||
if(group in user.groups.all()):
|
||||
|
@ -182,10 +538,16 @@ def removeUser(request, groupPk, userPk):
|
|||
|
||||
########## admins ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@admin_required
|
||||
def adminsIndex(request):
|
||||
admins = User.objects.filter(is_staff=True)
|
||||
return render(request, "users/admins_index.html", {"admins": admins})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@admin_required
|
||||
def addAdmin(request):
|
||||
form = SelectNonAdminUserForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -196,6 +558,9 @@ def addAdmin(request):
|
|||
return redirect(reverse('users:adminsIndex'))
|
||||
return render(request, "form.html", {"form_entete": "Gestion des admins", "form": form, "form_title": "Ajout d'un admin", "form_button":"Ajouter l'utilisateur aux admins"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@admin_required
|
||||
def removeAdmin(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
if user.is_staff:
|
||||
|
@ -214,10 +579,16 @@ def removeAdmin(request, pk):
|
|||
|
||||
########## superusers ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@superuser_required
|
||||
def superusersIndex(request):
|
||||
superusers = User.objects.filter(is_superuser=True)
|
||||
return render(request, "users/superusers_index.html", {"superusers": superusers})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@superuser_required
|
||||
def addSuperuser(request):
|
||||
form = SelectNonSuperUserForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -229,6 +600,9 @@ def addSuperuser(request):
|
|||
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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@superuser_required
|
||||
def removeSuperuser(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
if user.is_superuser:
|
||||
|
@ -244,11 +618,20 @@ def removeSuperuser(request, pk):
|
|||
|
||||
########## Cotisations ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.add_cotisationhistory')
|
||||
def addCotisationHistory(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
form = addCotisationHistoryForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
cotisation = form.save(commit=False)
|
||||
if(cotisation.paymentMethod.affect_balance):
|
||||
if(user.profile.balance >= cotisation.amount):
|
||||
user.profile.balance -= cotisation.amount
|
||||
else:
|
||||
cotisation.delete()
|
||||
messages.error(request, "Solde insuffisant")
|
||||
cotisation.user = user
|
||||
cotisation.coopeman = request.user
|
||||
cotisation.amount = cotisation.cotisation.amount
|
||||
|
@ -264,6 +647,9 @@ def addCotisationHistory(request, 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"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.validate_consumptionhistory')
|
||||
def validateCotisationHistory(request, pk):
|
||||
cotisationHistory = get_object_or_404(CotisationHistory, pk=pk)
|
||||
cotisationHistory.valid = CotisationHistory.VALID
|
||||
|
@ -271,18 +657,26 @@ def validateCotisationHistory(request, pk):
|
|||
messages.success(request, "La cotisation a bien été validée")
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.validate_consumptionhistory')
|
||||
def invalidateCotisationHistory(request, pk):
|
||||
cotisationHistory = get_object_or_404(CotisationHistory, pk=pk)
|
||||
cotisationHistory.valid = CotisationHistory.INVALID
|
||||
cotisationHistory.save()
|
||||
user = cotisationHistory.user
|
||||
user.profile.cotisationEnd = user.profile.cotisationEnd - timedelta(days=cotisationHistory.duration)
|
||||
if(cotisationHistory.paymentMethod.affect_balance):
|
||||
user.profile.balance += cotisation.amount
|
||||
user.save()
|
||||
messages.success(request, "La cotisation a bien été invalidée")
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
########## Whitelist ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.add_whitelisthistory')
|
||||
def addWhiteListHistory(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
form = addWhiteListHistoryForm(request.POST or None)
|
||||
|
@ -303,10 +697,16 @@ def addWhiteListHistory(request, pk):
|
|||
|
||||
########## Schools ##########
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.view_school')
|
||||
def schoolsIndex(request):
|
||||
schools = School.objects.all()
|
||||
return render(request, "users/schools_index.html", {"schools": schools})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.add_school')
|
||||
def createSchool(request):
|
||||
form = SchoolForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
|
@ -315,6 +715,9 @@ def createSchool(request):
|
|||
return redirect(reverse('users:schoolsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Création d'une école", "form_button": "Créer"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.change_school')
|
||||
def editSchool(request, pk):
|
||||
school = get_object_or_404(School, pk=pk)
|
||||
form = SchoolForm(request.POST or None, instance=school)
|
||||
|
@ -324,6 +727,9 @@ def editSchool(request, pk):
|
|||
return redirect(reverse('users:schoolsIndex'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Modification de l'école " + str(school), "form_button": "Modifier"})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
@permission_required('users.delete_school')
|
||||
def deleteSchool(request, pk):
|
||||
school = get_object_or_404(School, pk=pk)
|
||||
message = "L'école " + str(school) + " a bien été supprimée"
|
||||
|
@ -355,6 +761,13 @@ class AdherentAutocomplete(autocomplete.Select2QuerySetView):
|
|||
class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = User.objects.filter(is_superuser=False)
|
||||
if self.q:
|
||||
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q))
|
||||
return qs
|
||||
|
||||
class NonAdminUserAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = User.objects.filter(is_staff=False)
|
||||
if self.q:
|
||||
qs = qs.filter(Q(username__istartswith=self.q) | Q(first_name__istartswith=self.q) | Q(last_name__istartswith=self.q))
|
||||
return qs
|
Loading…
Reference in a new issue