From 5a1ae12f6cfdaf65caa8c1a0b2124cf7fd4c6f0f Mon Sep 17 00:00:00 2001 From: nanoy Date: Thu, 29 Aug 2019 12:35:47 +0200 Subject: [PATCH 1/4] Add use_stocks field --- gestion/admin.py | 4 +- gestion/forms.py | 2 +- gestion/models.py | 8 +++ .../templates/gestion/product_profile.html | 1 + gestion/templates/gestion/stocks.html | 2 +- gestion/views.py | 62 ++++++++++++++----- 6 files changed, 61 insertions(+), 18 deletions(-) diff --git a/gestion/admin.py b/gestion/admin.py index 95b9471..8097687 100644 --- a/gestion/admin.py +++ b/gestion/admin.py @@ -59,10 +59,10 @@ class ProductAdmin(SimpleHistoryAdmin): """ The admin class for :class:`Products `. """ - 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') search_fields = ('name',) - list_filter = ('is_active', 'adherentRequired', 'category') + list_filter = ('is_active', 'adherentRequired', 'category', 'use_stocks') class ReloadAdmin(SimpleHistoryAdmin): """ diff --git a/gestion/forms.py b/gestion/forms.py index daa8b8c..5aa0af7 100644 --- a/gestion/forms.py +++ b/gestion/forms.py @@ -54,7 +54,7 @@ class KegForm(forms.ModelForm): category = forms.ModelChoiceField(queryset=Category.objects.all(), label="Catégorie") 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() diff --git a/gestion/models.py b/gestion/models.py index 64267d2..627cebf 100644 --- a/gestion/models.py +++ b/gestion/models.py @@ -26,6 +26,13 @@ class Category(models.Model): Return active producs of this category """ 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): """ @@ -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 """ 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() def __str__(self): diff --git a/gestion/templates/gestion/product_profile.html b/gestion/templates/gestion/product_profile.html index b9dde04..4858c27 100644 --- a/gestion/templates/gestion/product_profile.html +++ b/gestion/templates/gestion/product_profile.html @@ -19,5 +19,6 @@ Actif : {{ product.is_active | yesno:"Oui, Non"}}
Dégré : {{ product.deg }}
Volume : {{ product.volume }}cl
+ Utiliser les stocks : {{product.use_stocks|yesno:"Oui,Non"}}
{% endblock %} diff --git a/gestion/templates/gestion/stocks.html b/gestion/templates/gestion/stocks.html index 82f0671..69ea005 100644 --- a/gestion/templates/gestion/stocks.html +++ b/gestion/templates/gestion/stocks.html @@ -24,7 +24,7 @@ - {% for product in category.active_products %} + {% for product in category.active_stock_products %} {{ product.name }} {{ product.stock }} diff --git a/gestion/views.py b/gestion/views.py index f8e4bed..cb2d353 100644 --- a/gestion/views.py +++ b/gestion/views.py @@ -160,7 +160,7 @@ def order(request): kegHistory.quantitySold += Decimal(quantity * 0.125) kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.save() - else: + if product.use_stocks: if(product.stock > quantity): product.stock -= quantity product.save() @@ -197,11 +197,36 @@ def order(request): consumption, _ = Consumption.objects.get_or_create(customer=user, product=article) consumption.quantity += quantity consumption.save() - if(article.stock > quantity): - article.stock -= quantity - article.save() - else: - raise Exception("Le stock du produit " + article.name + "n'autorise pas l'opération") + if(article.draft_category == Product.DRAFT_PINTE): + keg = get_object_or_404(Keg, pinte=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.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.save() 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.quantity -= consumption.quantity consumptionT.save() - product.stock += consumption.quantity - product.save() + if product.use_stocks: + product.stock += consumption.quantity + product.save() consumption.delete() messages.success(request, "La consommation a bien été annulée") return redirect(reverse('users:profile', kwargs={'pk': user.pk})) @@ -467,8 +493,9 @@ class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView): 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() + if product.use_stocks: + product.stock = request.GET.get("stock") + product.save() return HttpResponse("Le stock a bien été mis à jour") @active_required @@ -492,8 +519,12 @@ def addKeg(request): """ form = KegForm(request.POST or None) 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) - 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 = ceil(10*pinte_price)/10 name = form.cleaned_data["name"][4:] @@ -509,7 +540,8 @@ def addKeg(request): deg = form.cleaned_data["deg"], adherentRequired = True, showingMultiplier = 1, - draft_category = Product.DRAFT_PINTE + draft_category = Product.DRAFT_PINTE, + use_stocks=False, ) pinte.save() keg.pinte = pinte @@ -524,7 +556,8 @@ def addKeg(request): deg = form.cleaned_data["deg"], adherentRequired = True, showingMultiplier = 1, - draft_category = Product.DRAFT_DEMI + draft_category = Product.DRAFT_DEMI, + use_stocks=False, ) demi.save() keg.demi = demi @@ -540,7 +573,8 @@ def addKeg(request): deg = form.cleaned_data["deg"], adherentRequired = True, showingMultiplier = 1, - draft_category = Product.DRAFT_DEMI + draft_category = Product.DRAFT_DEMI, + use_stocks=False, ) galopin.save() keg.galopin = galopin From 03b07cad954b0d4c2f08a0b31279b300d42d0938 Mon Sep 17 00:00:00 2001 From: nanoy Date: Thu, 29 Aug 2019 12:35:52 +0200 Subject: [PATCH 2/4] Add use_stocks field --- gestion/migrations/0013_auto_20190829_1219.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 gestion/migrations/0013_auto_20190829_1219.py diff --git a/gestion/migrations/0013_auto_20190829_1219.py b/gestion/migrations/0013_auto_20190829_1219.py new file mode 100644 index 0000000..79c38d5 --- /dev/null +++ b/gestion/migrations/0013_auto_20190829_1219.py @@ -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 ?'), + ), + ] From 2718884b77dd42493d12fbc5665c318d65b51b47 Mon Sep 17 00:00:00 2001 From: nanoy Date: Thu, 29 Aug 2019 12:45:30 +0200 Subject: [PATCH 3/4] Divide keg forms --- gestion/forms.py | 21 ++++++++++++++++++--- gestion/views.py | 10 +++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/gestion/forms.py b/gestion/forms.py index 5aa0af7..20822bc 100644 --- a/gestion/forms.py +++ b/gestion/forms.py @@ -42,9 +42,9 @@ class ProductForm(forms.ModelForm): fields = "__all__" 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: @@ -52,7 +52,7 @@ class KegForm(forms.ModelForm): fields = ["name", "stockHold", "amount", "capacity"] 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)]) create_galopin = forms.BooleanField(required=False, label="Créer le produit galopin ?") @@ -61,6 +61,21 @@ class KegForm(forms.ModelForm): 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): + 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 MenuForm(forms.ModelForm): """ A form to create and edit a :class:`~gestion.models.Menu`. diff --git a/gestion/views.py b/gestion/views.py index cb2d353..860eb7c 100644 --- a/gestion/views.py +++ b/gestion/views.py @@ -22,7 +22,7 @@ from decimal import * import os 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 users.models import School from preferences.models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile @@ -515,9 +515,9 @@ def stocks(request): @permission_required('gestion.add_keg') 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(): try: price_profile = PriceProfile.objects.get(use_for_draft=True) @@ -588,13 +588,13 @@ def addKeg(request): @permission_required('gestion.change_keg') 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 The primary key of the :class:`gestion.models.Keg` to edit. """ 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()): form.save() messages.success(request, "Le fût a bien été modifié") From 190ef87f81936c439112cb139fe606a062cab620 Mon Sep 17 00:00:00 2001 From: nanoy Date: Thu, 29 Aug 2019 12:47:07 +0200 Subject: [PATCH 4/4] Update version info --- CHANGELOG.md | 3 +++ templates/footer.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6452260..031d8a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v3.6.4 +* Ajout d'un champ use_stocks +* Séparation des formulaires de fût ## v3.6.3 * Refonte totale du système de stocks * Fix price profile diff --git a/templates/footer.html b/templates/footer.html index c45aa08..ffb1fac 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -42,6 +42,6 @@
  • Facebook
  • - +