2016-08-04 05:21:04 +02:00
|
|
|
from django.shortcuts import render, get_object_or_404, redirect
|
2016-08-07 17:02:01 +02:00
|
|
|
from django.core.exceptions import PermissionDenied, ValidationError
|
2016-08-04 05:21:04 +02:00
|
|
|
from django.views.generic import ListView, DetailView
|
|
|
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
|
|
|
from django.core.urlresolvers import reverse_lazy
|
|
|
|
from django.contrib import messages
|
|
|
|
from django.contrib.messages.views import SuccessMessageMixin
|
2016-08-02 10:40:46 +02:00
|
|
|
from django.contrib.auth.decorators import login_required, permission_required
|
2016-08-07 23:41:46 +02:00
|
|
|
from django.contrib.auth.models import User, Permission
|
2016-08-06 22:19:52 +02:00
|
|
|
from django.http import HttpResponse, JsonResponse, Http404
|
|
|
|
from django.forms import modelformset_factory
|
2016-08-08 00:24:46 +02:00
|
|
|
from django.db import IntegrityError, transaction
|
2016-08-09 11:02:26 +02:00
|
|
|
from django.db.models import F
|
2016-08-08 07:44:05 +02:00
|
|
|
from django.utils import timezone
|
2016-08-02 10:40:46 +02:00
|
|
|
from gestioncof.models import CofProfile, Clipper
|
2016-08-08 07:44:05 +02:00
|
|
|
from kfet.models import Account, Checkout, Article, Settings, AccountNegative
|
2016-08-03 04:38:54 +02:00
|
|
|
from kfet.forms import *
|
2016-08-06 22:19:52 +02:00
|
|
|
from collections import defaultdict
|
2016-08-02 10:40:46 +02:00
|
|
|
|
|
|
|
@login_required
|
|
|
|
def home(request):
|
|
|
|
return render(request, "kfet/base.html")
|
|
|
|
|
|
|
|
def put_cleaned_data_in_dict(dict, form):
|
|
|
|
for field in form.cleaned_data:
|
|
|
|
dict[field] = form.cleaned_data[field]
|
|
|
|
|
2016-08-04 05:21:04 +02:00
|
|
|
# -----
|
|
|
|
# Account views
|
|
|
|
# -----
|
|
|
|
|
|
|
|
# Account - General
|
|
|
|
|
2016-08-02 10:40:46 +02:00
|
|
|
@login_required
|
2016-08-08 12:46:43 +02:00
|
|
|
@permission_required('kfet.is_team')
|
2016-08-03 04:38:54 +02:00
|
|
|
def account(request):
|
2016-08-04 05:21:04 +02:00
|
|
|
accounts = Account.objects.order_by('trigramme')
|
2016-08-03 04:38:54 +02:00
|
|
|
return render(request, "kfet/account.html", { 'accounts' : accounts })
|
|
|
|
|
2016-08-04 05:21:04 +02:00
|
|
|
@login_required
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def account_is_validandfree_ajax(request):
|
|
|
|
if not request.GET.get("trigramme"):
|
|
|
|
raise Http404
|
|
|
|
trigramme = request.GET.get("trigramme")
|
|
|
|
data = Account.is_validandfree(trigramme)
|
2016-08-06 22:19:52 +02:00
|
|
|
return JsonResponse(data)
|
2016-08-04 05:21:04 +02:00
|
|
|
|
|
|
|
# Account - Create
|
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
@login_required
|
2016-08-08 12:46:43 +02:00
|
|
|
@permission_required('kfet.is_team')
|
2016-08-03 04:38:54 +02:00
|
|
|
def account_create(request):
|
|
|
|
|
2016-08-02 10:40:46 +02:00
|
|
|
# A envoyer au template
|
|
|
|
data_template = {
|
2016-08-03 04:38:54 +02:00
|
|
|
'account_trigramme_form': AccountTriForm(),
|
2016-08-04 05:21:04 +02:00
|
|
|
'errors' : {},
|
2016-08-02 10:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Enregistrement
|
|
|
|
if request.method == "POST":
|
|
|
|
# Pour indiquer la tentative d'enregistrement au template
|
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
# Checking permission
|
|
|
|
if not request.user.has_perm('kfet.add_account'):
|
|
|
|
raise PermissionDenied
|
|
|
|
|
2016-08-02 10:40:46 +02:00
|
|
|
# Peuplement des forms
|
|
|
|
username = request.POST.get('username')
|
|
|
|
try:
|
2016-08-03 04:38:54 +02:00
|
|
|
user = User.objects.get(username=username)
|
2016-08-02 10:40:46 +02:00
|
|
|
(cof, _) = CofProfile.objects.get_or_create(user=user)
|
2016-08-03 04:38:54 +02:00
|
|
|
user_form = UserForm(request.POST, instance=user)
|
|
|
|
cof_form = CofForm(request.POST, instance=cof)
|
2016-08-02 10:40:46 +02:00
|
|
|
except User.DoesNotExist:
|
|
|
|
user_form = UserForm(request.POST)
|
|
|
|
cof_form = CofForm(request.POST)
|
2016-08-03 04:38:54 +02:00
|
|
|
trigramme_form = AccountTriForm(request.POST)
|
|
|
|
account_form = AccountNoTriForm(request.POST)
|
|
|
|
|
2016-08-02 10:40:46 +02:00
|
|
|
# Ajout des erreurs pour le template
|
|
|
|
data_template['errors']['user_form'] = user_form.errors
|
|
|
|
data_template['errors']['cof_form'] = cof_form.errors
|
|
|
|
data_template['errors']['trigramme_form'] = trigramme_form.errors
|
|
|
|
data_template['errors']['account_form'] = account_form.errors
|
|
|
|
|
|
|
|
if all((user_form.is_valid(), cof_form.is_valid(),
|
|
|
|
trigramme_form.is_valid(), account_form.is_valid())):
|
|
|
|
data = {}
|
2016-08-03 04:38:54 +02:00
|
|
|
# Fill data for Account.save()
|
2016-08-02 10:40:46 +02:00
|
|
|
put_cleaned_data_in_dict(data, user_form)
|
|
|
|
put_cleaned_data_in_dict(data, cof_form)
|
|
|
|
|
|
|
|
try:
|
2016-08-03 04:38:54 +02:00
|
|
|
account = trigramme_form.save(data = data)
|
|
|
|
account_form = AccountNoTriForm(request.POST, instance=account)
|
|
|
|
account_form.save()
|
2016-08-04 05:21:04 +02:00
|
|
|
messages.success(request, 'Compte créé : %s' % account.trigramme)
|
2016-08-02 10:40:46 +02:00
|
|
|
except Account.UserHasAccount as e:
|
2016-08-04 05:21:04 +02:00
|
|
|
messages.error(request, \
|
|
|
|
"Cet utilisateur a déjà un compte K-Fêt : %s" % e.trigramme)
|
2016-08-02 10:40:46 +02:00
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
return render(request, "kfet/account_create.html", data_template)
|
2016-08-02 10:40:46 +02:00
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
def account_form_set_readonly_fields(user_form, cof_form):
|
2016-08-02 10:40:46 +02:00
|
|
|
user_form.fields['username'].widget.attrs['readonly'] = True
|
|
|
|
cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
|
|
|
cof_form.fields['is_cof'].widget.attrs['disabled'] = True
|
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
@login_required
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def account_create_ajax(request, username=None, login_clipper=None):
|
2016-08-02 10:40:46 +02:00
|
|
|
user = None
|
|
|
|
if login_clipper:
|
|
|
|
# à partir d'un clipper
|
|
|
|
# le user associé à ce clipper ne devrait pas encore existé
|
|
|
|
clipper = get_object_or_404(Clipper, username = login_clipper)
|
|
|
|
try:
|
|
|
|
# Vérification que clipper ne soit pas déjà dans User
|
2016-08-03 04:38:54 +02:00
|
|
|
user = User.objects.get(username=login_clipper)
|
2016-08-02 10:40:46 +02:00
|
|
|
# Ici, on nous a menti, le user existe déjà
|
|
|
|
username = user.username
|
|
|
|
login_clipper = None
|
|
|
|
except User.DoesNotExist:
|
|
|
|
# Clipper (sans user déjà existant)
|
|
|
|
|
|
|
|
# UserForm - Prefill + Création
|
|
|
|
user_initial_data = {
|
|
|
|
'username' : login_clipper,
|
|
|
|
'email' : login_clipper + "@clipper.ens.fr"}
|
|
|
|
if clipper.fullname:
|
|
|
|
# Prefill du nom et prénom
|
|
|
|
names = clipper.fullname.split()
|
|
|
|
# Le premier, c'est le prénom
|
|
|
|
user_initial_data['first_name'] = names[0]
|
|
|
|
if len(names) > 1:
|
|
|
|
# Si d'autres noms -> tous dans le nom de famille
|
|
|
|
user_initial_data['last_name'] = " ".join(names[1:])
|
|
|
|
user_form = UserForm(initial = user_initial_data)
|
|
|
|
|
|
|
|
# CofForm - Prefill + Création
|
|
|
|
cof_initial_data = { 'login_clipper': login_clipper }
|
|
|
|
cof_form = CofForm(initial = cof_initial_data)
|
|
|
|
|
|
|
|
# AccountForm
|
|
|
|
account_form = AccountForm()
|
|
|
|
|
|
|
|
# Protection (read-only) des champs username et login_clipper
|
2016-08-03 04:38:54 +02:00
|
|
|
account_form_set_readonly_fields(user_form, cof_form)
|
2016-08-02 10:40:46 +02:00
|
|
|
if username:
|
|
|
|
# le user existe déjà
|
|
|
|
user = get_object_or_404(User, username=username)
|
|
|
|
# récupération du profil cof
|
|
|
|
(cof, _) = CofProfile.objects.get_or_create(user=user)
|
|
|
|
# UserForm + CofForm - Création à partir des instances existantes
|
|
|
|
user_form = UserForm(instance = user)
|
|
|
|
cof_form = CofForm(instance = cof)
|
|
|
|
# AccountForm
|
2016-08-03 04:38:54 +02:00
|
|
|
account_form = AccountNoTriForm()
|
2016-08-02 10:40:46 +02:00
|
|
|
# Protection (read-only) des champs username et login_clipper
|
2016-08-03 04:38:54 +02:00
|
|
|
account_form_set_readonly_fields(user_form, cof_form)
|
2016-08-02 10:40:46 +02:00
|
|
|
elif not login_clipper:
|
|
|
|
# connaît pas du tout, faut tout remplir
|
|
|
|
user_form = UserForm()
|
|
|
|
cof_form = CofForm()
|
2016-08-03 04:38:54 +02:00
|
|
|
account_form = AccountNoTriForm()
|
2016-08-02 10:40:46 +02:00
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
return render(request, "kfet/account_create_form.html", {
|
2016-08-02 10:40:46 +02:00
|
|
|
'account_form' : account_form,
|
|
|
|
'cof_form' : cof_form,
|
|
|
|
'user_form' : user_form,
|
|
|
|
})
|
|
|
|
|
2016-08-04 05:21:04 +02:00
|
|
|
# Account - Read
|
2016-08-03 04:38:54 +02:00
|
|
|
|
|
|
|
@login_required
|
|
|
|
def account_read(request, trigramme):
|
|
|
|
try:
|
|
|
|
account = Account.objects.get(trigramme=trigramme)
|
|
|
|
except Account.DoesNotExist:
|
|
|
|
raise Http404
|
|
|
|
|
|
|
|
# Checking permissions
|
|
|
|
if not request.user.has_perm('kfet.is_team') \
|
2016-08-04 05:21:04 +02:00
|
|
|
and request.user != account.user:
|
2016-08-03 04:38:54 +02:00
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
return render(request, "kfet/account_read.html", { 'account' : account })
|
|
|
|
|
2016-08-04 05:21:04 +02:00
|
|
|
# Account - Update
|
|
|
|
|
2016-08-03 04:38:54 +02:00
|
|
|
@login_required
|
|
|
|
def account_update(request, trigramme):
|
|
|
|
try:
|
|
|
|
account = Account.objects.get(trigramme=trigramme)
|
|
|
|
except Account.DoesNotExist:
|
|
|
|
raise Http404
|
|
|
|
|
|
|
|
# Checking permissions
|
2016-08-04 05:21:04 +02:00
|
|
|
if not request.user.has_perm('kfet.is_team') \
|
|
|
|
and request.user != account.user:
|
2016-08-03 04:38:54 +02:00
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
if request.method == "POST":
|
|
|
|
# Update attempt
|
|
|
|
|
2016-08-04 05:21:04 +02:00
|
|
|
# Checking permissions
|
|
|
|
if not request.user.has_perm('kfet.change_account') \
|
|
|
|
and request.user != account.user:
|
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
# Peuplement des forms
|
2016-08-03 04:38:54 +02:00
|
|
|
if request.user.has_perm('kfet.change_account'):
|
|
|
|
account_form = AccountForm(request.POST, instance = account)
|
|
|
|
else:
|
2016-08-03 06:33:27 +02:00
|
|
|
account_form = AccountRestrictForm(request.POST, instance = account)
|
2016-08-03 04:38:54 +02:00
|
|
|
cof_form = CofRestrictForm(request.POST, instance=account.cofprofile)
|
2016-08-04 05:21:04 +02:00
|
|
|
user_form = UserRestrictForm(request.POST, instance=account.user)
|
2016-08-03 04:38:54 +02:00
|
|
|
|
|
|
|
if all((account_form.is_valid(), cof_form.is_valid(), user_form.is_valid())):
|
|
|
|
data = {}
|
|
|
|
# Fill data for Account.save()
|
|
|
|
put_cleaned_data_in_dict(data, user_form)
|
|
|
|
put_cleaned_data_in_dict(data, cof_form)
|
|
|
|
|
|
|
|
# Updating
|
|
|
|
account_form.save(data = data)
|
2016-08-04 05:21:04 +02:00
|
|
|
if request.user == account.user:
|
|
|
|
messages.success(request, \
|
|
|
|
'Vos informations ont été mises à jour')
|
|
|
|
else:
|
|
|
|
messages.success(request, \
|
|
|
|
'Informations du compte %s mises à jour' % account.trigramme)
|
|
|
|
return redirect('kfet.account.read', account.trigramme)
|
|
|
|
else:
|
|
|
|
messages.error(request, \
|
|
|
|
'Informations non mises à jour. Corrigez les erreurs')
|
2016-08-03 04:38:54 +02:00
|
|
|
else:
|
|
|
|
# No update attempt
|
2016-08-04 05:21:04 +02:00
|
|
|
if request.user.has_perm('kfet.is_team'):
|
2016-08-03 04:38:54 +02:00
|
|
|
account_form = AccountForm(instance = account)
|
|
|
|
else:
|
|
|
|
account_form = AccountRestrictForm(instance = account)
|
|
|
|
cof_form = CofRestrictForm(instance = account.cofprofile)
|
2016-08-04 05:21:04 +02:00
|
|
|
user_form = UserRestrictForm(instance = account.user)
|
2016-08-03 04:38:54 +02:00
|
|
|
|
|
|
|
return render(request, "kfet/account_update.html", {
|
|
|
|
'account' : account,
|
|
|
|
'account_form' : account_form,
|
|
|
|
'cof_form' : cof_form,
|
|
|
|
'user_form' : user_form,
|
|
|
|
})
|
2016-08-04 05:21:04 +02:00
|
|
|
|
|
|
|
# -----
|
|
|
|
# Checkout views
|
|
|
|
# -----
|
|
|
|
|
|
|
|
# Checkout - General
|
|
|
|
|
|
|
|
class CheckoutList(ListView):
|
|
|
|
model = Checkout
|
|
|
|
template_name = 'kfet/checkout.html'
|
|
|
|
context_object_name = 'checkouts'
|
|
|
|
|
|
|
|
# Checkout - Create
|
|
|
|
|
|
|
|
class CheckoutCreate(SuccessMessageMixin, CreateView):
|
|
|
|
model = Checkout
|
|
|
|
template_name = 'kfet/checkout_create.html'
|
|
|
|
form_class = CheckoutForm
|
|
|
|
success_message = 'Nouvelle caisse : %(name)s'
|
|
|
|
|
|
|
|
# Surcharge de la validation
|
|
|
|
def form_valid(self, form):
|
|
|
|
# Checking permission
|
|
|
|
if not self.request.user.has_perm('add_checkout'):
|
|
|
|
raise PermissionDenied
|
|
|
|
# Creating
|
|
|
|
form.instance.created_by = self.request.user.profile.account_kfet
|
|
|
|
return super(CheckoutCreate, self).form_valid(form)
|
|
|
|
|
|
|
|
# Checkout - Read
|
|
|
|
|
|
|
|
class CheckoutRead(DetailView):
|
2016-08-04 08:23:34 +02:00
|
|
|
model = Checkout
|
2016-08-04 05:21:04 +02:00
|
|
|
template_name = 'kfet/checkout_read.html'
|
|
|
|
context_object_name = 'checkout'
|
|
|
|
|
|
|
|
# Checkout - Update
|
|
|
|
|
|
|
|
class CheckoutUpdate(SuccessMessageMixin, UpdateView):
|
|
|
|
model = Checkout
|
|
|
|
template_name = 'kfet/checkout_update.html'
|
|
|
|
form_class = CheckoutRestrictForm
|
|
|
|
success_message = 'Informations mises à jour pour la caisse : %(name)s'
|
|
|
|
|
|
|
|
# Surcharge de la validation
|
|
|
|
def form_valid(self, form):
|
|
|
|
# Checking permission
|
|
|
|
if not self.request.user.has_perm('change_checkout'):
|
|
|
|
raise PermissionDenied
|
|
|
|
# Updating
|
|
|
|
return super(CheckoutUpdate, self).form_valid(form)
|
2016-08-04 08:23:34 +02:00
|
|
|
|
|
|
|
# -----
|
|
|
|
# Article views
|
|
|
|
# -----
|
|
|
|
|
|
|
|
# Article - General
|
|
|
|
|
|
|
|
class ArticleList(ListView):
|
|
|
|
model = Article
|
|
|
|
queryset = Article.objects.order_by('category', '-is_sold', 'name')
|
|
|
|
template_name = 'kfet/article.html'
|
|
|
|
context_object_name = 'articles'
|
|
|
|
|
|
|
|
# Article - Create
|
|
|
|
|
|
|
|
class ArticleCreate(SuccessMessageMixin, CreateView):
|
|
|
|
model = Article
|
|
|
|
template_name = 'kfet/article_create.html'
|
|
|
|
form_class = ArticleForm
|
|
|
|
success_message = 'Nouvel item : %(category)s - %(name)s'
|
|
|
|
|
|
|
|
# Surcharge de la validation
|
|
|
|
def form_valid(self, form):
|
|
|
|
# Checking permission
|
|
|
|
if not self.request.user.has_perm('add_article'):
|
|
|
|
raise PermissionDenied
|
|
|
|
# Creating
|
|
|
|
return super(ArticleCreate, self).form_valid(form)
|
|
|
|
|
|
|
|
# Article - Read
|
|
|
|
|
|
|
|
class ArticleRead(DetailView):
|
|
|
|
model = Article
|
|
|
|
template_name = 'kfet/article_read.html'
|
|
|
|
context_object_name = 'article'
|
|
|
|
|
|
|
|
# Article - Update
|
|
|
|
|
|
|
|
class ArticleUpdate(UpdateView):
|
|
|
|
model = Article
|
|
|
|
template_name = 'kfet/article_update.html'
|
|
|
|
form_class = ArticleRestrictForm
|
|
|
|
success_message = "Informations mises à jour pour l'article : %(name)s"
|
|
|
|
|
|
|
|
# Surcharge de la validation
|
|
|
|
def form_valid(self, form):
|
|
|
|
# Checking permission
|
|
|
|
if not self.request.user.has_perm('change_article'):
|
|
|
|
raise PermissionDenied
|
|
|
|
# Updating
|
|
|
|
return super(ArticleUpdate, self).form_valid(form)
|
2016-08-06 22:19:52 +02:00
|
|
|
|
|
|
|
# -----
|
|
|
|
# K-Psul
|
|
|
|
# -----
|
|
|
|
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def kpsul(request):
|
|
|
|
data = {}
|
|
|
|
data['operationgroup_form'] = KPsulOperationGroupForm()
|
|
|
|
data['trigramme_form'] = KPsulAccountForm()
|
|
|
|
data['checkout_form'] = KPsulCheckoutForm()
|
2016-08-06 23:44:58 +02:00
|
|
|
operation_formset = KPsulOperationFormSet(queryset=Operation.objects.none())
|
2016-08-06 22:19:52 +02:00
|
|
|
data['operation_formset'] = operation_formset
|
|
|
|
return render(request, 'kfet/kpsul.html', data)
|
|
|
|
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def kpsul_account_data(request):
|
|
|
|
trigramme = request.POST.get('trigramme', '')
|
|
|
|
account = get_object_or_404(Account, trigramme=trigramme)
|
|
|
|
data = { 'pk': account.pk, 'name': account.name, 'email': account.email,
|
|
|
|
'is_cof': account.is_cof, 'promo': account.promo,
|
|
|
|
'balance': account.balance, 'is_frozen': account.is_frozen,
|
|
|
|
'departement': account.departement, 'nickname': account.nickname }
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def kpsul_checkout_data(request):
|
|
|
|
pk = request.POST.get('pk', 0)
|
|
|
|
checkout = get_object_or_404(Checkout, pk=pk)
|
|
|
|
data = { 'pk': checkout.pk, 'name': checkout.name, 'balance': checkout.balance,
|
|
|
|
'valid_from': checkout.valid_from, 'valid_to': checkout.valid_to }
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
2016-08-09 11:02:26 +02:00
|
|
|
def get_missing_perms(required_perms, user):
|
|
|
|
missing_perms_codenames = [ (perm.split('.'))[1]
|
|
|
|
for perm in required_perms if not user.has_perm(perm)]
|
|
|
|
missing_perms = list(
|
|
|
|
Permission.objects
|
|
|
|
.filter(codename__in=missing_perms_codenames)
|
|
|
|
.values_list('name', flat=True))
|
|
|
|
return missing_perms
|
|
|
|
|
2016-08-06 22:19:52 +02:00
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def kpsul_perform_operations(request):
|
2016-08-07 17:02:01 +02:00
|
|
|
# Initializing response data
|
2016-08-06 22:19:52 +02:00
|
|
|
data = defaultdict(list)
|
|
|
|
|
2016-08-07 17:02:01 +02:00
|
|
|
# Checking operationgroup
|
|
|
|
operationgroup_form = KPsulOperationGroupForm(request.POST)
|
|
|
|
if not operationgroup_form.is_valid():
|
|
|
|
data['errors'].append({'operation_group': list(operationgroup_form.errors)})
|
|
|
|
|
|
|
|
# Checking operation_formset
|
|
|
|
operation_formset = KPsulOperationFormSet(request.POST)
|
|
|
|
if not operation_formset.is_valid():
|
|
|
|
data['errors'].append({'operations': list(operation_formset.errors) })
|
|
|
|
|
2016-08-07 23:41:46 +02:00
|
|
|
# Returning BAD REQUEST if errors
|
2016-08-06 22:19:52 +02:00
|
|
|
if 'errors' in data:
|
|
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
2016-08-07 17:22:39 +02:00
|
|
|
# Pre-saving (no commit)
|
2016-08-07 17:02:01 +02:00
|
|
|
operationgroup = operationgroup_form.save(commit = False)
|
|
|
|
operations = operation_formset.save(commit = False)
|
|
|
|
|
2016-08-08 12:46:43 +02:00
|
|
|
# Specific account's checking
|
|
|
|
if operationgroup.on_acc.is_cash:
|
|
|
|
for operation in operations:
|
|
|
|
if operation.type in [Operation.DEPOSIT, Operation.WITHDRAW]:
|
|
|
|
data['errors'].append(
|
|
|
|
{'account': 'Charge et retrait impossible sur LIQ'})
|
|
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
2016-08-07 18:37:06 +02:00
|
|
|
# Retrieving COF grant
|
|
|
|
cof_grant = Settings.SUBVENTION_COF()
|
2016-08-08 02:50:04 +02:00
|
|
|
# Retrieving addcosts data
|
|
|
|
addcost_amount = Settings.ADDCOST_AMOUNT()
|
|
|
|
addcost_for = Settings.ADDCOST_FOR()
|
2016-08-07 18:37:06 +02:00
|
|
|
|
2016-08-08 02:50:04 +02:00
|
|
|
# Initializing vars
|
2016-08-09 11:02:26 +02:00
|
|
|
required_perms = set()
|
2016-08-08 02:50:04 +02:00
|
|
|
cof_grant_divisor = 1 + cof_grant / 100
|
|
|
|
is_addcost = (addcost_for and addcost_amount
|
|
|
|
and addcost_for != operationgroup.on_acc)
|
2016-08-08 03:32:48 +02:00
|
|
|
addcost_total = 0
|
2016-08-08 12:46:43 +02:00
|
|
|
to_checkout_balance = 0
|
2016-08-07 23:41:46 +02:00
|
|
|
|
|
|
|
# 1. Calculating amount of each PURCHASE operations
|
2016-08-08 02:50:04 +02:00
|
|
|
# 1.1 Standard price for n articles
|
|
|
|
# 1.2 Adding addcost if there is one
|
|
|
|
# 1.3 Taking into account cof status
|
|
|
|
# 2. Updating (no commit) stock of article for PURCHASE operations
|
|
|
|
# 3. Calculating amount of operation group
|
2016-08-08 00:41:31 +02:00
|
|
|
# 4. Adding required permissions to perform each operation
|
2016-08-08 12:46:43 +02:00
|
|
|
# 5. Calculating total addcost
|
2016-08-08 02:50:04 +02:00
|
|
|
# and adding addcost_for in operation instance
|
2016-08-08 12:46:43 +02:00
|
|
|
# 6. Calculating diff for checkout's balance
|
2016-08-06 22:19:52 +02:00
|
|
|
for operation in operations:
|
2016-08-07 17:22:39 +02:00
|
|
|
if operation.type == Operation.PURCHASE:
|
2016-08-08 02:50:04 +02:00
|
|
|
# 1.1
|
2016-08-07 17:22:39 +02:00
|
|
|
operation.amount = - operation.article.price * operation.article_nb
|
2016-08-08 02:50:04 +02:00
|
|
|
if is_addcost:
|
2016-08-08 12:46:43 +02:00
|
|
|
# 1.2
|
2016-08-08 02:50:04 +02:00
|
|
|
operation.addcost_amount = addcost_amount * operation.article_nb
|
|
|
|
operation.amount -= operation.addcost_amount
|
|
|
|
# 5
|
2016-08-08 03:32:48 +02:00
|
|
|
addcost_total += operation.addcost_amount
|
2016-08-08 02:50:04 +02:00
|
|
|
operation.addcost_for = addcost_for
|
2016-08-08 12:46:43 +02:00
|
|
|
# 6
|
|
|
|
if operationgroup.on_acc.is_cash:
|
|
|
|
to_checkout_balance += -operation.amount
|
2016-08-08 02:50:04 +02:00
|
|
|
# 1.3
|
2016-08-07 18:37:06 +02:00
|
|
|
if operationgroup.on_acc.is_cof:
|
|
|
|
operation.amount = operation.amount / cof_grant_divisor
|
2016-08-08 00:41:31 +02:00
|
|
|
# 2
|
|
|
|
operation.article.stock -= operation.article_nb
|
2016-08-08 12:46:43 +02:00
|
|
|
else:
|
|
|
|
# Ope.type is deposit or withdraw
|
|
|
|
# 6 too
|
|
|
|
to_checkout_balance += operation.amount
|
2016-08-07 23:41:46 +02:00
|
|
|
# 3
|
2016-08-08 00:41:31 +02:00
|
|
|
operationgroup.amount += operation.amount
|
|
|
|
# 4
|
2016-08-07 23:41:46 +02:00
|
|
|
if operation.type == Operation.DEPOSIT:
|
2016-08-09 11:02:26 +02:00
|
|
|
required_perms.add('kfet.perform_deposit')
|
2016-08-07 23:41:46 +02:00
|
|
|
|
2016-08-08 03:32:48 +02:00
|
|
|
# Starting transaction to ensure data consistency
|
|
|
|
# Using select_for_update where it is critical
|
2016-08-08 00:13:53 +02:00
|
|
|
try:
|
2016-08-08 00:24:46 +02:00
|
|
|
with transaction.atomic():
|
2016-08-08 07:44:05 +02:00
|
|
|
on_acc = operationgroup.on_acc
|
2016-08-08 03:32:48 +02:00
|
|
|
on_acc = Account.objects.select_for_update().get(pk=on_acc.pk)
|
|
|
|
# Adding required permissions to perform operation group
|
2016-08-08 07:44:05 +02:00
|
|
|
(opegroup_perms, stop_ope) = on_acc.perms_to_perform_operation(
|
2016-08-08 03:32:48 +02:00
|
|
|
amount = operationgroup.amount)
|
2016-08-09 11:02:26 +02:00
|
|
|
required_perms |= opegroup_perms
|
2016-08-08 03:32:48 +02:00
|
|
|
|
|
|
|
# Checking authenticated user has all perms
|
2016-08-08 07:44:05 +02:00
|
|
|
if stop_ope or not request.user.has_perms(required_perms):
|
2016-08-08 03:32:48 +02:00
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
# If 1 perm is required, saving who perform the operations
|
|
|
|
if len(required_perms) > 0:
|
|
|
|
operationgroup.valid_by = request.user.profile.account_kfet
|
|
|
|
|
|
|
|
# Filling cof status for statistics
|
|
|
|
operationgroup.is_cof = on_acc.is_cof
|
|
|
|
|
2016-08-08 12:46:43 +02:00
|
|
|
# If not cash account,
|
|
|
|
# saving account's balance and adding to Negative if not in
|
|
|
|
if not on_acc.is_cash:
|
|
|
|
on_acc.balance += operationgroup.amount
|
|
|
|
on_acc.save()
|
|
|
|
if on_acc.balance < 0:
|
|
|
|
if hasattr(on_acc, 'negative'):
|
|
|
|
if not on_acc.negative.start:
|
|
|
|
on_acc.negative.start = timezone.now()
|
|
|
|
on_acc.negative.save()
|
|
|
|
else:
|
|
|
|
negative = AccountNegative(
|
|
|
|
account = on_acc, start = timezone.now())
|
|
|
|
negative.save()
|
|
|
|
elif (hasattr(on_acc, 'negative')
|
|
|
|
and not on_acc.negative.balance_offset):
|
|
|
|
on_acc.negative.delete()
|
|
|
|
|
|
|
|
# Updating checkout's balance
|
|
|
|
operationgroup.checkout.balance += to_checkout_balance
|
|
|
|
operationgroup.checkout.save()
|
2016-08-08 07:44:05 +02:00
|
|
|
|
2016-08-08 02:50:04 +02:00
|
|
|
# Saving addcost_for with new balance if there is one
|
|
|
|
if is_addcost:
|
2016-08-08 04:11:08 +02:00
|
|
|
addcost_for.balance += addcost_total
|
2016-08-08 02:50:04 +02:00
|
|
|
addcost_for.save()
|
|
|
|
|
2016-08-08 03:32:48 +02:00
|
|
|
# Saving operation group
|
|
|
|
operationgroup.save()
|
|
|
|
data['operationgroup'] = operationgroup.pk
|
|
|
|
|
2016-08-08 00:13:53 +02:00
|
|
|
# Filling operationgroup id for each operations and saving
|
2016-08-08 00:41:31 +02:00
|
|
|
# Saving articles with new stock
|
2016-08-08 00:13:53 +02:00
|
|
|
for operation in operations:
|
|
|
|
operation.group = operationgroup
|
|
|
|
operation.save()
|
2016-08-08 00:41:31 +02:00
|
|
|
if operation.type == Operation.PURCHASE:
|
|
|
|
operation.article.save()
|
2016-08-08 00:13:53 +02:00
|
|
|
data['operations'].append(operation.pk)
|
2016-08-08 03:32:48 +02:00
|
|
|
except PermissionDenied:
|
2016-08-08 07:44:05 +02:00
|
|
|
# Sending BAD_REQUEST with missing perms or url to manage negative
|
2016-08-08 03:32:48 +02:00
|
|
|
missing_perms = \
|
|
|
|
[ Permission.objects.get(codename=codename).name for codename in (
|
|
|
|
(perm.split('.'))[1] for perm in
|
|
|
|
required_perms if not request.user.has_perm(perm)
|
|
|
|
)]
|
2016-08-08 07:44:05 +02:00
|
|
|
if missing_perms:
|
|
|
|
data['errors'].append({'missing_perms': missing_perms })
|
|
|
|
if stop_ope:
|
|
|
|
data['errors'].append({'negative': 'url to manage negative'})
|
2016-08-08 03:32:48 +02:00
|
|
|
return JsonResponse(data, status=403)
|
2016-08-06 22:19:52 +02:00
|
|
|
|
|
|
|
return JsonResponse(data)
|
2016-08-09 11:02:26 +02:00
|
|
|
|
|
|
|
@permission_required('kfet.is_team')
|
|
|
|
def kpsul_cancel_operations(request):
|
|
|
|
# Pour la réponse
|
|
|
|
data = { 'canceled': [], 'warnings': {}, 'errors': {}}
|
|
|
|
|
|
|
|
# Checking if BAD REQUEST (opes_pk not int or not existing)
|
|
|
|
try:
|
|
|
|
# Set pour virer les doublons
|
|
|
|
opes_post = set(map(int, filter(None, request.POST.getlist('operation', []))))
|
|
|
|
except ValueError:
|
|
|
|
return JsonResponse(data, status=400)
|
|
|
|
opes_all = Operation.objects.select_related('group', 'group__on_acc', 'group__on_acc__negative').filter(pk__in=opes_post)
|
|
|
|
opes_pk = [ ope.pk for ope in opes_all ]
|
|
|
|
opes_notexisting = [ ope for ope in opes_post if ope not in opes_pk ]
|
|
|
|
if opes_notexisting:
|
|
|
|
data['errors']['opes_notexisting'] = opes_notexisting
|
|
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
|
|
|
opes_already_canceled = [] # Déjà annulée
|
|
|
|
opes = [] # Pas déjà annulée
|
|
|
|
required_perms = set()
|
|
|
|
stop_all = False
|
|
|
|
cancel_duration = Settings.CANCEL_DURATION()
|
|
|
|
to_accounts_balances = defaultdict(lambda:0) # Modifs à faire sur les balances des comptes
|
|
|
|
to_groups_amounts = defaultdict(lambda:0) # ------ sur les montants des groupes d'opé
|
|
|
|
to_checkouts_balances = defaultdict(lambda:0) # ------ sur les balances de caisses
|
|
|
|
to_articles_stocks = defaultdict(lambda:0) # ------ sur les stocks d'articles
|
|
|
|
for ope in opes_all:
|
|
|
|
if ope.canceled_at:
|
|
|
|
# Opération déjà annulée, va pour un warning en Response
|
|
|
|
opes_already_canceled.append(ope.pk)
|
|
|
|
else:
|
|
|
|
opes.append(ope.pk)
|
|
|
|
# Si opé il y a plus de CANCEL_DURATION, permission requise
|
|
|
|
if ope.group.at + cancel_duration < timezone.now():
|
|
|
|
required_perms.add('kfet.cancel_old_operations')
|
|
|
|
|
|
|
|
# Calcul de toutes modifs à faire en cas de validation
|
|
|
|
|
|
|
|
# Pour les balances de comptes
|
|
|
|
if not ope.group.on_acc.is_cash:
|
|
|
|
to_accounts_balances[ope.group.on_acc] -= ope.amount
|
|
|
|
if ope.addcost_for and ope.addcost_amount:
|
|
|
|
to_accounts_balances[ope.addcost_for] -= ope.addcost_amount
|
|
|
|
# Pour les groupes d'opés
|
|
|
|
to_groups_amounts[ope.group] -= ope.amount
|
|
|
|
# Pour les balances de caisses
|
|
|
|
if ope.type == Operation.PURCHASE:
|
|
|
|
if ope.group.on_acc.is_cash:
|
|
|
|
to_checkouts_balances[ope.group.on_acc] -= - ope.amount
|
|
|
|
else:
|
|
|
|
to_checkouts_balances[ope.group.on_acc] -= ope.amount
|
|
|
|
# Pour les stocks d'articles
|
|
|
|
if ope.article and ope.article_nb:
|
|
|
|
to_articles_stocks[ope.article] += ope.article_nb
|
|
|
|
|
|
|
|
if not opes:
|
|
|
|
data['warnings']['already_canceled'] = opes_already_canceled
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
|
|
|
# Checking permissions or stop
|
|
|
|
overdraft_duration_max = Settings.OVERDRAFT_DURATION()
|
|
|
|
overdraft_amount_max = Settings.OVERDRAFT_AMOUNT()
|
|
|
|
for account in to_accounts_balances:
|
|
|
|
(perms, stop) = account.perms_to_perform_operation(
|
|
|
|
amount = to_accounts_balances[account],
|
|
|
|
overdraft_duration_max = overdraft_duration_max,
|
|
|
|
overdraft_amount_max = overdraft_amount_max)
|
|
|
|
required_perms |= perms
|
|
|
|
stop_all = stop_all or stop
|
|
|
|
|
|
|
|
if stop_all or not request.user.has_perms(required_perms):
|
|
|
|
missing_perms = get_missing_perms(required_perms, request.user)
|
|
|
|
if missing_perms:
|
|
|
|
data['errors']['missing_perms'] = missing_perms
|
|
|
|
if stop_all:
|
|
|
|
data['errors']['negative'] = True
|
|
|
|
return JsonResponse(data, status=403)
|
|
|
|
|
|
|
|
with transaction.atomic():
|
|
|
|
canceled_by = required_perms and request.user.profile.account_kfet or None
|
|
|
|
(Operation.objects.filter(pk__in=opes)
|
|
|
|
.update(canceled_by=canceled_by, canceled_at=timezone.now()))
|
|
|
|
for account in to_accounts_balances:
|
|
|
|
Account.objects.filter(pk=account.pk).update(
|
|
|
|
balance = F('balance') + to_accounts_balances[account])
|
|
|
|
for checkout in to_checkouts_balances:
|
|
|
|
Checkout.objects.filter(pk=checkout.pk).update(
|
|
|
|
balance = F('balance') + to_checkouts_balances[checkout])
|
|
|
|
for group in to_groups_amounts:
|
|
|
|
OperationGroup.objects.filter(pk=group.pk).update(
|
|
|
|
amount = F('amount') + to_groups_amounts[group])
|
|
|
|
for article in to_articles_stocks:
|
|
|
|
Article.objects.filter(pk=article.pk).update(
|
|
|
|
stock = F('stock') + to_articles_stocks[article])
|
|
|
|
|
|
|
|
data['canceled'] = opes
|
|
|
|
if opes_already_canceled:
|
|
|
|
data['warnings']['already_canceled'] = opes_already_canceled
|
|
|
|
return JsonResponse(data)
|