views.py 27 KB
Newer Older
lhark's avatar
lhark committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017  Gabriel Détraz
# Copyright © 2017  Goulven Kermarec
# Copyright © 2017  Augustin Lemesle
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

chirac's avatar
chirac committed
23 24 25
# App de gestion des users pour re2o
# Goulven Kermarec, Gabriel Détraz
# Gplv2
26
from __future__ import unicode_literals
chirac's avatar
chirac committed
27
import os
chirac's avatar
chirac committed
28
from django.shortcuts import render, redirect
29
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
30
from django.contrib.auth.decorators import login_required, permission_required
chirac's avatar
chirac committed
31
from django.contrib import messages
chirac's avatar
chirac committed
32
from django.db.models import ProtectedError
33
from django.db import transaction
34
from django.db.models import Q
Dalahro's avatar
Dalahro committed
35
from django.forms import modelformset_factory, formset_factory
chirac's avatar
chirac committed
36
from django.utils import timezone
37
from reversion import revisions as reversion
root's avatar
root committed
38
from reversion.models import Version
chirac's avatar
chirac committed
39 40 41 42 43
# Import des models, forms et fonctions re2o
from users.models import User
from re2o.settings import LOGO_PATH
from re2o import settings
from re2o.views import form
44
from re2o.utils import SortTable
chirac's avatar
chirac committed
45 46
from preferences.models import OptionalUser, AssoOption, GeneralOption
from .models import Facture, Article, Vente, Paiement, Banque
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
from .forms import (
    NewFactureForm,
    TrezEditFactureForm,
    EditFactureForm,
    ArticleForm,
    DelArticleForm,
    PaiementForm,
    DelPaiementForm,
    BanqueForm,
    DelBanqueForm,
    NewFactureFormPdf,
    SelectUserArticleForm,
    SelectClubArticleForm,
    CreditSoldeForm
)
62
from .tex import render_tex
chirac's avatar
chirac committed
63

64

chirac's avatar
chirac committed
65
@login_required
chirac's avatar
chirac committed
66
@permission_required('cableur')
chirac's avatar
chirac committed
67
def new_facture(request, userid):
68 69 70 71 72 73 74
    """Creation d'une facture pour un user. Renvoie la liste des articles
    et crée des factures dans un formset. Utilise un peu de js coté template
    pour ajouter des articles.
    Parse les article et boucle dans le formset puis save les ventes,
    enfin sauve la facture parente.
    TODO : simplifier cette fonction, déplacer l'intelligence coté models
    Facture et Vente."""
75 76 77
    try:
        user = User.objects.get(pk=userid)
    except User.DoesNotExist:
78
        messages.error(request, u"Utilisateur inexistant")
79 80
        return redirect("/cotisations/")
    facture = Facture(user=user)
81
    # Le template a besoin de connaitre les articles pour le js
82 83 84
    article_list = Article.objects.filter(
        Q(type_user='All') | Q(type_user=request.user.class_name)
    )
85
    # On envoie la form fature et un formset d'articles
chirac's avatar
chirac committed
86
    facture_form = NewFactureForm(request.POST or None, instance=facture)
87 88 89 90
    if request.user.is_class_club:
        article_formset = formset_factory(SelectClubArticleForm)(request.POST or None)
    else:
        article_formset = formset_factory(SelectUserArticleForm)(request.POST or None)
91
    if facture_form.is_valid() and article_formset.is_valid():
chirac's avatar
chirac committed
92
        new_facture_instance = facture_form.save(commit=False)
93
        articles = article_formset
94
        # Si au moins un article est rempli
95
        if any(art.cleaned_data for art in articles):
chirac's avatar
chirac committed
96
            options, _created = OptionalUser.objects.get_or_create()
chibrac's avatar
chibrac committed
97 98
            user_solde = options.user_solde
            solde_negatif = options.solde_negatif
99 100
            # Si on paye par solde, que l'option est activée,
            # on vérifie que le négatif n'est pas atteint
chibrac's avatar
chibrac committed
101
            if user_solde:
chirac's avatar
chirac committed
102 103
                if new_facture_instance.paiement == Paiement.objects.get_or_create(
                        moyen='solde'
104
                )[0]:
