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

Merge pull request #18 from nanoy42/dev

Dev
This commit is contained in:
Yoann Pietri 2019-08-29 12:47:48 +02:00 committed by GitHub
commit d7e21b6600
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 111 additions and 27 deletions

View file

@ -1,3 +1,6 @@
## v3.6.4
* Ajout d'un champ use_stocks
* Séparation des formulaires de fût
## v3.6.3 ## v3.6.3
* Refonte totale du système de stocks * Refonte totale du système de stocks
* Fix price profile * Fix price profile

View file

@ -59,10 +59,10 @@ 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', 'stock', 'volume', 'deg') list_display = ('name', 'amount', 'is_active', 'category', 'adherentRequired', 'stock', 'volume', 'deg', 'use_stocks')
ordering = ('name', 'amount', 'stock', 'deg') ordering = ('name', 'amount', 'stock', 'deg')
search_fields = ('name',) search_fields = ('name',)
list_filter = ('is_active', 'adherentRequired', 'category') list_filter = ('is_active', 'adherentRequired', 'category', 'use_stocks')
class ReloadAdmin(SimpleHistoryAdmin): class ReloadAdmin(SimpleHistoryAdmin):
""" """

View file

@ -42,9 +42,9 @@ class ProductForm(forms.ModelForm):
fields = "__all__" fields = "__all__"
widgets = {'amount': forms.TextInput} widgets = {'amount': forms.TextInput}
class KegForm(forms.ModelForm): class CreateKegForm(forms.ModelForm):
""" """
A form to create and edit a :class:`~gestion.models.Keg`. A form to create a :class:`~gestion.models.Keg`.
""" """
class Meta: class Meta:
@ -52,9 +52,24 @@ class KegForm(forms.ModelForm):
fields = ["name", "stockHold", "amount", "capacity"] fields = ["name", "stockHold", "amount", "capacity"]
widgets = {'amount': forms.TextInput} widgets = {'amount': forms.TextInput}
category = forms.ModelChoiceField(queryset=Category.objects.all(), label="Catégorie") category = forms.ModelChoiceField(queryset=Category.objects.all(), label="Catégorie", help_text="Catégorie dans laquelle placer les produits pinte, demi (et galopin si besoin).")
deg = forms.DecimalField(max_digits=5, decimal_places=2, label="Degré", validators=[MinValueValidator(0)]) deg = forms.DecimalField(max_digits=5, decimal_places=2, label="Degré", validators=[MinValueValidator(0)])
create_galopin = forms.BooleanField(label="Créer le produit galopin ?") create_galopin = forms.BooleanField(required=False, label="Créer le produit galopin ?")
def clean(self):
cleaned_data = super().clean()
if cleaned_data.get("name")[0:4] != "Fût ":
raise ValidationError("Le nom du fût doit être sous la forme 'Fût nom de la bière'")
class EditKegForm(forms.ModelForm):
"""
A form to edit a :class:`~gestion.models.Keg`.
"""
class Meta:
model = Keg
fields = ["name", "stockHold", "amount", "capacity", "pinte", "demi", "galopin"]
widgets = {'amount': forms.TextInput}
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()

View file

@ -0,0 +1,23 @@
# Generated by Django 2.1 on 2019-08-29 10:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0012_auto_20190827_2119'),
]
operations = [
migrations.AddField(
model_name='historicalproduct',
name='use_stocks',
field=models.BooleanField(default=True, verbose_name='Utiliser les stocks ?'),
),
migrations.AddField(
model_name='product',
name='use_stocks',
field=models.BooleanField(default=True, verbose_name='Utiliser les stocks ?'),
),
]

View file

