3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-11-28 15:42:25 +00:00
coope/gestion/views.py

1145 lines
47 KiB
Python
Raw Normal View History

2018-11-22 21:52:15 +00:00
from django.shortcuts import render, redirect, get_object_or_404
2018-10-05 22:03:02 +00:00
from django.contrib import messages
from django.urls import reverse
2018-11-22 21:52:15 +00:00
from django.http import HttpResponse, Http404
2019-05-03 21:27:11 +00:00
from django.contrib.auth.models import User, Group
2018-11-22 21:52:15 +00:00
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required, permission_required
2018-11-25 12:52:32 +00:00
from django.utils import timezone
2018-12-24 00:30:00 +00:00
from django.http import HttpResponseRedirect
2019-01-22 19:27:18 +00:00
from django.db import transaction
2019-06-23 11:46:12 +00:00
from django.conf import settings
2018-10-05 22:03:02 +00:00
2019-01-22 19:27:18 +00:00
from datetime import datetime, timedelta
2019-01-05 23:01:30 +00:00
2019-01-22 19:27:18 +00:00
from django_tex.views import render_to_pdf
2019-01-05 23:01:30 +00:00
from coopeV3.acl import active_required, acl_or, admin_required
2019-06-23 13:31:55 +00:00
from coopeV3.utils import compute_price
2018-11-22 21:52:15 +00:00
import simplejson as json
2018-10-05 22:03:02 +00:00
from dal import autocomplete
2018-11-22 21:52:15 +00:00
from decimal import *
2019-06-23 11:46:12 +00:00
import os
2019-06-23 13:31:55 +00:00
from math import floor, ceil
2018-10-05 22:03:02 +00:00
2019-06-23 13:31:55 +00:00
from .forms import ReloadForm, RefundForm, ProductForm, KegForm, MenuForm, GestionForm, SearchMenuForm, SearchProductForm, SelectPositiveKegForm, SelectActiveKegForm, PinteForm, GenerateReleveForm, CategoryForm, SearchCategoryForm, GenerateInvoiceForm, ComputePriceForm
2019-05-03 19:09:32 +00:00
from .models import Product, Menu, Keg, ConsumptionHistory, KegHistory, Consumption, MenuHistory, Pinte, Reload, Refund, Category
2019-05-03 21:27:11 +00:00
from users.models import School
from preferences.models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile
2019-01-05 23:01:30 +00:00
from users.models import CotisationHistory
2018-08-31 12:46:35 +00:00
2018-11-22 21:52:15 +00:00
@active_required
@login_required
@acl_or('gestion.add_consumptionhistory', 'gestion.add_reload', 'gestion.add_refund')
def manage(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays the manage view.
2018-12-02 15:28:40 +00:00
"""
2019-05-03 19:09:32 +00:00
categories = Category.objects.exclude(order=0).order_by('order')
2018-11-22 21:52:15 +00:00
pay_buttons = PaymentMethod.objects.filter(is_active=True)
2018-10-05 22:03:02 +00:00
gestion_form = GestionForm(request.POST or None)
reload_form = ReloadForm(request.POST or None)
refund_form = RefundForm(request.POST or None)
bieresPression = []
menus = Menu.objects.filter(is_active=True)
kegs = Keg.objects.filter(is_active=True)
2019-01-06 04:18:31 +00:00
gp, _ = GeneralPreferences.objects.get_or_create(pk=1)
2019-01-22 19:27:18 +00:00
cotisations = Cotisation.objects.all()
2019-01-06 04:18:31 +00:00
floating_buttons = gp.floating_buttons
2018-10-05 22:03:02 +00:00
for keg in kegs:
if(keg.pinte):
bieresPression.append(keg.pinte)
if(keg.demi):
bieresPression.append(keg.demi)
if(keg.galopin):
bieresPression.append(keg.galopin)
2018-12-02 15:28:40 +00:00
return render(request, "gestion/manage.html", {
"gestion_form": gestion_form,
"reload_form": reload_form,
"refund_form": refund_form,
"bieresPression": bieresPression,
2019-05-03 19:09:32 +00:00
"categories": categories,
2019-01-06 04:18:31 +00:00
"pay_buttons": pay_buttons,
"floating_buttons": floating_buttons,
2019-01-22 19:27:18 +00:00
"cotisations": cotisations
2018-12-02 15:28:40 +00:00
})
2018-11-22 21:52:15 +00:00
2018-12-02 18:50:15 +00:00
@csrf_exempt
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_consumptionhistory')
def order(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Processes the given order. The order is passed through POST.
2018-12-02 15:28:40 +00:00
"""
2019-01-22 19:27:18 +00:00
error_message = "Impossible d'effectuer la transaction. Toute opération abandonnée. Veuillez contacter le président ou le trésorier"
try:
with transaction.atomic():
if("user" not in request.POST or "paymentMethod" not in request.POST or "amount" not in request.POST or "order" not in request.POST):
raise Exception("Erreur du post")
2018-11-25 12:52:32 +00:00
else:
2019-01-22 19:27:18 +00:00
user = get_object_or_404(User, pk=request.POST['user'])
paymentMethod = get_object_or_404(PaymentMethod, pk=request.POST['paymentMethod'])
amount = Decimal(request.POST['amount'])
order = json.loads(request.POST["order"])
menus = json.loads(request.POST["menus"])
listPintes = json.loads(request.POST["listPintes"])
cotisations = json.loads(request.POST['cotisations'])
gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
if (not order) and (not menus) and (not cotisations):
error_message = "Pas de commande"
raise Exception(error_message)
if(cotisations):
for co in cotisations:
cotisation = Cotisation.objects.get(pk=co['pk'])
for i in range(co['quantity']):
cotisation_history = CotisationHistory(cotisation=cotisation)
if(paymentMethod.affect_balance):
if(user.profile.balance >= cotisation_history.cotisation.amount):
user.profile.debit += cotisation_history.cotisation.amount
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
2019-06-23 15:11:58 +00:00
else:
user.profile.direct_debit += cotisation_history.cotisation.amount
2019-01-22 19:27:18 +00:00
cotisation_history.user = user
cotisation_history.coopeman = request.user
cotisation_history.amount = cotisation.amount
cotisation_history.duration = cotisation.duration
cotisation_history.paymentMethod = paymentMethod
if(user.profile.cotisationEnd and user.profile.cotisationEnd > timezone.now()):
cotisation_history.endDate = user.profile.cotisationEnd + timedelta(days=cotisation.duration)
else:
cotisation_history.endDate = timezone.now() + timedelta(days=cotisation.duration)
user.profile.cotisationEnd = cotisation_history.endDate
user.save()
cotisation_history.save()
adherentRequired = False
for o in order:
product = get_object_or_404(Product, pk=o["pk"])
adherentRequired = adherentRequired or product.adherentRequired
for m in menus:
menu = get_object_or_404(Menu, pk=m["pk"])
adherentRequired = adherentRequired or menu.adherent_required
if(adherentRequired and not user.profile.is_adherent):
error_message = "N'est pas adhérent et devrait l'être."
raise Exception(error_message)
# Partie un peu complexe : je libère toutes les pintes de la commande, puis je test
# s'il a trop de pintes non rendues, puis je réalloue les pintes
for pinte in listPintes:
allocate(pinte, None)
if(gp.use_pinte_monitoring and gp.lost_pintes_allowed and user.profile.nb_pintes >= gp.lost_pintes_allowed):
error_message = "Impossible de réaliser la commande : l'utilisateur a perdu trop de pintes."
raise Exception(error_message)
for pinte in listPintes:
allocate(pinte, user)
for o in order:
product = get_object_or_404(Product, pk=o["pk"])
quantity = int(o["quantity"])
2019-05-06 07:40:40 +00:00
if(product.draft_category == Product.DRAFT_PINTE):
2019-01-22 19:27:18 +00:00
keg = get_object_or_404(Keg, pinte=product)
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()
2019-05-06 07:40:40 +00:00
elif(product.draft_category == Product.DRAFT_DEMI):
2019-01-22 19:27:18 +00:00
keg = get_object_or_404(Keg, demi=product)
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()
2019-05-06 07:40:40 +00:00
elif(product.draft_category == Product.DRAFT_GALOPIN):
2019-01-22 19:27:18 +00:00
keg = get_object_or_404(Keg, galopin=product)
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()
else:
if(product.stockHold > 0):
product.stockHold -= 1
product.save()
consumption, _ = Consumption.objects.get_or_create(customer=user, product=product)
consumption.quantity += quantity
consumption.save()
ch = ConsumptionHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, product=product, amount=Decimal(quantity*product.amount), coopeman=request.user)
ch.save()
2019-06-12 21:53:01 +00:00
user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000)
2019-01-26 16:02:23 +00:00
if(paymentMethod.affect_balance):
if(user.profile.balance >= Decimal(product.amount*quantity)):
user.profile.debit += Decimal(product.amount*quantity)
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
2019-06-23 15:11:58 +00:00
else:
user.profile.direct_debit += Decimal(product.amount*quantity)
2019-01-22 19:27:18 +00:00
for m in menus:
menu = get_object_or_404(Menu, pk=m["pk"])
quantity = int(m["quantity"])
mh = MenuHistory(customer=user, quantity=quantity, paymentMethod=paymentMethod, menu=menu, amount=int(quantity*menu.amount), coopeman=request.user)
mh.save()
2019-01-26 16:02:23 +00:00
if(paymentMethod.affect_balance):
if(user.profile.balance >= Decimal(product.amount*quantity)):
user.profile.debit += Decimal(product.amount*quantity)
else:
error_message = "Solde insuffisant"
raise Exception(error_message)
2019-06-23 15:11:58 +00:00
else:
user.profile.direct_debit += Decimal(product.amount*quantity)
2019-01-22 19:27:18 +00:00
for article in menu.articles.all():
consumption, _ = Consumption.objects.get_or_create(customer=user, product=article)
consumption.quantity += quantity
consumption.save()
if(article.stockHold > 0):
article.stockHold -= 1
article.save()
2019-06-12 21:53:01 +00:00
user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000)
2019-01-24 21:33:48 +00:00
user.save()
2019-01-22 19:27:18 +00:00
return HttpResponse("La commande a bien été effectuée")
except Exception as e:
return HttpResponse(error_message)
2018-11-22 21:52:15 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_reload')
2018-10-05 22:03:02 +00:00
def reload(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`Reload form <gestion.forms.reloadForm>`.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
reload_form = ReloadForm(request.POST or None)
2018-12-02 15:28:40 +00:00
if reload_form.is_valid():
reload_entry = reload_form.save(commit=False)
reload_entry.coopeman = request.user
reload_entry.save()
2018-10-05 22:03:02 +00:00
user = reload_form.cleaned_data['customer']
amount = reload_form.cleaned_data['amount']
user.profile.credit += amount
user.save()
2018-12-02 15:28:40 +00:00
messages.success(request, "Le compte de " + user.username + " a bien été crédité de " + str(amount) + "")
2018-10-05 22:03:02 +00:00
else:
messages.error(request, "Le rechargement a échoué")
return redirect(reverse('gestion:manage'))
2018-12-24 00:30:00 +00:00
@active_required
@login_required
@permission_required('gestion.delete_reload')
def cancel_reload(request, pk):
"""
2019-02-28 12:18:41 +00:00
Delete a :class:`gestion.models.Reload`.
pk
The primary key of the reload to delete.
2018-12-24 00:30:00 +00:00
"""
reload_entry = get_object_or_404(Reload, pk=pk)
if reload_entry.customer.profile.balance >= reload_entry.amount:
reload_entry.customer.profile.credit -= reload_entry.amount
reload_entry.customer.save()
reload_entry.delete()
messages.success(request, "Le rechargement a bien été annulé.")
else:
messages.error(request, "Impossible d'annuler le rechargement. Le solde deviendrait négatif.")
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_refund')
2018-10-05 22:03:02 +00:00
def refund(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`Refund form <gestion.forms.RefundForm>`.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
refund_form = RefundForm(request.POST or None)
2018-12-02 15:28:40 +00:00
if refund_form.is_valid():
2018-10-05 22:03:02 +00:00
user = refund_form.cleaned_data['customer']
amount = refund_form.cleaned_data['amount']
2018-12-02 15:28:40 +00:00
if amount <= user.profile.balance:
refund_entry = refund_form.save(commit = False)
refund_entry.coopeman = request.user
refund_entry.save()
2018-10-05 22:03:02 +00:00
user.profile.credit -= amount
user.save()
messages.success(request, "Le compte de " + user.username + " a bien été remboursé de " + str(amount) + "")
else:
messages.error(request, "Impossible de rembourser l'utilisateur " + user.username + " de " + str(amount) + "€ : il n'a que " + str(user.profile.balance) + "€ sur son compte.")
else:
messages.error(request, "Le remboursement a échoué")
return redirect(reverse('gestion:manage'))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-30 18:54:12 +00:00
@login_required
@permission_required('gestion.delete_consumptionhistory')
def cancel_consumption(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Delete a :class:`consumption history <gestion.models.ConsumptionHistory>`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the consumption history to delete.
2018-12-02 15:28:40 +00:00
"""
2018-11-30 18:54:12 +00:00
consumption = get_object_or_404(ConsumptionHistory, pk=pk)
user = consumption.customer
2018-12-18 10:38:20 +00:00
if consumption.paymentMethod.affect_balance:
user.profile.debit -= consumption.amount
2019-06-23 15:11:58 +00:00
else:
user.profile.direct_debit -= consumption.amount
2019-06-12 21:53:01 +00:00
user.profile.alcohol -= Decimal(consumption.quantity * float(consumption.product.deg) * consumption.product.volume * 0.79 /10 /1000)
user.save()
2018-12-13 18:26:58 +00:00
consumptionT = Consumption.objects.get(customer=user, product=consumption.product)
consumptionT.quantity -= consumption.quantity
consumptionT.save()
2018-11-30 18:54:12 +00:00
consumption.delete()
messages.success(request, "La consommation a bien été annulée")
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-30 18:54:12 +00:00
@login_required
@permission_required('gestion.delete_menuhistory')
def cancel_menu(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Delete a :class:`menu history <gestion.models.MenuHistory>`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the menu history to delete.
2018-12-02 15:28:40 +00:00
"""
2018-11-30 18:54:12 +00:00
menu_history = get_object_or_404(MenuHistory, pk=pk)
user = menu_history.customer
2018-12-18 10:38:20 +00:00
if menu_history.paymentMethod.affect_balance:
user.profile.debit -= menu_history.amount
2019-06-23 15:11:58 +00:00
else:
user.profile.direct_debit -= menu_history.amount
2018-12-13 18:26:58 +00:00
for product in manu_history.menu.articles:
consumptionT = Consumption.objects.get(customer=user, product=product)
consumptionT -= menu_history.quantity
2019-01-05 23:01:30 +00:00
consumptionT.save()
2019-06-12 21:53:01 +00:00
user.profile.alcohol -= Decimal(menu_history.quantity * float(menu_history.product.deg) * menu_history.product.volume * 0.79 /10 /1000)
2019-06-23 15:11:58 +00:00
user.save()
2018-11-30 18:54:12 +00:00
menu_history.delete()
messages.success(request, "La consommation du menu a bien été annulée")
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
2018-11-22 21:52:15 +00:00
########## Products ##########
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@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')
2018-10-05 22:03:02 +00:00
def productsIndex(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays the products manage static page.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
return render(request, "gestion/products_index.html")
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_product')
2018-10-05 22:03:02 +00:00
def addProduct(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.ProductForm` to add a product.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
form = ProductForm(request.POST or None)
if(form.is_valid()):
product = form.save()
2018-10-05 22:03:02 +00:00
messages.success(request, "Le produit a bien été ajouté")
return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk}))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter", "form_button_icon": "plus-square"})
2018-10-05 22:03:02 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 23:15:09 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.change_product')
2018-11-25 23:15:09 +00:00
def editProduct(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.ProductForm` to edit a product.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the the :class:`gestion.models.Product` to edit.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 23:15:09 +00:00
product = get_object_or_404(Product, pk=pk)
form = ProductForm(request.POST or None, instance=product)
if(form.is_valid()):
form.save()
messages.success(request, "Le produit a bien été modifié")
return redirect(reverse('gestion:productProfile', kwargs={'pk':product.pk}))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Modification d'un produit", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
2018-11-25 23:15:09 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.view_product')
2018-10-05 22:03:02 +00:00
def productsList(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Display the list of :class:`products <gestion.models.Product>`.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
products = Product.objects.all()
return render(request, "gestion/products_list.html", {"products": products})
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.view_product')
def searchProduct(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.SearchProduct` to search a :class:`gestion.models.Product`.
2018-12-02 15:28:40 +00:00
"""
2018-11-22 21:52:15 +00:00
form = SearchProductForm(request.POST or None)
if(form.is_valid()):
return redirect(reverse('gestion:productProfile', kwargs={'pk': form.cleaned_data['product'].pk }))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title":"Rechercher un produit", "form_button": "Rechercher", "form_button_icon": "search"})
2018-11-22 21:52:15 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.view_product')
def productProfile(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays the profile of a :class:`gestion.models.Product`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Product` to display profile.
2018-12-02 15:28:40 +00:00
"""
2018-11-22 21:52:15 +00:00
product = get_object_or_404(Product, pk=pk)
return render(request, "gestion/product_profile.html", {"product": product})
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
2018-12-23 22:55:27 +00:00
def getProduct(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-06-23 14:43:23 +00:00
Get a :class:`gestion.models.Product` by pk and return it in JSON format.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Product` to get infos.
2018-12-02 15:28:40 +00:00
"""
2018-12-23 22:55:27 +00:00
product = Product.objects.get(pk=pk)
2019-05-06 07:40:40 +00:00
if product.category == Product.DRAFT_PINTE:
nb_pintes = 1
else:
nb_pintes = 0
2019-06-23 14:43:23 +00:00
data = json.dumps({"pk": product.pk, "name": product.name, "amount": product.amount, "needQuantityButton": product.needQuantityButton, "nb_pintes": nb_pintes})
2018-10-05 22:03:02 +00:00
return HttpResponse(data, content_type='application/json')
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 23:15:09 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.change_product')
2018-11-25 23:15:09 +00:00
def switch_activate(request, pk):
"""
2019-02-28 12:18:41 +00:00
Switch the active status of the requested :class:`gestion.models.Product`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Product` to display profile.
2018-11-25 23:15:09 +00:00
"""
product = get_object_or_404(Product, pk=pk)
product.is_active = 1 - product.is_active
product.save()
messages.success(request, "La disponibilité du produit a bien été changée")
return redirect(reverse('gestion:productProfile', kwargs={'pk': product.pk}))
2018-11-25 23:15:09 +00:00
2018-11-22 21:52:15 +00:00
class ProductsAutocomplete(autocomplete.Select2QuerySetView):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Autocomplete view for all :class:`products <gestion.models.Product>`.
2018-12-02 15:28:40 +00:00
"""
2018-11-22 21:52:15 +00:00
def get_queryset(self):
qs = Product.objects.all()
if self.q:
2019-01-23 11:31:33 +00:00
qs = qs.filter(name__icontains=self.q)
2018-11-22 21:52:15 +00:00
return qs
2018-10-05 22:03:02 +00:00
2018-12-23 22:55:27 +00:00
class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
"""
2019-02-28 12:18:41 +00:00
Autocomplete view for active :class:`products <gestion.models.Product>`.
2018-12-23 22:55:27 +00:00
"""
def get_queryset(self):
qs = Product.objects.filter(is_active=True)
if self.q:
2019-01-23 11:31:33 +00:00
qs = qs.filter(name__icontains=self.q)
2018-12-23 22:55:27 +00:00
return qs
2018-10-05 22:03:02 +00:00
########## Kegs ##########
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_keg')
2018-10-05 22:03:02 +00:00
def addKeg(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.KegForm` to add a :class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
form = KegForm(request.POST or None)
if form.is_valid():
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:]
create_galopin = form.cleaned_data["create_galopin"]
pinte = Product(
name = "Pinte " + name,
amount = pinte_price,
stockHold = 0,
stockBar = 0,
category = form.cleaned_data["category"],
needQuantityButton = False,
is_active = True,
volume = 50,
deg = form.cleaned_data["deg"],
adherentRequired = True,
showingMultiplier = 1,
draft_category = Product.DRAFT_PINTE
)
pinte.save()
keg.pinte = pinte
demi = Product(
name = "Demi " + name,
amount = ceil(5*pinte_price)/10,
stockHold = 0,
stockBar = 0,
category = form.cleaned_data["category"],
needQuantityButton = False,
is_active = True,
volume = 25,
deg = form.cleaned_data["deg"],
adherentRequired = True,
showingMultiplier = 1,
draft_category = Product.DRAFT_DEMI
)
demi.save()
keg.demi = demi
if create_galopin:
galopin = Product(
name = "Galopin " + name,
amount = ceil(2.5 * pinte_price)/10,
stockHold = 0,
stockBar = 0,
category = form.cleaned_data["category"],
needQuantityButton = False,
is_active = True,
volume = 13,
deg = form.cleaned_data["deg"],
adherentRequired = True,
showingMultiplier = 1,
draft_category = Product.DRAFT_DEMI
)
galopin.save()
keg.galopin = galopin
2018-10-05 22:03:02 +00:00
keg = form.save()
messages.success(request, "Le fût " + keg.name + " a bien été ajouté")
2018-11-25 12:52:32 +00:00
return redirect(reverse('gestion:kegsList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un fût", "form_button": "Ajouter", "form_button_icon": "plus-square"})
2018-10-05 22:03:02 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.change_keg')
2018-11-25 12:52:32 +00:00
def editKeg(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.KegForm` to edit a :class:`gestion.models.Keg`.
2019-01-05 23:01:30 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Keg` to edit.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
keg = get_object_or_404(Keg, pk=pk)
form = KegForm(request.POST or None, instance=keg)
if(form.is_valid()):
form.save()
messages.success(request, "Le fût a bien été modifié")
return redirect(reverse('gestion:kegsList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Modification d'un fût", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
2018-11-25 12:52:32 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
@permission_required('gestion.open_keg')
def openKeg(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.SelectPositiveKegForm` to open a :class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
form = SelectPositiveKegForm(request.POST or None)
if(form.is_valid()):
keg = form.cleaned_data['keg']
previousKegHistory = KegHistory.objects.filter(keg=keg).filter(isCurrentKegHistory=True)
for pkh in previousKegHistory:
pkh.isCurrentKegHistory = False
pkh.closingDate = timezone.now()
pkh.save()
kegHistory = KegHistory(keg = keg)
kegHistory.save()
keg.stockHold -= 1
keg.is_active = True
keg.save()
messages.success(request, "Le fut a bien été percuté")
return redirect(reverse('gestion:kegsList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title":"Percutage d'un fût", "form_button":"Percuter", "form_button_icon": "fill-drip"})
2018-11-25 12:52:32 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
@permission_required('gestion.open_keg')
def openDirectKeg(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Opens a class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the class:`gestion.models.Keg` to open.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
keg = get_object_or_404(Keg, pk=pk)
if(keg.stockHold > 0):
previousKegHistory = KegHistory.objects.filter(keg=keg).filter(isCurrentKegHistory=True)
for pkh in previousKegHistory:
pkh.isCurrentKegHistory = False
pkh.closingDate = timezone.now()
pkh.save()
kegHistory = KegHistory(keg = keg)
kegHistory.save()
keg.stockHold -= 1
keg.is_active = True
keg.save()
messages.success(request, "Le fût a bien été percuté")
else:
messages.error(request, "Il n'y a pas de fût en stock")
return redirect(reverse('gestion:kegsList'))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
@permission_required('gestion.close_keg')
def closeKeg(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.SelectPositiveKegForm` to open a :class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
form = SelectActiveKegForm(request.POST or None)
if(form.is_valid()):
keg = form.cleaned_data['keg']
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.isCurrentKegHistory = False
kegHistory.closingDate = timezone.now()
kegHistory.save()
keg.is_active = False
keg.save()
messages.success(request, "Le fût a bien été fermé")
return redirect(reverse('gestion:kegsList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title":"Fermeture d'un fût", "form_button":"Fermer le fût", "form_button_icon": "fill"})
2018-11-25 12:52:32 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.close_keg')
2018-11-25 12:52:32 +00:00
def closeDirectKeg(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Closes a class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the class:`gestion.models.Keg` to open.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
keg = get_object_or_404(Keg, pk=pk)
2018-12-02 15:28:40 +00:00
if keg.is_active:
2018-11-25 12:52:32 +00:00
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.isCurrentKegHistory = False
kegHistory.closingDate = timezone.now()
kegHistory.save()
keg.is_active = False
keg.save()
messages.success(request, "Le fût a bien été fermé")
else:
messages.error(request, "Le fût n'est pas ouvert")
return redirect(reverse('gestion:kegsList'))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
@permission_required('gestion.view_keg')
def kegsList(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Display the list of :class:`kegs <gestion.models.Keg>`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
kegs_active = KegHistory.objects.filter(isCurrentKegHistory=True)
2019-01-24 21:26:38 +00:00
ids_actives = kegs_active.values('keg__id')
2018-11-25 12:52:32 +00:00
kegs_inactive = Keg.objects.exclude(id__in = ids_actives)
return render(request, "gestion/kegs_list.html", {"kegs_active": kegs_active, "kegs_inactive": kegs_inactive})
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 12:52:32 +00:00
@login_required
@permission_required('gestion.view_keghistory')
def kegH(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Display the :class:`history <gestion.models.KegHistory>` of requested :class:`gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
keg = get_object_or_404(Keg, pk=pk)
kegHistory = KegHistory.objects.filter(keg=keg).order_by('-openingDate')
return render(request, "gestion/kegh.html", {"keg": keg, "kegHistory": kegHistory})
class KegActiveAutocomplete(autocomplete.Select2QuerySetView):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Autocomplete view for active :class:`kegs <gestion.models.Keg>`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
def get_queryset(self):
qs = Keg.objects.filter(is_active = True)
if self.q:
2019-01-23 11:31:33 +00:00
qs = qs.filter(name__icontains=self.q)
2018-11-25 12:52:32 +00:00
return qs
class KegPositiveAutocomplete(autocomplete.Select2QuerySetView):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Autocomplete view for :class:`kegs <gestion.models.Keg>` with positive stockHold.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
def get_queryset(self):
qs = Keg.objects.filter(stockHold__gt = 0)
if self.q:
2019-01-23 11:31:33 +00:00
qs = qs.filter(name__icontains=self.q)
2018-11-25 12:52:32 +00:00
return qs
2018-10-05 22:03:02 +00:00
########## Menus ##########
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.add_menu')
2018-10-05 22:03:02 +00:00
def addMenu(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Display a :class:`gestion.forms.MenuForm` to add a :class:`gestion.models.Menu`.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
form = MenuForm(request.POST or None)
extra_css = "#id_articles{height:200px;}"
if(form.is_valid()):
menu = form.save()
messages.success(request, "Le menu " + menu.name + " a bien été ajouté")
2018-11-25 23:15:09 +00:00
return redirect(reverse('gestion:menusList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un menu", "form_button": "Ajouter", "form_button_icon": "plus-square", "extra_css": extra_css})
2018-10-05 22:03:02 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 23:15:09 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.change_menu')
2018-11-25 23:15:09 +00:00
def edit_menu(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.MenuForm` to edit a :class:`gestion.models.Menu`.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Menu` to edit.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 23:15:09 +00:00
menu = get_object_or_404(Menu, pk=pk)
form = MenuForm(request.POST or None, instance=menu)
extra_css = "#id_articles{height:200px;}"
if form.is_valid():
form.save()
messages.success(request, "Le menu a bien été modifié")
return redirect(reverse('gestion:menusList'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Modification d'un menu", "form_button": "Modifier", "form_button_icon": "pencil-alt", "extra_css": extra_css})
2018-11-22 21:52:15 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
@permission_required('gestion.view_menu')
def searchMenu(request):
"""
2019-02-28 12:18:41 +00:00
Displays a :class:`gestion.forms.SearchMenuForm` to search a :class:`gestion.models.Menu`.
2018-11-22 21:52:15 +00:00
"""
form = SearchMenuForm(request.POST or None)
if(form.is_valid()):
2018-11-25 23:15:09 +00:00
menu = form.cleaned_data['menu']
return redirect(reverse('gestion:editMenu', kwargs={'pk':menu.pk}))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Recherche d'un menu", "form_button": "Modifier", "form_button_icon": "search"})
2018-11-22 21:52:15 +00:00
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 23:15:09 +00:00
@login_required
@permission_required('gestion.view_menu')
def menus_list(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Display the list of :class:`menus <gestion.models.Menu>`.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 23:15:09 +00:00
menus = Menu.objects.all()
return render(request, "gestion/menus_list.html", {"menus": menus})
2018-12-02 15:28:40 +00:00
@active_required
2018-11-25 23:15:09 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.change_menu')
2018-11-25 23:15:09 +00:00
def switch_activate_menu(request, pk):
"""
2019-02-28 12:18:41 +00:00
Switch active status of a :class:`gestion.models.Menu`.
2018-11-25 23:15:09 +00:00
"""
menu = get_object_or_404(Menu, pk=pk)
menu.is_active = 1 - menu.is_active
menu.save()
messages.success(request, "La disponibilité du menu a bien été changée")
return redirect(reverse('gestion:menusList'))
2018-12-02 15:28:40 +00:00
@active_required
2018-11-27 08:07:12 +00:00
@login_required
2018-12-02 15:28:40 +00:00
@permission_required('gestion.view_menu')
2018-12-23 22:55:27 +00:00
def get_menu(request, pk):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Get a :class:`gestion.models.Menu` by pk and return it in JSON format.
2018-12-02 15:28:40 +00:00
2019-02-28 12:18:41 +00:00
pk
The primary key of the :class:`gestion.models.Menu`.
2018-12-02 15:28:40 +00:00
"""
2018-12-23 22:55:27 +00:00
menu = get_object_or_404(Menu, pk=pk)
nb_pintes = 0
for article in menu.articles:
2019-05-06 07:40:40 +00:00
if article.category == Product.DRAFT_PINTE:
nb_pintes +=1
2019-06-23 14:43:23 +00:00
data = json.dumps({"pk": menu.pk, "name": menu.name, "amount" : menu.amount, "needQuantityButton": False, "nb_pintes": nb_pintes})
2018-11-27 08:07:12 +00:00
return HttpResponse(data, content_type='application/json')
2018-11-22 21:52:15 +00:00
class MenusAutocomplete(autocomplete.Select2QuerySetView):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Autocomplete view for active :class:`menus <gestion.models.Menu>`.
2018-12-02 15:28:40 +00:00
"""
2018-11-22 21:52:15 +00:00
def get_queryset(self):
qs = Menu.objects.all()
if self.q:
2019-01-23 11:31:33 +00:00
qs = qs.filter(name__icontains=self.q)
2018-11-22 21:52:15 +00:00
return qs
2018-12-02 15:28:40 +00:00
2018-11-22 21:52:15 +00:00
########## Ranking ##########
2018-12-02 15:28:40 +00:00
@active_required
2018-11-22 21:52:15 +00:00
@login_required
def ranking(request):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Displays the ranking page.
2018-12-02 15:28:40 +00:00
"""
2018-11-22 21:52:15 +00:00
bestBuyers = User.objects.order_by('-profile__debit')[:25]
2019-06-10 23:28:22 +00:00
bestDrinkers = User.objects.order_by('-profile__alcohol')[:25]
2019-01-18 14:38:48 +00:00
form = SearchProductForm(request.POST or None)
if(form.is_valid()):
product_ranking = form.cleaned_data['product'].ranking
else:
product_ranking = None
return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers, "product_ranking": product_ranking, "form": form})
########## Pinte monitoring ##########
def allocate(pinte_pk, user):
"""
2019-02-28 12:18:41 +00:00
Allocate a :class:`gestion.models.Pinte` to a user (:class:`django.contrib.auth.models.User`) or release the pinte if user is None
"""
try:
pinte = Pinte.objects.get(pk=pinte_pk)
if pinte.current_owner is not None:
pinte.previous_owner = pinte.current_owner
pinte.current_owner = user
pinte.save()
return True
except Pinte.DoesNotExist:
2018-12-23 11:54:37 +00:00
return False
2018-12-23 13:36:29 +00:00
@active_required
@login_required
@permission_required('gestion.change_pinte')
def release(request, pinte_pk):
"""
2019-02-28 12:18:41 +00:00
View to release a :class:`gestion.models.Pinte`.
pinte_pk
The primary key of the :class:`gestion.models.Pinte` to release.
2018-12-23 13:36:29 +00:00
"""
if allocate(pinte_pk, None):
messages.success(request, "La pinte a bien été libérée")
else:
messages.error(request, "Impossible de libérer la pinte")
return redirect(reverse('gestion:pintesList'))
2019-01-05 23:01:30 +00:00
2018-12-23 11:54:37 +00:00
@active_required
@login_required
@permission_required('gestion.add_pinte')
2018-12-23 13:36:29 +00:00
def add_pintes(request):
2019-02-28 12:18:41 +00:00
"""
Displays a :class:`gestion.forms.PinteForm` to add one or more :class:`gestion.models.Pinte`.
"""
2018-12-23 12:05:41 +00:00
form = PinteForm(request.POST or None)
2018-12-23 11:54:37 +00:00
if form.is_valid():
ids = form.cleaned_data['ids']
if ids != "":
ids = ids.split(" ")
else:
ids = range(form.cleaned_data['begin'], form.cleaned_data['end'] + 1)
i = 0
for id in ids:
if not Pinte.objects.filter(pk=id).exists():
new_pinte = Pinte(pk=int(id))
new_pinte.save()
i += 1
messages.success(request, str(i) + " pinte(s) a(ont) été ajoutée(s)")
return redirect(reverse('gestion:productsIndex'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Ajouter des pintes", "form_button": "Ajouter", "form_button_icon": "plus-square"})
2018-12-23 12:05:41 +00:00
@active_required
@login_required
@permission_required('gestion.change_pinte')
def release_pintes(request):
2019-02-28 12:18:41 +00:00
"""
Displays a :class:`gestion.forms.PinteForm` to release one or more :class:`gestion.models.Pinte`.
"""
2018-12-23 12:05:41 +00:00
form = PinteForm(request.POST or None)
if form.is_valid():
ids = form.cleaned_data['ids']
if ids != "":
ids = ids.split(" ")
else:
ids = range(form.cleaned_data['begin'], form.cleaned_data['end'] + 1)
i = 0
for id in ids:
if allocate(id, None):
i += 1
messages.success(request, str(i) + " pinte(s) a(ont) été libérée(s)")
return redirect(reverse('gestion:productsIndex'))
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Libérer des pintes", "form_button": "Libérer", "form_button_icon": "glass-whiskey"})
2018-12-23 13:36:29 +00:00
@active_required
@login_required
@permission_required('gestion.view_pinte')
def pintes_list(request):
2019-02-28 12:18:41 +00:00
"""
Displays the list of :class:`gestion.models.Pinte`
"""
2018-12-23 13:36:29 +00:00
free_pintes = Pinte.objects.filter(current_owner=None)
taken_pintes = Pinte.objects.exclude(current_owner=None)
2018-12-23 20:21:30 +00:00
return render(request, "gestion/pintes_list.html", {"free_pintes": free_pintes, "taken_pintes": taken_pintes})
@active_required
@login_required
@permission_required('auth.view_user')
def pintes_user_list(request):
2019-02-28 12:18:41 +00:00
"""
Displays the list of user, who have unreturned :class:`Pinte(s) <gestion.models.Pinte>`.
"""
2018-12-23 20:21:30 +00:00
pks = [x.pk for x in User.objects.all() if x.profile.nb_pintes > 0]
users = User.objects.filter(pk__in=pks)
2019-01-05 23:01:30 +00:00
return render(request, "gestion/pintes_user_list.html", {"users": users})
2019-06-23 11:46:12 +00:00
@active_required
@login_required
@permission_required('users.can_generate_invoices')
def gen_invoice(request):
"""
Displays a form to generate an invoice.
"""
form = GenerateInvoiceForm(request.POST or None)
if form.is_valid():
products = [x.split(";") for x in form.cleaned_data["products"].split("\n")]
total = 0
for product in products:
sub_total = Decimal(product[1]) * Decimal(product[2])
product.append(sub_total)
total += sub_total
return render_to_pdf(
request,
'gestion/invoice.tex',
{
"invoice_date": form.cleaned_data["invoice_date"],
"invoice_number": form.cleaned_data["invoice_number"],
"invoice_place": form.cleaned_data["invoice_place"],
"invoice_object": form.cleaned_data["invoice_object"],
"invoice_description": form.cleaned_data["invoice_description"],
"client_name": form.cleaned_data["client_name"],
"client_address_first_line": form.cleaned_data["client_address_fisrt_line"],
"client_address_second_line": form.cleaned_data["client_address_second_line"],
"products" : products,
"total": total,
"path" : os.path.join(settings.BASE_DIR, "templates/coope.png"),
},
filename="FE" + form.cleaned_data["invoice_number"] + ".pdf")
else:
return render(request, "form.html", {"form": form, "form_title": "Génération d'une facture", "form_button": "Générer", "form_button_icon": "file-pdf"})
2019-01-05 23:01:30 +00:00
@active_required
@login_required
@admin_required
def gen_releve(request):
2019-02-28 12:18:41 +00:00
"""
Displays a :class:`forms.gestion.GenerateReleveForm` to generate a releve.
"""
2019-01-05 23:01:30 +00:00
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
2019-01-22 19:27:18 +00:00
now = datetime.now()
2019-01-05 23:01:30 +00:00
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:
2019-01-17 22:16:43 +00:00
return render(request, "form.html", {"form": form, "form_title": "Génération d'un relevé", "form_button": "Générer", "form_button_icon": "file-pdf"})
2019-05-03 19:09:32 +00:00
2019-06-23 08:54:21 +00:00
@active_required
@login_required
@permission_required('preferences.can_divide')
def divide(request):
"""
Divide all non-divided cotisation
"""
if request.POST:
non_divided_cotisations = CotisationHistory.objects.filter(divided=False)
for cotisation_history in non_divided_cotisations:
cotisation_history.divided = True
cotisation_history.save()
divide_history = DivideHistory(
total_cotisations = non_divided_cotisations.count(),
total_cotisations_amount = sum([x.amount for x in non_divided_cotisations]),
total_ptm_amount = sum([x.amount_ptm for x in non_divided_cotisations]),
coopeman = request.user
)
divide_history.save()
non_divided_cotisations = CotisationHistory.objects.filter(divided=False)
total_amount = sum([x.amount for x in non_divided_cotisations])
total_amount_ptm = sum([x.amount_ptm for x in non_divided_cotisations])
divide_histories = DivideHistory.objects.all().order_by('-date')
return render(
request,
"gestion/divide.html",
{
"total_cotisations": non_divided_cotisations.count(),
"total_amount": total_amount,
"total_amount_ptm": total_amount_ptm,
"divide_histories": divide_histories,
}
)
2019-05-03 19:09:32 +00:00
########## categories ##########
@active_required
@login_required
@permission_required('gestion.add_category')
def addCategory(request):
"""
Displays a :class:`gestion.forms.CategoryForm` to add a category.
"""
form = CategoryForm(request.POST or None)
if(form.is_valid()):
category = form.save()
messages.success(request, "La catégorie a bien été ajoutée")
return redirect(reverse('gestion:categoryProfile', kwargs={'pk':category.pk}))
return render(request, "form.html", {"form": form, "form_title": "Ajout d'une catégorie", "form_button": "Ajouter", "form_button_icon": "plus-square"})
@active_required
@login_required
@permission_required('gestion.change_category')
def editCategory(request, pk):
"""
Displays a :class:`gestion.forms.CategoryForm` to edit a category.
pk
The primary key of the the :class:`gestion.models.Category` to edit.
"""
category = get_object_or_404(Category, pk=pk)
form = CategoryForm(request.POST or None, instance=category)
if(form.is_valid()):
form.save()
messages.success(request, "La catégorie a bien été modifiée")
return redirect(reverse('gestion:categoryProfile', kwargs={'pk': category.pk}))
return render(request, "form.html", {"form": form, "form_title": "Modification d'une catégorie", "form_button": "Modifier", "form_button_icon": "pencil-alt"})
@active_required
@login_required
@permission_required('gestion.view_category')
def categoriesList(request):
"""
Display the list of :class:`categories <gestion.models.Category>`.
"""
categories = Category.objects.all().order_by('order')
return render(request, "gestion/categories_list.html", {"categories": categories})
@active_required
@login_required
@permission_required('gestion.view_category')
def searchCategory(request):
"""
Displays a :class:`gestion.forms.SearchCategory` to search a :class:`gestion.models.Category`.
"""
form = SearchCategoryForm(request.POST or None)
if(form.is_valid()):
return redirect(reverse('gestion:categoryProfile', kwargs={'pk': form.cleaned_data['category'].pk }))
return render(request, "form.html", {"form": form, "form_title":"Rechercher une catégorie", "form_button": "Rechercher", "form_button_icon": "search"})
@active_required
@login_required
@permission_required('gestion.view_category')
def categoryProfile(request, pk):
"""
Displays the profile of a :class:`gestion.models.Category`.
pk
The primary key of the :class:`gestion.models.Category` to display profile.
"""
category = get_object_or_404(Category, pk=pk)
return render(request, "gestion/category_profile.html", {"category": category})
class CategoriesAutocomplete(autocomplete.Select2QuerySetView):
"""
Autocomplete view for active :class:`categories <gestion.models.Category>`.
"""
def get_queryset(self):
qs = Category.objects.all()
if self.q:
qs = qs.filter(name__icontains=self.q)
2019-05-03 21:27:11 +00:00
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,
2019-06-23 13:31:55 +00:00
})
########## Compute price ##########
def compute_price_view(request):
form = ComputePriceForm(request.POST or None)
if form.is_valid():
price_profile = form.cleaned_data["price_profile"]
price = compute_price(form.cleaned_data["price"], price_profile.a, price_profile.b, price_profile.c, price_profile.alpha)
form_p = "Le prix est " + str(ceil(100*price)/100) + " € (arrondi au centième) ou " + str(ceil(10*price)/10) + " € (arrondi au dixième)."
else:
form_p = ""
return render(request, "form.html", {"form": form, "form_title": "Calcul d'un prix", "form_button": "Calculer", "form_icon": "search_dollar", "form_p": form_p})