chibrac's avatar
chibrac committed
105 106 107
                    prix_total = 0
                    for art_item in articles:
                        if art_item.cleaned_data:
108 109
                            prix_total += art_item.cleaned_data['article']\
                                    .prix*art_item.cleaned_data['quantity']
chibrac's avatar
chibrac committed
110
                    if float(user.solde) - float(prix_total) < solde_negatif:
111 112
                        messages.error(request, "Le solde est insuffisant pour\
                                effectuer l'opération")
chibrac's avatar
chibrac committed
113
                        return redirect("/users/profil/" + userid)
114
            with transaction.atomic(), reversion.create_revision():
chirac's avatar
chirac committed
115
                new_facture_instance.save()
116 117
                reversion.set_user(request.user)
                reversion.set_comment("Création")
118 119 120 121
            for art_item in articles:
                if art_item.cleaned_data:
                    article = art_item.cleaned_data['article']
                    quantity = art_item.cleaned_data['quantity']
122
                    new_vente = Vente.objects.create(
chirac's avatar
chirac committed
123 124 125
                        facture=new_facture_instance,
                        name=article.name,
                        prix=article.prix,
126
                        type_cotisation=article.type_cotisation,
chirac's avatar
chirac committed
127 128 129
                        duration=article.duration,
                        number=quantity
                    )
130 131 132 133
                    with transaction.atomic(), reversion.create_revision():
                        new_vente.save()
                        reversion.set_user(request.user)
                        reversion.set_comment("Création")
134
            if any(art_item.cleaned_data['article'].type_cotisation
chirac's avatar
chirac committed
135
                   for art_item in articles if art_item.cleaned_data):
136 137 138 139 140 141 142
                messages.success(
                    request,
                    "La cotisation a été prolongée\
                    pour l'adhérent %s jusqu'au %s" % (
                        user.pseudo, user.end_adhesion()
                    )
                    )
143 144 145
            else:
                messages.success(request, "La facture a été crée")
            return redirect("/users/profil/" + userid)
146
        messages.error(
chirac's avatar
chirac committed
147 148
            request,
            u"Il faut au moins un article valide pour créer une facture"
149 150 151 152 153 154 155
            )
    return form({
        'factureform': facture_form,
        'venteform': article_formset,
        'articlelist': article_list
        }, 'cotisations/new_facture.html', request)

chirac's avatar
chirac committed
156

chirac's avatar
chirac committed
157
@login_required
158
@permission_required('tresorier')
159
def new_facture_pdf(request):
160 161 162
    """Permet de générer un pdf d'une facture. Réservée
    au trésorier, permet d'emettre des factures sans objet
    Vente ou Facture correspondant en bdd"""
Dalahro's avatar
Dalahro committed
163 164
    facture_form = NewFactureFormPdf(request.POST or None)
    if facture_form.is_valid():
chirac's avatar
chirac committed
165
        options, _created = AssoOption.objects.get_or_create()
Dalahro's avatar
Dalahro committed
166 167 168 169 170
        tbl = []
        article = facture_form.cleaned_data['article']
        quantite = facture_form.cleaned_data['number']
        paid = facture_form.cleaned_data['paid']
        destinataire = facture_form.cleaned_data['dest']
Dalahro's avatar
Dalahro committed
171 172
        chambre = facture_form.cleaned_data['chambre']
        fid = facture_form.cleaned_data['fid']
chirac's avatar
chirac committed
173 174
        for art in article:
            tbl.append([art, quantite, art.prix * quantite])
Dalahro's avatar
Dalahro committed
175
        prix_total = sum(a[2] for a in tbl)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
        user = {'name': destinataire, 'room': chambre}
        return render_tex(request, 'cotisations/factures.tex', {
            'DATE': timezone.now(),
            'dest': user,
            'fid': fid,
            'article': tbl,
            'total': prix_total,
            'paid': paid,
            'asso_name': options.name,
            'line1': options.adresse1,
            'line2': options.adresse2,
            'siret': options.siret,
            'email': options.contact,
            'phone': options.telephone,
            'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
            })
    return form({
        'factureform': facture_form
        }, 'cotisations/facture.html', request)

196

