3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-12-23 15:33:45 +00:00
This commit is contained in:
Yoann Pétri 2018-11-22 22:52:15 +01:00
parent 15e13f978c
commit 23eb8776a8
26 changed files with 748 additions and 112 deletions

1
.gitignore vendored
View file

@ -39,3 +39,4 @@ tags
# End of https://www.gitignore.io/api/vim,git,django
.vscode

View file

@ -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'

View file

@ -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')),
]

View file

@ -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)

View file

@ -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}))

View file

@ -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")

View file

@ -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%}

View file

@ -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">

View file

@ -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 %}

View file

@ -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"),
]

View file

@ -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")

View file

@ -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:

View file

@ -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):

View file

@ -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>

View file

@ -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'))

View file

@ -1,3 +1,5 @@
Django==2.1
django-autocomplete-light==3.3.2
pytz==2018.5
simplejson==3.16.0
docutils==0.14

View file

@ -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();
});
});
});

View file

@ -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>

View file

@ -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>

View file

@ -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)

View file

@ -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:

View file

@ -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)

View file

@ -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>

View file

@ -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%}

View file

@ -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"),
]

View file

@ -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