3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-12-25 00:13:46 +00:00

Merge branch 'release-3.2.0' into 'master'

Release 3.2.0

Closes #26, #28, #24, #1, and #18

See merge request coope/coopeV3!3
This commit is contained in:
Nanoy 2019-01-06 06:20:31 +01:00
commit 350027042e
27 changed files with 388 additions and 87 deletions

View file

@ -1,3 +1,10 @@
## v3.2.0
* Ajout d'icônes (avec font awesome)
* Amélioration du diagramme sur le profil (couleurs, valeur pour les fromages et charcuts, seuil des 1%)
* Boutons flottants sur la page de transation (avec options pour activer ou désactiver)
* Ajout du module comptabilité (génération de relevé entre deux dates)
* Exportation en csv par groupe
* Liens pour ajouter/retirer des admins/superusers enlevés sur le profil
## v3.1.0
* Tronque la quantité d'alcool ingéré sur le profil (fix #8)
* La modification des produits retourne sur la pge de profil du produit (fix #9)
@ -18,4 +25,4 @@
## v3.0.1
* Fix page inactive
* Fix prix dans les historiques de consommations
* Fix prix dans les historiques de consommations

View file

@ -38,6 +38,7 @@ INSTALLED_APPS = [
'dal',
'dal_select2',
'simple_history',
'django_tex',
]
MIDDLEWARE = [
@ -68,6 +69,14 @@ TEMPLATES = [
],
},
},
{
'NAME': 'tex',
'BACKEND': 'django_tex.engine.TeXEngine',
'APP_DIRS': True,
'OPTIONS': {
'environment': 'gestion.environment.my_environment',
}
},
]
WSGI_APPLICATION = 'coopeV3.wsgi.application'

12
gestion/environment.py Normal file
View file

@ -0,0 +1,12 @@
from django_tex.environment import environment
def latex_safe(value):
return str(value).replace('_', '\_').replace('$', '\$').replace('&', '\&').replace('#', '\#').replace('{', '\{').replace('}','\}')
def my_environment(**options):
env = environment(**options)
env.filters.update({
'latex_safe': latex_safe
})
return env

View file

@ -66,4 +66,8 @@ class SelectActiveKegForm(forms.Form):
class PinteForm(forms.Form):
ids = forms.CharField(widget=forms.Textarea, label="Numéros", help_text="Numéros séparés par un espace. Laissez vide pour utiliser le range.", required=False)
begin = forms.IntegerField(label="Début", help_text="Début du range", required=False)
end = forms.IntegerField(label="Fin", help_text="Fin du range", required=False)
end = forms.IntegerField(label="Fin", help_text="Fin du range", required=False)
class GenerateReleveForm(forms.Form):
begin = forms.DateTimeField(label="Date de début")
end = forms.DateTimeField(label="Date de fin")

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-01-05 23:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0004_auto_20181223_1830'),
]
operations = [
migrations.AddField(
model_name='historicalproduct',
name='showingMultiplier',
field=models.PositiveIntegerField(default=1),
),
migrations.AddField(
model_name='product',
name='showingMultiplier',
field=models.PositiveIntegerField(default=1),
),
]

View file

@ -39,6 +39,7 @@ class Product(models.Model):
volume = models.PositiveIntegerField(default=0)
deg = models.DecimalField(default=0,max_digits=5, decimal_places=2, verbose_name="Degré", validators=[MinValueValidator(0)])
adherentRequired = models.BooleanField(default=True, verbose_name="Adhérent requis")
showingMultiplier = models.PositiveIntegerField(default=1)
history = HistoricalRecords()
def __str__(self):

View file