Dalahro's avatar
Dalahro committed
197 198
@login_required
def facture_pdf(request, factureid):
199 200 201 202
    """Affiche en pdf une facture. Cree une ligne par Vente de la facture,
    et génére une facture avec le total, le moyen de paiement, l'adresse
    de l'adhérent, etc. Réservée à self pour un user sans droits,
    les droits cableurs permettent d'afficher toute facture"""
Dalahro's avatar
Dalahro committed
203 204 205
    try:
        facture = Facture.objects.get(pk=factureid)
    except Facture.DoesNotExist:
206
        messages.error(request, u"Facture inexistante")
Dalahro's avatar
Dalahro committed
207
        return redirect("/cotisations/")
208 209 210 211
    if not request.user.has_perms(('cableur',))\
            and facture.user != request.user:
        messages.error(request, "Vous ne pouvez pas afficher une facture ne vous\
                appartenant pas sans droit cableur")
Dalahro's avatar
Dalahro committed
212
        return redirect("/users/profil/" + str(request.user.id))
213
    if not facture.valid:
214 215
        messages.error(request, "Vous ne pouvez pas afficher\
        une facture non valide")
216
        return redirect("/users/profil/" + str(request.user.id))
chirac's avatar
chirac committed
217
    ventes_objects = Vente.objects.all().filter(facture=facture)
Dalahro's avatar
Dalahro committed
218
    ventes = []
chirac's avatar
chirac committed
219 220 221
    options, _created = AssoOption.objects.get_or_create()
    for vente in ventes_objects:
        ventes.append([vente, vente.number, vente.prix_total])
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    return render_tex(request, 'cotisations/factures.tex', {
        'paid': True,
        'fid': facture.id,
        'DATE': facture.date,
        'dest': facture.user,
        'article': ventes,
        'total': facture.prix_total(),
        'asso_name': options.name,
        'line1': options.adresse1,
        'line2': options.adresse2,
        'siret': options.siret,
        'email': options.contact,
        'phone': options.telephone,
        'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
        })

Dalahro's avatar
Dalahro committed
238

Dalahro's avatar
Dalahro committed
239
@login_required
chirac's avatar
chirac committed
240
@permission_required('cableur')
chirac's avatar
chirac committed
241
def edit_facture(request, factureid):
242 243 244
    """Permet l'édition d'une facture. On peut y éditer les ventes
    déjà effectuer, ou rendre une facture invalide (non payées, chèque
    en bois etc). Mets à jour les durée de cotisation attenantes"""
chirac's avatar
chirac committed
245 246 247
    try:
        facture = Facture.objects.get(pk=factureid)
    except Facture.DoesNotExist:
248
        messages.error(request, u"Facture inexistante")
chirac's avatar
chirac committed
249
        return redirect("/cotisations/")
250
    if request.user.has_perms(['tresorier']):
251 252 253 254
        facture_form = TrezEditFactureForm(
            request.POST or None,
            instance=facture
        )
255
    elif facture.control or not facture.valid:
256 257
        messages.error(request, "Vous ne pouvez pas editer une facture\
                controlée ou invalidée par le trésorier")
258 259 260
        return redirect("/cotisations/")
    else:
        facture_form = EditFactureForm(request.POST or None, instance=facture)
Dalahro's avatar
Dalahro committed
261
    ventes_objects = Vente.objects.filter(facture=facture)
262
    vente_form_set = modelformset_factory(
chirac's avatar
chirac committed
263 264 265 266 267
        Vente,
        fields=('name', 'number'),
        extra=0,
        max_num=len(ventes_objects)
        )
Dalahro's avatar
Dalahro committed
268 269
    vente_form = vente_form_set(request.POST or None, queryset=ventes_objects)
    if facture_form.is_valid() and vente_form.is_valid():
270 271 272 273
        with transaction.atomic(), reversion.create_revision():
            facture_form.save()
            vente_form.save()
            reversion.set_user(request.user)
274 275
            reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
                field for form in vente_form for field
chirac's avatar
chirac committed
276
                in facture_form.changed_data + form.changed_data))
chirac's avatar
chirac committed
277 278
        messages.success(request, "La facture a bien été modifiée")
        return redirect("/cotisations/")