@ -27,6 +27,13 @@ class Category(models.Model):
""" """
return self.product_set.filter(is_active=True) return self.product_set.filter(is_active=True)
@property
def active_stock_products(self):
"""
Return active products that use stocks
"""
return self.product_set.filter(is_active=True).filter(use_stocks=True)
class Product(models.Model): class Product(models.Model):
""" """
Stores a product. Stores a product.
@ -87,6 +94,7 @@ class Product(models.Model):
On the graphs on :func:`users.views.profile` view, the number of total consumptions is divised by the showingMultiplier On the graphs on :func:`users.views.profile` view, the number of total consumptions is divised by the showingMultiplier
""" """
draft_category = models.IntegerField(choices=DRAFT_TYPES, default=DRAFT_NONE, verbose_name="Type de pression") draft_category = models.IntegerField(choices=DRAFT_TYPES, default=DRAFT_NONE, verbose_name="Type de pression")
use_stocks = models.BooleanField(default=True, verbose_name="Utiliser les stocks ?")
history = HistoricalRecords() history = HistoricalRecords()
def __str__(self): def __str__(self):

View file

@ -19,5 +19,6 @@
<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>
<strong>Volume</strong> : {{ product.volume }}cl<br> <strong>Volume</strong> : {{ product.volume }}cl<br>
<strong>Utiliser les stocks</strong> : {{product.use_stocks|yesno:"Oui,Non"}}<br>
</section> </section>
{% endblock %} {% endblock %}

View file

@ -24,7 +24,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for product in category.active_products %} {% for product in category.active_stock_products %}
<tr id="tr-{{product.pk}}"> <tr id="tr-{{product.pk}}">
<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 id="stock-{{product.pk}}">{{ product.stock }}</td> <td id="stock-{{product.pk}}">{{ product.stock }}</td>

View file