@ -13,10 +13,31 @@
{% block content %}
{% if floating_buttons %}
<div class="alt_payment_buttons">
{% for pm in pay_buttons %}
<button class="button small pay_button" data-payment="{{pm.pk}}"><i class="fa fa-{{pm.icon}}"></i></button><br>
{% endfor %}
</div>
{% endif %}
<a class="up_button" href="#intro">
UP
</a>
<style>
.alt_payment_buttons{
display:block;
background-color:white;
position:fixed;
right:0;
padding-right: 1em;
top:50%;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.alt_payment_buttons button{
min-width: 0 !important;
background-color: white !important;
}
.up_button{
display:block;
background-color:white;
@ -28,7 +49,7 @@
text-align:center;
line-height:50px;
right:1em;
bottom : 1em;
bottom : 1em;
}
</style>
{% if perms.gestion.add_consumptionhistory %}
@ -63,7 +84,7 @@
<td id="balance">0€</td>
<td id="totalAmount">0€</td>
<td id="totalAfter">0€</td>
<td>{% for pm in pay_buttons %}<button class="btn small pay_button" data-payment="{{pm.pk}}">{{pm.name}}</button> {% endfor %}</td>
<td>{% for pm in pay_buttons %}<button class="btn small pay_button" data-payment="{{pm.pk}}"><i class="fa fa-{{pm.icon}}"></i> {{pm.name}}</button> {% endfor %}</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,71 @@
\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[french]{babel}
\usepackage[T1]{fontenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{eurosym}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
\usepackage{tabularx}
\usepackage{longtable}
\usepackage{tabu}
\author{Généré par CoopeV3}
\title{Relevé Coopé Technopôle Metz}
\begin{document}
\maketitle
\section{Informations générales}
\begin{longtabu}{|X|X|X|}
\hline
\multicolumn{2}{|c|}{Généré le } & \textbf{ {{- now | date('d/m/Y H:i:s') -}} }\\
\hline
Infos & De & \textbf{ {{- begin | date('d/m/Y H:i:s')-}} } \\
\cline{2-3} & À & \textbf{ {{- end | date('d/m/Y H:i:s') -}} }\\
\hline
Estimations & Espèces & \textbf{ {{- value_especes | latex_safe -}} \euro{}} \\
\cline{2-3} & Lydia & \textbf{ {{- value_lydia | latex_safe -}} \euro{}} \\
\cline{2-3} & Chèques & \textbf{ {{- value_cheque | latex_safe -}} \euro{}} \\
\hline
\end{longtabu}
\section{Transactions}
\begin{longtabu}{|c|X|X|X|X|X|}
\hline
\# & Date & Client & Montant & Moyen de paiement & Produit (Qté) \\
\hline
{% for consumption in consumptions %}
{{consumption.pk}} & {{consumption.date | date('d/m/Y H:i:s')}} & {{consumption.customer.first_name|latex_safe}} {{consumption.customer.last_name|latex_safe}} & {{consumption.amount}} \euro{} & {{consumption.paymentMethod}} & {{consumption.product}} (x{{consumption.quantity}})\\
\hline
{% endfor %}
\end{longtabu}
\section{Rechargements}
\begin{longtabu}{|c|X|X|X|X|}
\hline
\# & Date & Client & Montant & Moyen de paiement \\
\hline
{% for reload in reloads %}
{{reload.pk}} & {{ reload.date | date('d/m/Y H:i:s')}} & {{reload.customer.first_name | latex_safe}} {{reload.customer.last_name | latex_safe}} & {{ reload.amount }} \euro{} & {{reload.PaymentMethod}} \\
\hline
{% endfor %}
\end{longtabu}
\section{Remboursement}
\begin{longtabu}{|c|X|X|X|}
\hline
\# & Date & Client & Montant\\
\hline
{% for refund in refunds %}
{{refund.pk}} & {{ refund.date | date('d/m/Y H:i:s')}} & {{refund.customer.first_name|latex_safe}} {{refund.customer.last_name|latex_safe}} & {{ refund.amount }} \euro{}\\
\hline
{% endfor %}
\end{longtabu}
\section{Cotisations}
\begin{longtabu}{|c|X|X|X|X|X|}
\hline
\# & Date & Client & Montant & Durée & Moyen de paiement \\
\hline
{% for cot in cotisations %}
{{cot.pk}} & {{ cot.paymentDate | date('d/m/Y H:i:s')}} & {{cot.user.first_name|latex_safe}} {{cot.user.last_name|latex_safe}} & {{cot.amount}} \euro{} & {{cot.duration}} jours & {{cot.paymentMethod}} \\
\hline
{% endfor %}
\end{longtabu}
\end{document}

View file

@ -44,4 +44,5 @@ urlpatterns = [
path('kegs-active-autocomplete', views.KegActiveAutocomplete.as_view(), name="kegs-active-autocomplete"),
path('menus-autcomplete', views.MenusAutocomplete.as_view(), name="menus-autocomplete"),
path('cancelReload/<int:pk>', views.cancel_reload, name="cancelReload"),
path('gen_releve', views.gen_releve, name="gen_releve"),
]

View file

@ -8,15 +8,19 @@ from django.contrib.auth.decorators import login_required, permission_required
from django.utils import timezone
from django.http import HttpResponseRedirect
from coopeV3.acl import active_required, acl_or
from django_tex.views import render_to_pdf
from coopeV3.acl import active_required, acl_or, admin_required
import simplejson as json
from dal import autocomplete
from decimal import *
import datetime
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm
from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm
from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund
from preferences.models import PaymentMethod, GeneralPreferences
from users.models import CotisationHistory
@active_required
@login_required
@ -26,10 +30,10 @@ def manage(request):
Display the manage page
**Context**
``gestion_form``
The manage form
``reload_form``
The :model:`gestion.Reload` form
@ -44,13 +48,13 @@ def manage(request):
``panini``
A list of active :model:`gestion.Product` corresponding to panini items
``food``
A list of active :model:`gestion.Product` corresponding to non-panini items
``soft``
A list of active :model:`gestion.Product` correspond to non alcoholic beverage
``menus``
The list of active :model:`gestion.Menu`
@ -72,6 +76,8 @@ def manage(request):
soft = Product.objects.filter(category=Product.SOFT).filter(is_active=True)
menus = Menu.objects.filter(is_active=True)
kegs = Keg.objects.filter(is_active=True)
gp, _ = GeneralPreferences.objects.get_or_create(pk=1)
floating_buttons = gp.floating_buttons
for keg in kegs:
if(keg.pinte):
bieresPression.append(keg.pinte)
@ -89,7 +95,8 @@ def manage(request):
"food": food,
"soft": soft,
"menus": menus,
"pay_buttons": pay_buttons
"pay_buttons": pay_buttons,
"floating_buttons": floating_buttons,
})
@csrf_exempt
@ -288,7 +295,7 @@ def cancel_menu(request, pk):
for product in manu_history.menu.articles:
consumptionT = Consumption.objects.get(customer=user, product=product)
consumptionT -= menu_history.quantity
consumptionT.save()
consumptionT.save()
menu_history.delete()
messages.success(request, "La consommation du menu a bien été annulée")
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
@ -318,7 +325,7 @@ def addProduct(request):
``form``
The ProductForm instance
``form_title``
The title for the form template
@ -350,7 +357,7 @@ def editProduct(request, pk):
``form``
The ProductForm instance
``form_title``
The title for the form template
@ -399,7 +406,7 @@ def searchProduct(request):
``form``
The SearchProductForm instance
``form_title``
The title for the form template
@ -426,7 +433,7 @@ def productProfile(request, pk):
The primary key of the requested :model:`gestion.Product`
**Context**
``product``
The :model:`gestion.Product` instance
@ -500,10 +507,10 @@ def addKeg(request):
Display a form to add a :model:`gestion.Keg`
**Context**
``form``
The KegForm instance
``form_title``
The title for the :template:`form.html` template
@ -532,10 +539,10 @@ def editKeg(request, pk):
The primary key of the requested :model:`gestion.Keg`
**Context**
``form``
The KegForm instance
``form_title``
The title for the :template:`form.html` template
@ -562,10 +569,10 @@ def openKeg(request):
Display a form to open a :model:`gestion.Keg`
**Context**
``form``
The SelectPositiveKegForm instance
``form_title``
The title for the :template:`form.html` template
@ -628,10 +635,10 @@ def closeKeg(request):
Display a form to close a :model:`gestion.Keg`
**Context**
``form``
The SelectActiveKegForm instance
``form_title``
The title for the :template:`form.html` template
@ -716,7 +723,7 @@ def kegH(request, pk):
``keg``
The :model:`gestion.Keg` instance
``kegHistory``
List of :model:`gestion.KegHistory` attached to keg
@ -758,10 +765,10 @@ def addMenu(request):
Display a form to add a :model:`gestion.Menu`
**Context**
``form``
The MenuForm instance
``form_title``
The title for the :template:`form.html` template
@ -791,10 +798,10 @@ def edit_menu(request, pk):
The primary key of requested :model:`gestion.Menu`
**Context**
``form``
The MenuForm instance
``form_title``
The title for the :template:`form.html` template
@ -962,7 +969,7 @@ def release(request, pinte_pk):
else:
messages.error(request, "Impossible de libérer la pinte")
return redirect(reverse('gestion:pintesList'))
@active_required
@login_required
@permission_required('gestion.add_pinte')
@ -1017,4 +1024,52 @@ def pintes_list(request):
def pintes_user_list(request):
pks = [x.pk for x in User.objects.all() if x.profile.nb_pintes > 0]
users = User.objects.filter(pk__in=pks)
return render(request, "gestion/pintes_user_list.html", {"users": users})
return render(request, "gestion/pintes_user_list.html", {"users": users})
@active_required
@login_required
@admin_required
def gen_releve(request):
form = GenerateReleveForm(request.POST or None)
if form.is_valid():
begin, end = form.cleaned_data['begin'], form.cleaned_data['end']
consumptions = ConsumptionHistory.objects.filter(date__gte=begin).filter(date__lte=end).order_by('-date')
reloads = Reload.objects.filter(date__gt=begin).filter(date__lt=end).order_by('-date')
refunds = Refund.objects.filter(date__gt=begin).filter(date__lt=end).order_by('-date')
cotisations = CotisationHistory.objects.filter(paymentDate__gt=begin).filter(paymentDate__lt=end).order_by('-paymentDate')
especes = PaymentMethod.objects.get(name="Espèces")
lydia = PaymentMethod.objects.get(name="Lydia")
cheque = PaymentMethod.objects.get(name="Chèque")
value_especes = 0
value_lydia = 0
value_cheque = 0
for consumption in consumptions:
pm = consumption.paymentMethod
if pm == especes:
value_especes += consumption.amount
elif pm == lydia:
value_lydia += consumption.amount
elif pm == cheque:
value_cheque += consumption.amount
for reload in reloads:
pm = reload.PaymentMethod
if pm == especes:
value_especes += reload.amount
elif pm == lydia:
value_lydia += reload.amount
elif pm == cheque:
value_cheque += reload.amount
for refund in refunds:
value_especes -= refund.amount
for cot in cotisations:
pm = cot.paymentMethod
if pm == especes:
value_especes += cot.amount
elif pm == lydia:
value_lydia += cot.amount
elif pm == cheque:
value_cheque += cot.amount
now = datetime.datetime.now()
return render_to_pdf(request, 'gestion/releve.tex', {"consumptions": consumptions, "reloads": reloads, "refunds": refunds, "cotisations": cotisations, "begin": begin, "end": end, "now": now, "value_especes": value_especes, "value_lydia": value_lydia, "value_cheque": value_cheque}, filename="releve.pdf")
else:
return render(request, "form.html", {"form": form, "form_title": "Génération d'un relevé", "form_button": "Générer"})

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-01-06 03:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0003_auto_20181223_1440'),
]
operations = [
migrations.AddField(
model_name='historicalpaymentmethod',
name='icon',
field=models.CharField(blank=True, max_length=255, verbose_name='Icône'),
),
migrations.AddField(
model_name='paymentmethod',
name='icon',
field=models.CharField(blank=True, max_length=255, verbose_name='Icône'),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-01-06 04:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0004_auto_20190106_0452'),
]
operations = [
migrations.AddField(
model_name='generalpreferences',
name='floating_buttons',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='historicalgeneralpreferences',
name='floating_buttons',
field=models.BooleanField(default=False),
),
]

View file

@ -12,6 +12,7 @@ class PaymentMethod(models.Model):
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")
icon = models.CharField(max_length=255, verbose_name="Icône", blank=True)
history = HistoricalRecords()
def __str__(self):
@ -32,6 +33,7 @@ class GeneralPreferences(models.Model):
grocer = models.CharField(max_length=255, blank=True)
use_pinte_monitoring = models.BooleanField(default=False)
lost_pintes_allowed = models.PositiveIntegerField(default=0)
floating_buttons = models.BooleanField(default=False)
history = HistoricalRecords()
class Cotisation(models.Model):

View file

@ -6,6 +6,7 @@
<li><a href="#second">Site actif</a></li>
<li><a href="#third">Bureau</a></li>
<li><a href="#fourth">Suivi de pintes</a></li>
<li><a href="fifth">Autre</a></li>
</ul>
{% endblock %}
@ -23,6 +24,11 @@
{{form.global_message}}
</div>
</div>
<div class="row uniform">
<div class="12u">
<button type="submit">Enregistrer</button>
</div>
</div>
</div>
</div>
</section>
@ -43,6 +49,11 @@
{{form.active_message}}
</div>
</div>
<div class="row uniform">
<div class="12u">
<button type="submit">Enregistrer</button>
</div>
</div>
</div>
</div>
</section>
@ -76,6 +87,11 @@
{{form.brewer}}
</div>
</div>
<div class="row uniform">
<div class="12u">
<button type="submit">Enregistrer</button>
</div>
</div>
</div>
</div>
</section>
@ -105,5 +121,25 @@
</div>
</div>
</section>
<section id="fifth" class="main">
<div class="spotlight">
<div class="content">
<header class="major">
<h2>Autre</h2>
</header>
<div class="row uniform">
<div class="12u">
{{form.floating_buttons}}
<label for="{{form.floating_buttons.id_for_label}}">Utiliser les boutons de paiement flottants ?</label>
</div>
</div>
<div class="row uniform">
<div class="12u">
<button type="submit">Enregistrer</button>
</div>
</div>
</div>
</div>
</section>
</form>
{% endblock %}

View file

@ -22,6 +22,7 @@
<th>Cotisations ?</th>
<th>Rechargements ?</th>
<th>Affecte le solde</th>
<th>Icône</th>
<th>Administration</th>
</tr>
</thead>
@ -33,6 +34,7 @@
<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><i class="fa fa-{{ pm.icon }}"></i></td>
<td>{% if perms.preferences.change_paymentmethod %}<a class="button small" href="{% url 'preferences:editPaymentMethod' pm.pk %}">Modifier</a> {% endif %}{% if perms.preferences.delete_paymentmethod %}<a class="button small" href="{% url 'preferences:deletePaymentMethod' pm.pk %}">Supprimer</a>{% endif %}</td>
</tr>
{% endfor %}

View file

@ -33,6 +33,7 @@ def generalPreferences(request):
form = GeneralPreferencesForm(request.POST or None, instance=gp)
if(form.is_valid()):
form.save()
messages.success(request, "Les préférences générales ont bien été mises à jour")
return render(request, "preferences/general_preferences.html", {"form": form})
########## Cotisations ##########

View file

@ -3,4 +3,5 @@ django-autocomplete-light==3.3.2
pytz==2018.5
simplejson==3.16.0
docutils==0.14
django-simple-history==2.5.1
django-simple-history==2.5.1
jinja2==2.10

View file

@ -9,6 +9,7 @@
<link rel="icon" sizes="32x32" href="{% static 'favicon32.ico' %}" type="image/x-icon">
<link rel="icon" sizes="96x96" href="{% static 'favicon96.ico' %}" type="image/x-icon">
<link rel="stylesheet" href="{%static 'css/main.css' %}" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>

View file

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

View file

@ -1,43 +1,49 @@
{% if request.user.is_authenticated %}
<span class="tabulation2">
<a href="{% url 'users:profile' request.user.pk %}">Mon profil</a>
<i class="fa fa-user"></i> <a href="{% url 'users:profile' request.user.pk %}">Mon profil</a>
</span>
{% if perms.gestion.add_consumptionhistory or perms.gestion.add_refund or perms.gestion.add_reload %}
<span class="tabulation2">
<a href="{% url 'gestion:manage' %}">Transactions</a>
<i class="fa fa-cash-register"></i> <a href="{% url 'gestion:manage' %}">Transactions</a>
</span>
{% endif %}
{% if perms.auth.add_user or perms.auth.view_user or perms.auth.add_group or perms.auth.view_group or perms.users.add_school or perms.users.view_school %}
<span class="tabulation2">
<a href="{% url 'users:index' %}">Gestion des clients</a>
<i class="fa fa-users"></i> <a href="{% url 'users:index' %}">Gestion des clients</a>
</span>
{% endif %}
{% if perms.gestion.view_product or perms.gestion.add_product or perms.gestion.add_keg or perms.gestion.view_keg or perms.gestion.change_keg or perms.gestion.view_menu or perms.gestion.add_menu %}
<span class="tabulation2">
<a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a>
<i class="fa fa-dolly-flatbed"></i> <a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a>
</span>
{% endif %}
<span class="tabulation2">
<a href="{% url 'gestion:ranking' %}">Classement</a>
<i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a>
</span>
{% if perms.preferences.change_generalpreferences %}
<span class="tabulation2">
<a href="{% url 'preferences:generalPreferences' %}">Admin</a>
<br>
<i class="fa fa-tools"></i> <a href="{% url 'preferences:generalPreferences' %}">Admin</a>
</span>
{% endif %}
{% if request.user.is_staff %}
<span class="tabulation2">
<i class="fa fa-business-time"></i> <a href="{% url 'gestion:gen_releve' %}">Comptabilité</a>
</span>
{% endif %}
{% if perms.preferences.view_cotisation %}
<span class="tabulation2">
<a href="{% url 'preferences:cotisationsIndex' %}">Cotisations</a>
<i class="fa fa-calendar-check"></i> <a href="{% url 'preferences:cotisationsIndex' %}">Cotisations</a>
</span>
{% endif %}
{% if perms.preferences.view_cotisation %}
<span class="tabulation2">
<a href="{% url 'preferences:paymentMethodsIndex' %}">Moyens de paiement</a>
<i class="fa fa-comments-dollar"></i> <a href="{% url 'preferences:paymentMethodsIndex' %}">Moyens de paiement</a>
</span>
{% endif %}
<span class="tabulation2">
<a href="{% url 'users:logout' %}">Deconnexion</a>
<i class="fa fa-bed"></i> <a href="{% url 'users:logout' %}">Deconnexion</a>
</span>
{% else %}
<a href="{% url 'users:login' %}">Connexion</a>
<i class="fa fa-sign-in"></i> <a href="{% url 'users:login' %}">Connexion</a>
{% endif %}

View file

@ -128,4 +128,5 @@ class ExportForm(forms.Form):
('debit', 'Débit')
)
query_type = forms.ChoiceField(choices=QUERY_TYPE_CHOICES, label="Ensemble de la demande")
fields = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=FIELDS_CHOICES, label="Champs")
fields = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=FIELDS_CHOICES, label="Champs")
group = forms.ModelChoiceField(queryset=Group.objects.all(), empty_label="Tous les groupes", required=False, label="Groupe")