279 280 281 282 283
    return form({
        'factureform': facture_form,
        'venteform': vente_form
        }, 'cotisations/edit_facture.html', request)

chirac's avatar
chirac committed
284

285 286 287
@login_required
@permission_required('cableur')
def del_facture(request, factureid):
288 289
    """Suppression d'une facture. Supprime en cascade les ventes
    et cotisations filles"""
290 291 292
    try:
        facture = Facture.objects.get(pk=factureid)
    except Facture.DoesNotExist:
293
        messages.error(request, u"Facture inexistante")
294
        return redirect("/cotisations/")
chirac's avatar
chirac committed
295
    if facture.control or not facture.valid:
296 297
        messages.error(request, "Vous ne pouvez pas editer une facture\
                controlée ou invalidée par le trésorier")
298
        return redirect("/cotisations/")
299
    if request.method == "POST":
300 301 302
        with transaction.atomic(), reversion.create_revision():
            facture.delete()
            reversion.set_user(request.user)
303 304
        messages.success(request, "La facture a été détruite")
        return redirect("/cotisations/")
305 306 307 308 309
    return form({
        'objet': facture,
        'objet_name': 'facture'
        }, 'cotisations/delete.html', request)

310

chibrac's avatar
chibrac committed
311 312 313 314 315 316 317
@login_required
@permission_required('cableur')
def credit_solde(request, userid):
    """ Credit ou débit de solde """
    try:
        user = User.objects.get(pk=userid)
    except User.DoesNotExist:
318
        messages.error(request, u"Utilisateur inexistant")
chibrac's avatar
chibrac committed
319 320 321 322 323 324 325 326
        return redirect("/cotisations/")
    facture = CreditSoldeForm(request.POST or None)
    if facture.is_valid():
        facture_instance = facture.save(commit=False)
        with transaction.atomic(), reversion.create_revision():
            facture_instance.user = user
            facture_instance.save()
            reversion.set_user(request.user)
327 328
            reversion.set_comment("Création")
        new_vente = Vente.objects.create(
chirac's avatar
chirac committed
329 330 331 332 333
            facture=facture_instance,
            name="solde",
            prix=facture.cleaned_data['montant'],
            number=1
            )
chibrac's avatar
chibrac committed
334 335 336 337 338 339 340 341 342
        with transaction.atomic(), reversion.create_revision():
            new_vente.save()
            reversion.set_user(request.user)
            reversion.set_comment("Création")
        messages.success(request, "Solde modifié")
        return redirect("/cotisations/")
    return form({'factureform': facture}, 'cotisations/facture.html', request)


chirac's avatar
chirac committed
343
@login_required
344
@permission_required('tresorier')
345
def add_article(request):
346 347 348 349 350 351 352
    """Ajoute un article. Champs : désignation,
    prix, est-ce une cotisation et si oui sa durée
    Réservé au trésorier
    Nota bene : les ventes déjà effectuées ne sont pas reliées
    aux articles en vente. La désignation, le prix... sont
    copiés à la création de la facture. Un changement de prix n'a
    PAS de conséquence sur les ventes déjà faites"""
353 354
    article = ArticleForm(request.POST or None)
    if article.is_valid():
355 356 357 358
        with transaction.atomic(), reversion.create_revision():
            article.save()
            reversion.set_user(request.user)
            reversion.set_comment("Création")
359
        messages.success(request, "L'article a été ajouté")
360 361 362
        return redirect("/cotisations/index_article/")
    return form({'factureform': article}, 'cotisations/facture.html', request)

363

chirac's avatar
chirac committed
364
@login_required
365
@permission_required('tresorier')
366
def edit_article(request, articleid):
367 368
    """Edition d'un article (designation, prix, etc)
    Réservé au trésorier"""
369 370 371
    try:
        article_instance = Article.objects.get(pk=articleid)
    except Article.DoesNotExist:
372
        messages.error(request, u"Entrée inexistante")
373 374 375
        return redirect("/cotisations/index_article/")
    article = ArticleForm(request.POST or None, instance=article_instance)
    if article.is_valid():
376 377 378
        with transaction.atomic(), reversion.create_revision():
            article.save()
            reversion.set_user(request.user)