@ -22,7 +22,7 @@ from decimal import *
import os import os
from math import floor, ceil from math import floor, ceil
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm, CategoryForm, SearchCategoryForm, GenerateInvoiceForm, ComputePriceForm from .forms import ReloadForm, RefundForm, ProductForm, CreateKegForm, EditKegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm, CategoryForm, SearchCategoryForm, GenerateInvoiceForm, ComputePriceForm
from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund, Category from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund, Category
from users.models import School from users.models import School
from preferences.models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile from preferences.models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile
@ -160,7 +160,7 @@ def order(request):
kegHistory.quantitySold += Decimal(quantity * 0.125) kegHistory.quantitySold += Decimal(quantity * 0.125)
kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.amountSold += Decimal(quantity * product.amount)
kegHistory.save() kegHistory.save()
else: if product.use_stocks:
if(product.stock > quantity): if(product.stock > quantity):
product.stock -= quantity product.stock -= quantity
product.save() product.save()
@ -197,11 +197,36 @@ 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.stock > quantity): if(article.draft_category == Product.DRAFT_PINTE):
article.stock -= quantity keg = get_object_or_404(Keg, pinte=article)
article.save() if(not keg.is_active):
else: raise Exception("Fût non actif")
raise Exception("Le stock du produit " + article.name + "n'autorise pas l'opération") kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.5)
kegHistory.amountSold += Decimal(quantity * product.amount)
kegHistory.save()
elif(article.draft_category == Product.DRAFT_DEMI):
keg = get_object_or_404(Keg, demi=article)
if(not keg.is_active):
raise Exception("Fût non actif")
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.25)
kegHistory.amountSold += Decimal(quantity * product.amount)
kegHistory.save()
elif(article.draft_category == Product.DRAFT_GALOPIN):
keg = get_object_or_404(Keg, galopin=article)
if(not keg.is_active):
raise Exception("Fût non actif")
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.quantitySold += Decimal(quantity * 0.125)
kegHistory.amountSold += Decimal(quantity * product.amount)
kegHistory.save()
if article.use_stocks:
if(article.stock > quantity):
article.stock -= quantity
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")
@ -296,8 +321,9 @@ 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 if product.use_stocks:
product.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}))
@ -467,8 +493,9 @@ class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
def update_stock(request, pk): def update_stock(request, pk):
product = get_object_or_404(Product, pk=pk) product = get_object_or_404(Product, pk=pk)
if("stock" in request.GET): if("stock" in request.GET):
product.stock = request.GET.get("stock") if product.use_stocks:
product.save() product.stock = request.GET.get("stock")
product.save()
return HttpResponse("Le stock a bien été mis à jour") return HttpResponse("Le stock a bien été mis à jour")
@active_required @active_required
@ -488,12 +515,16 @@ def stocks(request):
@permission_required('gestion.add_keg') @permission_required('gestion.add_keg')
def addKeg(request): def addKeg(request):
""" """
Displays a :class:`gestion.forms.KegForm` to add a :class:`gestion.models.Keg`. Displays a :class:`gestion.forms.CreateKegForm` to add a :class:`gestion.models.Keg`.
""" """
form = KegForm(request.POST or None) form = CreateKegForm(request.POST or None)
if form.is_valid(): if form.is_valid():
try:
price_profile = PriceProfile.objects.get(use_for_draft=True)
except:
messages.error(request, "Il n'y a pas de profil de prix pour les pressions")
return redirect(reverse('preferences:priceProfilesIndex'))
keg = form.save(commit=False) keg = form.save(commit=False)
price_profile = get_object_or_404(PriceProfile, use_for_draft=True)
pinte_price = compute_price(form.cleaned_data["amount"]/(2*form.cleaned_data["capacity"]), price_profile.a, price_profile.b, price_profile.c, price_profile.alpha) pinte_price = compute_price(form.cleaned_data["amount"]/(2*form.cleaned_data["capacity"]), price_profile.a, price_profile.b, price_profile.c, price_profile.alpha)
pinte_price = ceil(10*pinte_price)/10 pinte_price = ceil(10*pinte_price)/10
name = form.cleaned_data["name"][4:] name = form.cleaned_data["name"][4:]
@ -509,7 +540,8 @@ def addKeg(request):
deg = form.cleaned_data["deg"], deg = form.cleaned_data["deg"],
adherentRequired = True, adherentRequired = True,
showingMultiplier = 1, showingMultiplier = 1,
draft_category = Product.DRAFT_PINTE draft_category = Product.DRAFT_PINTE,
use_stocks=False,
) )
pinte.save() pinte.save()
keg.pinte = pinte keg.pinte = pinte
@ -524,7 +556,8 @@ def addKeg(request):
deg = form.cleaned_data["deg"], deg = form.cleaned_data["deg"],
adherentRequired = True, adherentRequired = True,
showingMultiplier = 1, showingMultiplier = 1,
draft_category = Product.DRAFT_DEMI draft_category = Product.DRAFT_DEMI,
use_stocks=False,
) )
demi.save() demi.save()
keg.demi = demi keg.demi = demi
@ -540,7 +573,8 @@ def addKeg(request):
deg = form.cleaned_data["deg"], deg = form.cleaned_data["deg"],
adherentRequired = True, adherentRequired = True,
showingMultiplier = 1, showingMultiplier = 1,
draft_category = Product.DRAFT_DEMI draft_category = Product.DRAFT_DEMI,
use_stocks=False,
) )
galopin.save() galopin.save()
keg.galopin = galopin keg.galopin = galopin
@ -554,13 +588,13 @@ def addKeg(request):
@permission_required('gestion.change_keg') @permission_required('gestion.change_keg')
def editKeg(request, pk): def editKeg(request, pk):
""" """
Displays a :class:`gestion.forms.KegForm` to edit a :class:`gestion.models.Keg`. Displays a :class:`gestion.forms.EditKegForm` to edit a :class:`gestion.models.Keg`.
pk pk
The primary key of the :class:`gestion.models.Keg` to edit. The primary key of the :class:`gestion.models.Keg` to edit.
""" """
keg = get_object_or_404(Keg, pk=pk) keg = get_object_or_404(Keg, pk=pk)
form = KegForm(request.POST or None, instance=keg) form = EditKegForm(request.POST or None, instance=keg)
if(form.is_valid()): if(form.is_valid()):
form.save() form.save()
messages.success(request, "Le fût a bien été modifié") messages.success(request, "Le fût a bien été modifié")

View file

@ -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.3 (release stable) &copy; 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p> <p class="copyright">coope.rez v3.6.4 (release stable) &copy; 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p>