3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-11-28 23:52:27 +00:00

Merge pull request #13 from nanoy42/stocks

Stocks. Fix #11
This commit is contained in:
Yoann Pietri 2019-08-28 12:35:02 +02:00 committed by GitHub
commit 9f417bbec6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 164 additions and 27 deletions

View file

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

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

View file

@ -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")
""" """
@ -95,7 +91,7 @@ class Product(models.Model):
def __str__(self): def __str__(self):
if self.draft_category == self.DRAFT_NONE: if self.draft_category == self.DRAFT_NONE:
return self.name + "(" + str(self.amount) + " €)" return self.name + " (" + str(self.amount) + " €)"
else: else:
return self.name + " (" + str(self.amount) + " €, " + str(self.deg) + "°)" return self.name + " (" + str(self.amount) + " €, " + str(self.deg) + "°)"

View file

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

View file

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

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

View file

@ -55,4 +55,6 @@ urlpatterns = [
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"),
] ]

View file

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

16
staticfiles/stocks.js Normal file
View 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);
});
}
});
});

View file

@ -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">
<br>
<i class="fa fa-boxes"></i> <a href="{% url 'gestion:stocks' %}">Stocks</a>
</span>
{% endif %}
<span class="tabulation2"> <span class="tabulation2">
<br>
<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 %}