379 380 381 382 383
            reversion.set_comment(
                "Champs modifié(s) : %s" % ', '.join(
                    field for field in article.changed_data
                )
            )
384 385
        messages.success(request, "Type d'article modifié")
        return redirect("/cotisations/index_article/")
386 387
    return form({'factureform': article}, 'cotisations/facture.html', request)

388

chirac's avatar
chirac committed
389
@login_required
390
@permission_required('tresorier')
391
def del_article(request):
392
    """Suppression d'un article en vente"""
393 394 395
    article = DelArticleForm(request.POST or None)
    if article.is_valid():
        article_del = article.cleaned_data['articles']
396 397 398
        with transaction.atomic(), reversion.create_revision():
            article_del.delete()
            reversion.set_user(request.user)
399
        messages.success(request, "Le/les articles ont été supprimé")
400
        return redirect("/cotisations/index_article")
401 402
    return form({'factureform': article}, 'cotisations/facture.html', request)

403

chirac's avatar
chirac committed
404
@login_required
405
@permission_required('tresorier')
406
def add_paiement(request):
407 408
    """Ajoute un moyen de paiement. Relié aux factures
    via foreign key"""
409 410
    paiement = PaiementForm(request.POST or None)
    if paiement.is_valid():
411 412 413 414
        with transaction.atomic(), reversion.create_revision():
            paiement.save()
            reversion.set_user(request.user)
            reversion.set_comment("Création")
415
        messages.success(request, "Le moyen de paiement a été ajouté")
416 417 418
        return redirect("/cotisations/index_paiement/")
    return form({'factureform': paiement}, 'cotisations/facture.html', request)

419

chirac's avatar
chirac committed
420
@login_required
421
@permission_required('tresorier')
422
def edit_paiement(request, paiementid):
423
    """Edition d'un moyen de paiement"""
424 425 426
    try:
        paiement_instance = Paiement.objects.get(pk=paiementid)
    except Paiement.DoesNotExist:
427
        messages.error(request, u"Entrée inexistante")
428 429 430
        return redirect("/cotisations/index_paiement/")
    paiement = PaiementForm(request.POST or None, instance=paiement_instance)
    if paiement.is_valid():
431 432 433
        with transaction.atomic(), reversion.create_revision():
            paiement.save()
            reversion.set_user(request.user)
434 435
            reversion.set_comment(
                "Champs modifié(s) : %s" % ', '.join(
chirac's avatar
chirac committed
436
                    field for field in paiement.changed_data
437 438
                    )
            )
439 440
        messages.success(request, "Type de paiement modifié")
        return redirect("/cotisations/index_paiement/")
441 442
    return form({'factureform': paiement}, 'cotisations/facture.html', request)

443

chirac's avatar
chirac committed
444
@login_required
445
@permission_required('tresorier')
446
def del_paiement(request):
447
    """Suppression d'un moyen de paiement"""
448 449 450 451 452
    paiement = DelPaiementForm(request.POST or None)
    if paiement.is_valid():
        paiement_dels = paiement.cleaned_data['paiements']
        for paiement_del in paiement_dels:
            try:
453 454 455 456
                with transaction.atomic(), reversion.create_revision():
                    paiement_del.delete()
                    reversion.set_user(request.user)
                    reversion.set_comment("Destruction")
457
                messages.success(
chirac's avatar
chirac committed
458 459
                    request,
                    "Le moyen de paiement a été supprimé"
460
                    )
461
            except ProtectedError:
462 463 464 465 466
                messages.error(
                    request,
                    "Le moyen de paiement %s est affecté à au moins une\
                    facture, vous ne pouvez pas le supprimer" % paiement_del
                )
467
        return redirect("/cotisations/index_paiement/")
468 469
    return form({'factureform': paiement}, 'cotisations/facture.html', request)

470

chirac's avatar
chirac committed
471
@login_required
chirac's avatar
chirac committed
472
@permission_required('cableur')
chirac's avatar
chirac committed
473
def add_banque(request):
474
    """Ajoute une banque à la liste des banques"""
chirac's avatar
chirac committed
475 476
    banque = BanqueForm(request.POST or None)
    if banque.is_valid():
477 478 479 480
        with transaction.atomic(), reversion.create_revision():
            banque.save()
            reversion.set_user(request.user)
            reversion.set_comment("Création")
