mirror of
https://github.com/nanoy42/coope
synced 2024-11-25 04:43:11 +00:00
commit
cb449ee414
19 changed files with 260 additions and 85 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -45,3 +45,4 @@ static/
|
||||||
Pipfile
|
Pipfile
|
||||||
mediafiles
|
mediafiles
|
||||||
Pipfile.lock
|
Pipfile.lock
|
||||||
|
contributors.txt
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
## v3.6.3
|
||||||
|
* Refonte totale du système de stocks
|
||||||
|
* Fix price profile
|
||||||
|
* Rajoute un nombre de citations sur la page de statistiques
|
||||||
|
* Fix les contributeurs sur la page about et gencontributors en commande
|
||||||
## v3.6.2
|
## v3.6.2
|
||||||
* Fix sur les prix des cotisations.
|
* Fix sur les prix des cotisations.
|
||||||
* Page À propose
|
* Page À propose
|
||||||
|
|
15
coopeV3/management/commands/gencontributors.py
Normal file
15
coopeV3/management/commands/gencontributors.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Generate the git contributors file'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
try:
|
||||||
|
subprocess.call("rm " + settings.BASE_DIR + "/contributors.txt", shell=True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
subprocess.call("git -C " + settings.BASE_DIR + " shortlog -n $@ | grep \"):\" | sed 's|:||' >> " + settings.BASE_DIR + "/contributors.txt", shell=True)
|
||||||
|
subprocess.call("cat " + settings.BASE_DIR + "/contributors.txt", shell=True)
|
|
@ -25,11 +25,13 @@ urlpatterns = [
|
||||||
path('home', views.homepage, name="homepage"),
|
path('home', views.homepage, name="homepage"),
|
||||||
path('about', views.about, name="about"),
|
path('about', views.about, name="about"),
|
||||||
path('coope-runner', views.coope_runner, name="coope-runner"),
|
path('coope-runner', views.coope_runner, name="coope-runner"),
|
||||||
|
path('stats', views.stats, name="stats"),
|
||||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('users/', include('users.urls')),
|
path('users/', include('users.urls')),
|
||||||
path('gestion/', include('gestion.urls')),
|
path('gestion/', include('gestion.urls')),
|
||||||
path('preferences/', include('preferences.urls')),
|
path('preferences/', include('preferences.urls')),
|
||||||
|
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,15 @@ import os
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
||||||
from preferences.models import GeneralPreferences
|
from preferences.models import GeneralPreferences, PaymentMethod, Cotisation
|
||||||
from gestion.models import Keg
|
from gestion.models import Keg, ConsumptionHistory, Category, Product, Menu
|
||||||
|
from users.models import School
|
||||||
|
|
||||||
|
|
||||||
|
from .acl import active_required, admin_required
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
"""
|
"""
|
||||||
|
@ -38,16 +44,59 @@ def about(request):
|
||||||
"""
|
"""
|
||||||
A page about the project
|
A page about the project
|
||||||
"""
|
"""
|
||||||
os.system("git -C " + settings.BASE_DIR + " shortlog -n $@ | grep \"):\" | sed 's|:||' >> " + settings.BASE_DIR + "/contributors.txt")
|
|
||||||
contributors = []
|
contributors = []
|
||||||
|
try:
|
||||||
with open(settings.BASE_DIR + "/contributors.txt", "r") as f:
|
with open(settings.BASE_DIR + "/contributors.txt", "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
print(line)
|
contributors.append((line[:line.find('(')], int(line[(line.find('(') + 1):line.find(')')])))
|
||||||
print(line.split(" ")[0])
|
except:
|
||||||
contributors.append((line.split(" ")[0], int(line.split(" ")[1].replace("(", "").replace(")", "").replace("\n", ""))))
|
pass
|
||||||
os.system("rm " + settings.BASE_DIR + "/contributors.txt")
|
|
||||||
license = []
|
license = []
|
||||||
with open(settings.BASE_DIR + "/LICENSE", "r") as f:
|
with open(settings.BASE_DIR + "/LICENSE", "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
license.append(line)
|
license.append(line)
|
||||||
return render(request, "about.html", {"contributors": contributors, "license": license})
|
return render(request, "about.html", {"contributors": contributors, "license": license})
|
||||||
|
|
||||||
|
@active_required
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def stats(request):
|
||||||
|
users = User.objects.all()
|
||||||
|
adherents = [x for x in users if x.profile.is_adherent]
|
||||||
|
transactions = ConsumptionHistory.objects.all()
|
||||||
|
categories = Category.objects.all()
|
||||||
|
categories_shown = Category.objects.exclude(order=0)
|
||||||
|
products = Product.objects.all()
|
||||||
|
active_products = Product.objects.filter(is_active=True)
|
||||||
|
active_kegs = Keg.objects.filter(is_active=True)
|
||||||
|
sum_positive_balance = sum([x.profile.balance for x in users if x.profile.balance > 0])
|
||||||
|
sum_balance = sum([x.profile.balance for x in users])
|
||||||
|
schools = School.objects.all()
|
||||||
|
groups = Group.objects.all()
|
||||||
|
admins = User.objects.filter(is_staff=True)
|
||||||
|
superusers = User.objects.filter(is_superuser=True)
|
||||||
|
menus = Menu.objects.all()
|
||||||
|
payment_methods = PaymentMethod.objects.all()
|
||||||
|
cotisations = Cotisation.objects.all()
|
||||||
|
gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
|
||||||
|
nb_quotes = len(gp.global_message.split("\n"))
|
||||||
|
return render(request, "stats.html", {
|
||||||
|
"users": users,
|
||||||
|
"adherents": adherents,
|
||||||
|
"transactions": transactions,
|
||||||
|
"categories": categories,
|
||||||
|
"categories_shown": categories_shown,
|
||||||
|
"products": products,
|
||||||
|
"active_products": active_products,
|
||||||
|
"active_kegs": active_kegs,
|
||||||
|
"sum_positive_balance": sum_positive_balance,
|
||||||
|
"sum_balance": sum_balance,
|
||||||
|
"schools": schools,
|
||||||
|
"groups": groups,
|
||||||
|
"admins": admins,
|
||||||
|
"superusers": superusers,
|
||||||
|
"menus": menus,
|
||||||
|
"payment_methods": payment_methods,
|
||||||
|
"cotisations": cotisations,
|
||||||
|
"nb_quotes": nb_quotes,
|
||||||
|
})
|
|
@ -59,8 +59,8 @@ class ProductAdmin(SimpleHistoryAdmin):
|
||||||
"""
|
"""
|
||||||
The admin class for :class:`Products <gestion.models.Product>`.
|
The admin class for :class:`Products <gestion.models.Product>`.
|
||||||
"""
|
"""
|
||||||
list_display = ('name', 'amount', 'is_active', 'category', 'adherentRequired', 'stockHold', 'stockBar', 'volume', 'deg')
|
list_display = ('name', 'amount', 'is_active', 'category', 'adherentRequired', 'stock', 'volume', 'deg')
|
||||||
ordering = ('name', 'amount', 'stockHold', 'stockBar', 'deg')
|
ordering = ('name', 'amount', 'stock', 'deg')
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
list_filter = ('is_active', 'adherentRequired', 'category')
|
list_filter = ('is_active', 'adherentRequired', 'category')
|
||||||
|
|
||||||
|
|
53
gestion/migrations/0012_auto_20190827_2119.py
Normal file
53
gestion/migrations/0012_auto_20190827_2119.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Generated by Django 2.1 on 2019-08-27 19:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
def update(apps, schema_editor):
|
||||||
|
Product = apps.get_model('gestion', 'Product')
|
||||||
|
for product in Product.objects.all():
|
||||||
|
product.stock = product.stockBar
|
||||||
|
product.save()
|
||||||
|
|
||||||
|
def reverse(apps, schema_editor):
|
||||||
|
Product = apps.get_model('gestion', 'Product')
|
||||||
|
for product in Product.objects.all():
|
||||||
|
product.stockBar = product.stock
|
||||||
|
product.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gestion', '0011_auto_20190623_1640'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='historicalproduct',
|
||||||
|
name='stock',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='Stock'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='stock',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='Stock'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(update, reverse),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='historicalproduct',
|
||||||
|
name='stockBar',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='historicalproduct',
|
||||||
|
name='stockHold',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='product',
|
||||||
|
name='stockBar',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='product',
|
||||||
|
name='stockHold',
|
||||||
|
),
|
||||||
|
]
|
|
@ -54,13 +54,9 @@ class Product(models.Model):
|
||||||
"""
|
"""
|
||||||
The price of the product.
|
The price of the product.
|
||||||
"""
|
"""
|
||||||
stockHold = models.IntegerField(default=0, verbose_name="Stock en soute")
|
stock = models.IntegerField(default=0, verbose_name="Stock")
|
||||||
"""
|
"""
|
||||||
Number of product in the hold.
|
Number of product
|
||||||
"""
|
|
||||||
stockBar = models.IntegerField(default=0, verbose_name="Stock en bar")
|
|
||||||
"""
|
|
||||||
Number of product at the bar.
|
|
||||||
"""
|
"""
|
||||||
category = models.ForeignKey('Category', on_delete=models.PROTECT, verbose_name="Catégorie")
|
category = models.ForeignKey('Category', on_delete=models.PROTECT, verbose_name="Catégorie")
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
{% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small">Modifier</a><br>{% endif %}<br>
|
{% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small">Modifier</a><br>{% endif %}<br>
|
||||||
<strong>Nom</strong> : {{ product.name }}<br>
|
<strong>Nom</strong> : {{ product.name }}<br>
|
||||||
<strong>Prix de vente</strong> : {{ product.amount }}€<br>
|
<strong>Prix de vente</strong> : {{ product.amount }}€<br>
|
||||||
<strong>Stock en soute</strong> : {{ product.stockHold }}<br>
|
<strong>Stock en soute</strong> : {{ product.stock }}<br>
|
||||||
<strong>Stock au bar</strong> : {{ product.stockBar }}<br>
|
|
||||||
<strong>Catégorie</strong> : <a href="{% url 'gestion:categoryProfile' product.category.pk %}">{{ product.category }}</a><br>
|
<strong>Catégorie</strong> : <a href="{% url 'gestion:categoryProfile' product.category.pk %}">{{ product.category }}</a><br>
|
||||||
<strong>Actif</strong> : {{ product.is_active | yesno:"Oui, Non"}}<br>
|
<strong>Actif</strong> : {{ product.is_active | yesno:"Oui, Non"}}<br>
|
||||||
<strong>Dégré</strong> : {{ product.deg }}<br>
|
<strong>Dégré</strong> : {{ product.deg }}<br>
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nom</th>
|
<th>Nom</th>
|
||||||
<th>Prix</th>
|
<th>Prix</th>
|
||||||
<th>Stock (soute)</th>
|
<th>Stock</th>
|
||||||
<th>Stock (bar)</th>
|
|
||||||
<th>Catégorie</th>
|
<th>Catégorie</th>
|
||||||
<th>Actif</th>
|
<th>Actif</th>
|
||||||
<th>Degré</th>
|
<th>Degré</th>
|
||||||
|
@ -33,8 +32,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
|
<td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
|
||||||
<td>{{ product.amount}}</td>
|
<td>{{ product.amount}}</td>
|
||||||
<td>{{ product.stockHold }}</td>
|
<td>{{ product.stock }}</td>
|
||||||
<td>{{ product.stockBar }}</td>
|
|
||||||
<td>{{ product.category }}</td>
|
<td>{{ product.category }}</td>
|
||||||
<td>{{ product.is_active | yesno:"Oui, Non"}}</td>
|
<td>{{ product.is_active | yesno:"Oui, Non"}}</td>
|
||||||
<td>{{ product.deg }}</td>
|
<td>{{ product.deg }}</td>
|
||||||
|
|
41
gestion/templates/gestion/stocks.html
Normal file
41
gestion/templates/gestion/stocks.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block entete %}Gestion des produits{% endblock %}
|
||||||
|
{% block navbar%}
|
||||||
|
<ul>
|
||||||
|
{% for category in categories %}
|
||||||
|
<li><a href="#{{category}}">Stocks {{category}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% for category in categories %}
|
||||||
|
<section id="{{category}}" class="main">
|
||||||
|
<header class="major">
|
||||||
|
<h2>Stocks {{category}}</h2>
|
||||||
|
</header>
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nom</th>
|
||||||
|
<th>Stock</th>
|
||||||
|
<th>Mettre à jour</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for product in category.active_products %}
|
||||||
|
<tr id="tr-{{product.pk}}">
|
||||||
|
<td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
|
||||||
|
<td id="stock-{{product.pk}}">{{ product.stock }}</td>
|
||||||
|
<td><button class="update-stock" data-pk="{{product.pk}}" data-stock="{{product.stock}}" ><i class="fa fa-marker"></i></button></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
||||||
|
<script src="{% static 'jquery.js' %}"></script>
|
||||||
|
<script src="{% static 'stocks.js' %}"></script>
|
||||||
|
{% endblock %}
|
|
@ -52,8 +52,9 @@ urlpatterns = [
|
||||||
path('categoryProfile/<int:pk>', views.categoryProfile, name="categoryProfile"),
|
path('categoryProfile/<int:pk>', views.categoryProfile, name="categoryProfile"),
|
||||||
path('categoriesList', views.categoriesList, name="categoriesList"),
|
path('categoriesList', views.categoriesList, name="categoriesList"),
|
||||||
path('categories-autocomplete', views.CategoriesAutocomplete.as_view(), name="categories-autocomplete"),
|
path('categories-autocomplete', views.CategoriesAutocomplete.as_view(), name="categories-autocomplete"),
|
||||||
path('stats', views.stats, name="stats"),
|
|
||||||
path('divide', views.divide, name="divide"),
|
path('divide', views.divide, name="divide"),
|
||||||
path('gen_invoice', views.gen_invoice, name="gen_invoice"),
|
path('gen_invoice', views.gen_invoice, name="gen_invoice"),
|
||||||
path('compute-price', views.compute_price_view, name="compute-price"),
|
path('compute-price', views.compute_price_view, name="compute-price"),
|
||||||
|
path('stocks', views.stocks, name="stocks"),
|
||||||
|
path('updateStock/<int:pk>', views.update_stock, name="updateStock"),
|
||||||
]
|
]
|
|
@ -161,9 +161,11 @@ def order(request):
|
||||||
kegHistory.amountSold += Decimal(quantity * product.amount)
|
kegHistory.amountSold += Decimal(quantity * product.amount)
|
||||||
kegHistory.save()
|
kegHistory.save()
|
||||||
else:
|
else:
|
||||||
if(product.stockHold > 0):
|
if(product.stock > quantity):
|
||||||
product.stockHold -= 1
|
product.stock -= quantity
|
||||||
product.save()
|
product.save()
|
||||||
|
else:
|
||||||
|
raise Exception("Le stock du produit n'autorise pas l'opération")
|
||||||
consumption, _ = Consumption.objects.get_or_create(customer=user, product=product)
|
consumption, _ = Consumption.objects.get_or_create(customer=user, product=product)
|
||||||
consumption.quantity += quantity
|
consumption.quantity += quantity
|
||||||
consumption.save()
|
consumption.save()
|
||||||
|
@ -195,9 +197,11 @@ def order(request):
|
||||||
consumption, _ = Consumption.objects.get_or_create(customer=user, product=article)
|
consumption, _ = Consumption.objects.get_or_create(customer=user, product=article)
|
||||||
consumption.quantity += quantity
|
consumption.quantity += quantity
|
||||||
consumption.save()
|
consumption.save()
|
||||||
if(article.stockHold > 0):
|
if(article.stock > quantity):
|
||||||
article.stockHold -= 1
|
article.stock -= quantity
|
||||||
article.save()
|
article.save()
|
||||||
|
else:
|
||||||
|
raise Exception("Le stock du produit " + article.name + "n'autorise pas l'opération")
|
||||||
user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000)
|
user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000)
|
||||||
user.save()
|
user.save()
|
||||||
return HttpResponse("La commande a bien été effectuée")
|
return HttpResponse("La commande a bien été effectuée")
|
||||||
|
@ -282,6 +286,7 @@ def cancel_consumption(request, pk):
|
||||||
"""
|
"""
|
||||||
consumption = get_object_or_404(ConsumptionHistory, pk=pk)
|
consumption = get_object_or_404(ConsumptionHistory, pk=pk)
|
||||||
user = consumption.customer
|
user = consumption.customer
|
||||||
|
product = consumption.product
|
||||||
if consumption.paymentMethod.affect_balance:
|
if consumption.paymentMethod.affect_balance:
|
||||||
user.profile.debit -= consumption.amount
|
user.profile.debit -= consumption.amount
|
||||||
else:
|
else:
|
||||||
|
@ -291,6 +296,8 @@ def cancel_consumption(request, pk):
|
||||||
consumptionT = Consumption.objects.get(customer=user, product=consumption.product)
|
consumptionT = Consumption.objects.get(customer=user, product=consumption.product)
|
||||||
consumptionT.quantity -= consumption.quantity
|
consumptionT.quantity -= consumption.quantity
|
||||||
consumptionT.save()
|
consumptionT.save()
|
||||||
|
product.stock += consumption.quantity
|
||||||
|
product.save()
|
||||||
consumption.delete()
|
consumption.delete()
|
||||||
messages.success(request, "La consommation a bien été annulée")
|
messages.success(request, "La consommation a bien été annulée")
|
||||||
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
|
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
|
||||||
|
@ -311,7 +318,9 @@ def cancel_menu(request, pk):
|
||||||
user.profile.debit -= menu_history.amount
|
user.profile.debit -= menu_history.amount
|
||||||
else:
|
else:
|
||||||
user.profile.direct_debit -= menu_history.amount
|
user.profile.direct_debit -= menu_history.amount
|
||||||
for product in manu_history.menu.articles:
|
for product in menu_history.menu.articles:
|
||||||
|
product.stock += menu_history.quantity
|
||||||
|
product.save()
|
||||||
consumptionT = Consumption.objects.get(customer=user, product=product)
|
consumptionT = Consumption.objects.get(customer=user, product=product)
|
||||||
consumptionT -= menu_history.quantity
|
consumptionT -= menu_history.quantity
|
||||||
consumptionT.save()
|
consumptionT.save()
|
||||||
|
@ -322,6 +331,7 @@ def cancel_menu(request, pk):
|
||||||
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
|
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
|
||||||
|
|
||||||
########## Products ##########
|
########## Products ##########
|
||||||
|
|
||||||
@active_required
|
@active_required
|
||||||
@login_required
|
@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')
|
@acl_or('gestion.add_product', 'gestion.view_product', 'gestion.add_keg', 'gestion.view_keg', 'gestion.change_keg', 'gestion.view_menu', 'gestion.add_menu')
|
||||||
|
@ -451,6 +461,26 @@ class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
|
||||||
qs = qs.filter(name__icontains=self.q)
|
qs = qs.filter(name__icontains=self.q)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
@active_required
|
||||||
|
@login_required
|
||||||
|
@permission_required('gestion.change_product')
|
||||||
|
def update_stock(request, pk):
|
||||||
|
product = get_object_or_404(Product, pk=pk)
|
||||||
|
if("stock" in request.GET):
|
||||||
|
product.stock = request.GET.get("stock")
|
||||||
|
product.save()
|
||||||
|
return HttpResponse("Le stock a bien été mis à jour")
|
||||||
|
|
||||||
|
@active_required
|
||||||
|
@login_required
|
||||||
|
@permission_required('gestion.change_product')
|
||||||
|
def stocks(request):
|
||||||
|
"""
|
||||||
|
View to update stocks of active products
|
||||||
|
"""
|
||||||
|
categories = Category.objects.exclude(order=0).order_by("order")
|
||||||
|
return render(request, "gestion/stocks.html", {"categories": categories})
|
||||||
|
|
||||||
########## Kegs ##########
|
########## Kegs ##########
|
||||||
|
|
||||||
@active_required
|
@active_required
|
||||||
|
@ -471,8 +501,7 @@ def addKeg(request):
|
||||||
pinte = Product(
|
pinte = Product(
|
||||||
name = "Pinte " + name,
|
name = "Pinte " + name,
|
||||||
amount = pinte_price,
|
amount = pinte_price,
|
||||||
stockHold = 0,
|
stock = 0,
|
||||||
stockBar = 0,
|
|
||||||
category = form.cleaned_data["category"],
|
category = form.cleaned_data["category"],
|
||||||
needQuantityButton = False,
|
needQuantityButton = False,
|
||||||
is_active = True,
|
is_active = True,
|
||||||
|
@ -487,8 +516,7 @@ def addKeg(request):
|
||||||
demi = Product(
|
demi = Product(
|
||||||
name = "Demi " + name,
|
name = "Demi " + name,
|
||||||
amount = ceil(5*pinte_price)/10,
|
amount = ceil(5*pinte_price)/10,
|
||||||
stockHold = 0,
|
stock = 0,
|
||||||
stockBar = 0,
|
|
||||||
category = form.cleaned_data["category"],
|
category = form.cleaned_data["category"],
|
||||||
needQuantityButton = False,
|
needQuantityButton = False,
|
||||||
is_active = True,
|
is_active = True,
|
||||||
|
@ -504,8 +532,7 @@ def addKeg(request):
|
||||||
galopin = Product(
|
galopin = Product(
|
||||||
name = "Galopin " + name,
|
name = "Galopin " + name,
|
||||||
amount = ceil(2.5 * pinte_price)/10,
|
amount = ceil(2.5 * pinte_price)/10,
|
||||||
stockHold = 0,
|
stock = 0,
|
||||||
stockBar = 0,
|
|
||||||
category = form.cleaned_data["category"],
|
category = form.cleaned_data["category"],
|
||||||
needQuantityButton = False,
|
needQuantityButton = False,
|
||||||
is_active = True,
|
is_active = True,
|
||||||
|
@ -1013,7 +1040,9 @@ def divide(request):
|
||||||
"divide_histories": divide_histories,
|
"divide_histories": divide_histories,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
########## categories ##########
|
########## categories ##########
|
||||||
|
|
||||||
@active_required
|
@active_required
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('gestion.add_category')
|
@permission_required('gestion.add_category')
|
||||||
|
@ -1091,47 +1120,6 @@ class CategoriesAutocomplete(autocomplete.Select2QuerySetView):
|
||||||
qs = qs.filter(name__icontains=self.q)
|
qs = qs.filter(name__icontains=self.q)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
@active_required
|
|
||||||
@login_required
|
|
||||||
@admin_required
|
|
||||||
def stats(request):
|
|
||||||
users = User.objects.all()
|
|
||||||
adherents = [x for x in users if x.profile.is_adherent]
|
|
||||||
transactions = ConsumptionHistory.objects.all()
|
|
||||||
categories = Category.objects.all()
|
|
||||||
categories_shown = Category.objects.exclude(order=0)
|
|
||||||
products = Product.objects.all()
|
|
||||||
active_products = Product.objects.filter(is_active=True)
|
|
||||||
active_kegs = Keg.objects.filter(is_active=True)
|
|
||||||
sum_positive_balance = sum([x.profile.balance for x in users if x.profile.balance > 0])
|
|
||||||
sum_balance = sum([x.profile.balance for x in users])
|
|
||||||
schools = School.objects.all()
|
|
||||||
groups = Group.objects.all()
|
|
||||||
admins = User.objects.filter(is_staff=True)
|
|
||||||
superusers = User.objects.filter(is_superuser=True)
|
|
||||||
menus = Menu.objects.all()
|
|
||||||
payment_methods = PaymentMethod.objects.all()
|
|
||||||
cotisations = Cotisation.objects.all()
|
|
||||||
return render(request, "gestion/stats.html", {
|
|
||||||
"users": users,
|
|
||||||
"adherents": adherents,
|
|
||||||
"transactions": transactions,
|
|
||||||
"categories": categories,
|
|
||||||
"categories_shown": categories_shown,
|
|
||||||
"products": products,
|
|
||||||
"active_products": active_products,
|
|
||||||
"active_kegs": active_kegs,
|
|
||||||
"sum_positive_balance": sum_positive_balance,
|
|
||||||
"sum_balance": sum_balance,
|
|
||||||
"schools": schools,
|
|
||||||
"groups": groups,
|
|
||||||
"admins": admins,
|
|
||||||
"superusers": superusers,
|
|
||||||
"menus": menus,
|
|
||||||
"payment_methods": payment_methods,
|
|
||||||
"cotisations": cotisations,
|
|
||||||
})
|
|
||||||
|
|
||||||
########## Compute price ##########
|
########## Compute price ##########
|
||||||
|
|
||||||
def compute_price_view(request):
|
def compute_price_view(request):
|
||||||
|
|
|
@ -242,6 +242,6 @@ def delete_price_profile(request,pk):
|
||||||
"""
|
"""
|
||||||
price_profile = get_object_or_404(PriceProfile, pk=pk)
|
price_profile = get_object_or_404(PriceProfile, pk=pk)
|
||||||
message = "Le profil de prix " + price_profile.name + " a bien été supprimé"
|
message = "Le profil de prix " + price_profile.name + " a bien été supprimé"
|
||||||
price_pofile.delete()
|
price_profile.delete()
|
||||||
messages.success(request, message)
|
messages.success(request, message)
|
||||||
return redirect(reverse('preferences:priceProfilesIndex'))
|
return redirect(reverse('preferences:priceProfilesIndex'))
|
||||||
|
|
16
staticfiles/stocks.js
Normal file
16
staticfiles/stocks.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
$(document).ready(function(){
|
||||||
|
$(".update-stock").click(function(){
|
||||||
|
var pk = $(this).attr('data-pk');
|
||||||
|
var current_value = $(this).attr('data-stock');
|
||||||
|
var ok = false;
|
||||||
|
while(!ok){
|
||||||
|
var new_stock = prompt("Nouveau stock ? (entier attendu)", current_value);
|
||||||
|
ok = new_stock == null || !(isNaN(parseInt(new_stock)));
|
||||||
|
}
|
||||||
|
if(new_stock != null){
|
||||||
|
$.get("/gestion/updateStock/" + pk, {"stock": new_stock}, function(data){
|
||||||
|
$("#stock-"+pk).html(new_stock);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,8 +28,6 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
(<a href="https://github.com/nanoy42/coope/blob/master/LICENSE" target="_blank">https://github.com/nanoy42/coope/blob/master/LICENSE</a>).
|
(<a href="https://github.com/nanoy42/coope/blob/master/LICENSE" target="_blank">https://github.com/nanoy42/coope/blob/master/LICENSE</a>).
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
Version 3.6.2.
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="third" class="main">
|
<section id="third" class="main">
|
||||||
|
@ -37,12 +35,16 @@
|
||||||
<h2>Contributeurs</h2>
|
<h2>Contributeurs</h2>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
|
{% if contributors %}
|
||||||
Les contributeurs, triés par ordre décroissant de nombre de commits, sont:
|
Les contributeurs, triés par ordre décroissant de nombre de commits, sont:
|
||||||
<ol>
|
<ol>
|
||||||
{% for contributor in contributors %}
|
{% for contributor in contributors %}
|
||||||
<li>{{contributor.0}} ({{contributor.1}} commits)</li>
|
<li>{{contributor.0}} ({{contributor.1}} commits)</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
|
{% else %}
|
||||||
|
Impossible d'afficher la liste des contributeurs
|
||||||
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -42,6 +42,6 @@
|
||||||
<li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li>
|
<li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<p class="copyright">coope.rez v3.6.2 (release stable) © 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p>
|
<p class="copyright">coope.rez v3.6.3 (release stable) © 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,13 @@
|
||||||
<i class="fa fa-dolly-flatbed"></i> <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>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if perms.gestion.change_product %}
|
||||||
<span class="tabulation2">
|
<span class="tabulation2">
|
||||||
<br>
|
<br>
|
||||||
|
<i class="fa fa-boxes"></i> <a href="{% url 'gestion:stocks' %}">Stocks</a>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
<span class="tabulation2">
|
||||||
<i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a>
|
<i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a>
|
||||||
</span>
|
</span>
|
||||||
{% if perms.preferences.change_generalpreferences %}
|
{% if perms.preferences.change_generalpreferences %}
|
||||||
|
@ -31,7 +36,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_staff %}
|
{% if request.user.is_staff %}
|
||||||
<span class="tabulation2">
|
<span class="tabulation2">
|
||||||
<i class="fa fa-chart-bar"></i> <a href="{% url 'gestion:stats' %}">Stats</a>
|
<i class="fa fa-chart-bar"></i> <a href="{% url 'stats' %}">Stats</a>
|
||||||
</span>
|
</span>
|
||||||
<span class="tabulation2">
|
<span class="tabulation2">
|
||||||
<i class="fa fa-business-time"></i> <a href="{% url 'gestion:gen_releve' %}">Relevé</a>
|
<i class="fa fa-business-time"></i> <a href="{% url 'gestion:gen_releve' %}">Relevé</a>
|
||||||
|
|
|
@ -63,6 +63,10 @@
|
||||||
<td>Nombre de superusers</td>
|
<td>Nombre de superusers</td>
|
||||||
<td>{{superusers.count}}</td>
|
<td>{{superusers.count}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nombre de citations</td>
|
||||||
|
<td>{{nb_quotes}}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Nombre 8</td>
|
<td>Nombre 8</td>
|
||||||
<td>8</td>
|
<td>8</td>
|
Loading…
Reference in a new issue