View file

@ -169,4 +169,5 @@ def str_user(self):
fin = "Non adhérent"
return self.username + " (" + self.first_name + " " + self.last_name + ", " + str(self.profile.balance) + "€, " + fin + ")"
User.add_to_class("__str__", str_user)
User.add_to_class("__str__", str_user)

View file

@ -106,6 +106,7 @@
<form action="{% url 'users:exportCSV' %}" method="POST">
{% csrf_token %}
{{export_form}}
<br>
<button class="button" target="_blank">Exporter au format csv</button>
</form>
</section>

View file

@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load static %}
{% load users_extra %}
{% block entete %}{% if self %}Mon Profil{% else %}Profil de {{user}}{% endif %}{%endblock%}
{% block navbar %}
@ -62,20 +63,6 @@
{% if perms.users.can_change_user_perm %}
<span class="tabulation"><a href="{% url 'users:editGroups' user.pk %}">Changer les groupes</a></span>
{% endif %}
{% if request.user.is_staff %}
{% if user.is_staff %}
<span class="tabulation"><a href="">Retirer des admins</a></span>
{% else %}
<span class="tabulation"><a href="">Ajouter aux admins</a></span>
{% endif %}
{% endif %}
{% if request.user.is_superuser %}
{% if user.is_superuser %}
<span class="tabulation"><a href="">Retirer des superusers</a></span>
{% else %}
<span class="tabulation"><a href="">Ajouter aux superusers</a></span>
{% endif %}
{% endif %}
{% if perms.auth.change_user %}
<span class="tabulation"><a href="{% url 'users:switchActivateUser' user.pk %}">{{ user.is_active | yesno:"Désa,A"}}ctiver</a></span>
{% endif %}
@ -97,22 +84,10 @@
label: '# of Votes',
data: [{% for q in quantities %}{{q}}, {% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
{% for q in products %}
'rgb({% random_filter 0 255 %}, {% random_filter 0 255 %}, {% random_filter 0 255 %})',
{% endfor %}
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {

View file

View file

@ -0,0 +1,9 @@
import random
from django import template
register = template.Library()
@register.simple_tag
def random_filter(a, b):
return random.randint(a, b)

View file

@ -83,19 +83,24 @@ def export_csv(request):
users = User.objects
qt = export_form.cleaned_data['query_type']
if qt == 'all':
users = users.all()
filename="Utilisateurs-coope"
filename = "Utilisateurs-coope"
if not export_form.cleaned_data['group']:
users = users.all()
elif qt == 'all_active':
users = users.filter(is_active=True)
filename="Utilisateurs-actifs-coope"
filename = "Utilisateurs-actifs-coope"
elif qt == 'adherent':
pks = [x.pk for x in User.objects.all() if x.profile.is_adherent]
users = users.filter(pk__in=pks)
filename="Adherents-coope"
filename = "Adherents-coope"
elif qt == 'adherent_active':
pks = [x.pk for x in User.objects.filter(is_active=True) if x.profile.is_adherent]
users = users.filter(pk__in=pks)
filename="Adherents-actifs-coope"
filename = "Adherents-actifs-coope"
if export_form.cleaned_data['group']:
group = export_form.cleaned_data['group']
users = users.filter(groups=group)
filename += "(" + group.name + ")"
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="'+ filename + '.csv"'
writer = csv.writer(response)
@ -154,15 +159,25 @@ def profile(request, pk):
whitelists = WhiteListHistory.objects.filter(user=user)
reloads = Reload.objects.filter(customer=user).order_by('-date')[:5]
consumptionsChart = Consumption.objects.filter(customer=user)
products_pre = []
quantities_pre = []
for ch in consumptionsChart:
if ch.product in products_pre:
i = products_pre.index(ch.product)
quantities_pre[i] += int(ch.quantity/ch.product.showingMultiplier)
else:
products_pre.append(ch.product)
quantities_pre.append(int(ch.quantity/ch.product.showingMultiplier))
tot = len(products_pre)
totQ = sum(quantities_pre)
products = []
quantities = []
for ch in consumptionsChart:
if ch.product in products:
i = products.index(ch.product)
quantities[i] += ch.quantity
else:
products.append(ch.product)
quantities.append(ch.quantity)
for k in range(tot):
if quantities_pre[k]/totQ >= 0.01:
products.append(products_pre[k])
quantities.append(quantities_pre[k])
print(products)
print(quantities)
lastConsumptions = ConsumptionHistory.objects.filter(customer=user).order_by('-date')[:10]
lastMenus = MenuHistory.objects.filter(customer=user).order_by('-date')[:10]
return render(request, "users/profile.html",