chirac's avatar
chirac committed
481
        messages.success(request, "La banque a été ajoutée")
482 483 484
        return redirect("/cotisations/index_banque/")
    return form({'factureform': banque}, 'cotisations/facture.html', request)

485

chirac's avatar
chirac committed
486
@login_required
487
@permission_required('tresorier')
488
def edit_banque(request, banqueid):
489
    """Edite le nom d'une banque"""
490
    try:
491
        banque_instance = Banque.objects.get(pk=banqueid)
492
    except Banque.DoesNotExist:
493
        messages.error(request, u"Entrée inexistante")
494 495 496
        return redirect("/cotisations/index_banque/")
    banque = BanqueForm(request.POST or None, instance=banque_instance)
    if banque.is_valid():
497 498 499
        with transaction.atomic(), reversion.create_revision():
            banque.save()
            reversion.set_user(request.user)
500 501 502 503 504
            reversion.set_comment(
                "Champs modifié(s) : %s" % ', '.join(
                    field for field in banque.changed_data
                )
            )
505 506
        messages.success(request, "Banque modifiée")
        return redirect("/cotisations/index_banque/")
chirac's avatar
chirac committed
507 508
    return form({'factureform': banque}, 'cotisations/facture.html', request)

509

chirac's avatar
chirac committed
510
@login_required
511
@permission_required('tresorier')
chirac's avatar
chirac committed
512
def del_banque(request):
513
    """Supprime une banque"""
chirac's avatar
chirac committed
514 515 516 517 518
    banque = DelBanqueForm(request.POST or None)
    if banque.is_valid():
        banque_dels = banque.cleaned_data['banques']
        for banque_del in banque_dels:
            try:
519 520 521 522
                with transaction.atomic(), reversion.create_revision():
                    banque_del.delete()
                    reversion.set_user(request.user)
                    reversion.set_comment("Destruction")
chirac's avatar
chirac committed
523 524
                messages.success(request, "La banque a été supprimée")
            except ProtectedError:
525 526
                messages.error(request, "La banque %s est affectée à au moins\
                    une facture, vous ne pouvez pas la supprimer" % banque_del)
527
        return redirect("/cotisations/index_banque/")
chirac's avatar
chirac committed
528 529
    return form({'factureform': banque}, 'cotisations/facture.html', request)

530

531
@login_required
532
@permission_required('tresorier')
533
def control(request):
534 535
    """Pour le trésorier, vue pour controler en masse les
    factures.Case à cocher, pratique"""
chirac's avatar
chirac committed
536
    options, _created = GeneralOption.objects.get_or_create()
537
    pagination_number = options.pagination_number
538 539 540 541 542 543 544
    facture_list = Facture.objects.select_related('user').select_related('paiement')
    facture_list = SortTable.sort(
        facture_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.COTISATIONS_CONTROL
    )
545
    controlform_set = modelformset_factory(
chirac's avatar
chirac committed
546 547 548 549
        Facture,
        fields=('control', 'valid'),
        extra=0
        )
550
    paginator = Paginator(facture_list, pagination_number)
551 552 553 554 555 556 557
    page = request.GET.get('page')
    try:
        facture_list = paginator.page(page)
    except PageNotAnInteger:
        facture_list = paginator.page(1)
    except EmptyPage:
        facture_list = paginator.page(paginator.num.pages)
558
    controlform = controlform_set(request.POST or None, queryset=facture_list.object_list)
559
    if controlform.is_valid():
560 561 562 563
        with transaction.atomic(), reversion.create_revision():
            controlform.save()
            reversion.set_user(request.user)
            reversion.set_comment("Controle trésorier")
564
        return redirect("/cotisations/control/")
565 566 567 568 569
    return render(request, 'cotisations/control.html', {
        'facture_list': facture_list,
        'controlform': controlform
        })

570

chirac's avatar
chirac committed
571
@login_required
chirac's avatar
chirac committed
572
@permission_required('cableur')
573
def index_article(request):
574
    """Affiche l'ensemble des articles en vente"""
575
    article_list = Article.objects.order_by('name')
576 577 578 579
    return render(request, 'cotisations/index_article.html', {
        'article_list': article_list
        })

580

chirac's avatar
chirac committed
581
@login_required
chirac's avatar
chirac committed
582
@permission_required('cableur')
583
def index_paiement(request):
584
    """Affiche l'ensemble des moyens de paiement en vente"""
585
    paiement_list = Paiement.objects.order_by('moyen')
586 587 588 589
    return render(request, 'cotisations/index_paiement.html', {
        'paiement_list': paiement_list
        })

590

chirac's avatar
chirac committed
591
@login_required
chirac's avatar
chirac committed
592
@permission_required('cableur')
593
def index_banque(request):
594
    """Affiche l'ensemble des banques"""
595
    banque_list = Banque.objects.order_by('name')
596 597 598 599
    return render(request, 'cotisations/index_banque.html', {
        'banque_list': banque_list
        })

600

chirac's avatar
chirac committed
601
@login_required
chirac's avatar
chirac committed
602
@permission_required('cableur')
chirac's avatar
chirac committed
603
def index(request):
604
    """Affiche l'ensemble des factures, pour les cableurs et +"""
chirac's avatar
chirac committed
605
    options, _created = GeneralOption.objects.get_or_create()
606
    pagination_number = options.pagination_number
607 608 609 610 611 612 613 614
    facture_list = Facture.objects.select_related('user')\
        .select_related('paiement').prefetch_related('vente_set')
    facture_list = SortTable.sort(
        facture_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.COTISATIONS_INDEX
    )
615
    paginator = Paginator(facture_list, pagination_number)
616 617 618 619 620 621 622 623 624
    page = request.GET.get('page')
    try:
        facture_list = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        facture_list = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        facture_list = paginator.page(paginator.num_pages)
625 626 627 628
    return render(request, 'cotisations/index.html', {
        'facture_list': facture_list
        })

629 630

@login_required
631
def history(request, object_name, object_id):
632
    """Affiche l'historique de chaque objet"""
633
    if object_name == 'facture':
634
        try:
chirac's avatar
chirac committed
635
            object_instance = Facture.objects.get(pk=object_id)
636
        except Facture.DoesNotExist:
637 638 639 640 641 642 643
            messages.error(request, "Facture inexistante")
            return redirect("/cotisations/")
        if not request.user.has_perms(('cableur',))\
                and object_instance.user != request.user:
            messages.error(request, "Vous ne pouvez pas afficher l'historique\
                 d'une facture d'un autre user que vous sans droit cableur")
            return redirect("/users/profil/" + str(request.user.id))
644
    elif object_name == 'paiement' and request.user.has_perms(('cableur',)):
645
        try:
chirac's avatar
chirac committed
646
            object_instance = Paiement.objects.get(pk=object_id)
647
        except Paiement.DoesNotExist:
648 649
            messages.error(request, "Paiement inexistant")
            return redirect("/cotisations/")
650
    elif object_name == 'article' and request.user.has_perms(('cableur',)):
651
        try:
chirac's avatar
chirac committed
652
            object_instance = Article.objects.get(pk=object_id)
653
        except Article.DoesNotExist:
654 655
            messages.error(request, "Article inexistante")
            return redirect("/cotisations/")
656
    elif object_name == 'banque' and request.user.has_perms(('cableur',)):
657
        try:
chirac's avatar
chirac committed
658
            object_instance = Banque.objects.get(pk=object_id)
659
        except Banque.DoesNotExist:
660 661
            messages.error(request, "Banque inexistante")
            return redirect("/cotisations/")
662 663 664
    else:
        messages.error(request, "Objet  inconnu")
        return redirect("/cotisations/")
chirac's avatar
chirac committed
665
    options, _created = GeneralOption.objects.get_or_create()
666
    pagination_number = options.pagination_number
root's avatar
root committed
667
    reversions = Version.objects.get_for_object(object_instance)
668
    paginator = Paginator(reversions, pagination_number)
chirac's avatar
chirac committed
669 670 671 672 673 674 675 676 677
    page = request.GET.get('page')
    try:
        reversions = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        reversions = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        reversions = paginator.page(paginator.num_pages)
678 679 680 681
    return render(request, 're2o/history.html', {
        'reversions': reversions,
        'object': object_instance
        })