forms.py 49.9 KB
Newer Older
1
2
3
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

4
from django import forms
5
from django.forms import widgets
6
from django.contrib.admin import widgets as admin_widgets
7
8
from django.utils.safestring import mark_safe

9
import settings
10

11
12
13
import re
import time
import datetime
14

15
16
17
18
#: Import pour la traduction
from django.utils.translation import ugettext_lazy as _


19
20
21
22
class CreditRetraitWithoutIdbde(Exception):
    """Erreur levée en cas de tentative de crédit ou retrait sans idbde."""
    pass

23
24
25
26
27
class BootstrapForm(forms.Form):
    """Ajoute l'attribut 'class' à tous les champs du formulare"""
    def __init__(self, *args, **kwargs):
        super(BootstrapForm, self).__init__(*args, **kwargs)
        for name, field in self.fields.items():
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
            if field.widget.__class__ == widgets.RadioSelect:
                if field.widget.attrs.has_key('class'):
                    field.widget.attrs['class'] += ' radio-inline'
                else:
                    field.widget.attrs.update({'class': 'radio-inline'})
            elif field.widget.__class__ == widgets.CheckboxSelectMultiple:
                if field.widget.attrs.has_key('class'):
                    field.widget.attrs['class'] += ' checkbox-inline'
                else:
                    field.widget.attrs.update({'class': 'checkbox-inline'})
            elif field.widget.__class__ == widgets.CheckboxInput:
                if field.widget.attrs.has_key('class'):
                    field.widget.attrs['class'] += ' checkbox-inline'
                else:
                    field.widget.attrs.update({'class': 'checkbox-inline'})
43
            else:
44
45
46
47
                if field.widget.attrs.has_key('class'):
                    field.widget.attrs['class'] += ' form-control'
                else:
                    field.widget.attrs.update({'class': 'form-control'})
48
49

class LoginForm(BootstrapForm):
50
    """Formulaire de login"""
51
52
    username = forms.CharField(label=_(u"Pseudo"), widget=forms.TextInput(attrs={"placeholder" : _(u"Ton pseudo note kfet"), "autofocus" : "autofocus", "class" : "form-control"}))
    password = forms.CharField(label=_(u"Mot de passe"), widget=forms.PasswordInput(render_value=False, attrs={ "class" : "form-control" }))
Antoine Bernard's avatar
Antoine Bernard committed
53
    droits = forms.ChoiceField(label=_(u"Droits"), choices=[(k, settings.ACL_MASKS[k][0]) for k in settings._acl_masks_keys])
54

55
class InviteForm(BootstrapForm):
56
    """Formulaire d'invitation"""
57
58
    nom = forms.CharField(label=_(u"Nom"))
    prenom = forms.CharField(label=_(u"Prénom"))
59

60
61
62
class FrenchFloatField(forms.FloatField):
    """Un champ FloatField, mais qui accepte aussi la virgule comme séparateur"""
    def to_python(self, raw_value):
Vincent Le gallic's avatar
Vincent Le gallic committed
63
        """Conversion de la valeur texte en objet python."""
64
        return super(FrenchFloatField, self).to_python(raw_value.replace(",", "."))
65

66
class BaseCompteRelatedForm(BootstrapForm):
67
    """Classe de base pour tous les formulaires traitant un compte (même une préinscription)"""
68
69
70
71
72
73
    type = forms.ChoiceField(label=_(u"Type de compte"), choices=[("personne", _(u"Personne")), ("club", _(u"Club"))])
    nom = forms.CharField(label=_(u"Nom"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    prenom = forms.CharField(label=_(u"Prénom"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    mail = forms.CharField(label=_(u"E-mail"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    tel = forms.CharField(label=_(u"Téléphone"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    adresse = forms.CharField(label=_(u"Adresse"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
Antoine Bernard's avatar
Antoine Bernard committed
74
    pbsante = forms.CharField(label=_(u"Problèmes de santé"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
75
76
    normalien = forms.BooleanField(label=_(u"Normalien"), required=False)
    section = forms.CharField(label=_(u"Section"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
77
78


79
class Regen_pwForm(BootstrapForm):
80
    """Formulaire de demande de nouveau mot de passe"""
81
82
83
    nom = forms.CharField(label=_(u"Nom"), widget=forms.TextInput(attrs={"autocomplete" : "off", "class" : "form-control"}), required=True)
    prenom = forms.CharField(label=_(u"Prénom"), widget=forms.TextInput(attrs={"autocomplete" : "off", "class" : "form-control" }), required=True)
    mail = forms.CharField(label=_(u"E-mail"), widget=forms.TextInput(attrs={"autocomplete" : "off", "class" : "form-control" }), required=True)
84
85
86
87

class CompteRelatedForm(BaseCompteRelatedForm):
    """Classe de base pour les formulaires traitant un compte avec toutes ses données
       (par opposition à une préinscription)."""
88
89
90
91
92
    pseudo = forms.CharField(label=_(u"Pseudo"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    fonction = forms.CharField(label=_(u"Fonction"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    commentaire = forms.CharField(label=_(u"Commentaire"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    report_period = forms.IntegerField(label=_(u"Fréquence des rapports"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    bloque = forms.BooleanField(label=_(u"Bloquer le compte"), required=False)
93
94
    def __init__(self, *args, **kwargs):
        super(CompteRelatedForm, self).__init__(*args, **kwargs)
pac's avatar
pac committed
95
96
        # La section n'est facultative qu'à la préinscription et si c'est une personne
        self.fields["section"].required = (self.fields["type"] == "personne")
Vincent Le gallic's avatar
Vincent Le gallic committed
97
    
98
99
class CompteForm(CompteRelatedForm):
    """Formulaire pour modifier un compte"""
Vincent Le gallic's avatar
Vincent Le gallic committed
100
101
    def clean(self):
        """Supprime les None des champs facultatifs"""
102
        out = super(CompteForm, self).clean()
103
        if out.has_key("report_period") and (out["report_period"] == None):
Vincent Le gallic's avatar
Vincent Le gallic committed
104
105
            del out["report_period"]
        return out
106

107
108
109
110
class PreinscriptionForm(BaseCompteRelatedForm):
    """Formulaire de préinscription"""
    def clean(self):
        """Gestion des None"""
111
        out = super(PreinscriptionForm, self).clean()
112
113
        return out

114
class ReadhesionForm(BootstrapForm):
115
    """Formulaire de réadhésion"""
116
    section = forms.CharField(label=_(u"Section"), required=True, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
117
    # partie paiement
118
119
    on_note = FrenchFloatField(label=_(u"Montant supplémentaire à mettre sur la note"), required=False, initial=0, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    type_de_paiement = forms.ChoiceField(label=_(u"Type de paiement"),
120
121
                                         choices=[("none", _(u"Pas de crédit")),
                                                  ("cheque", _(u"Chèque")),
122
123
124
                                                  ("especes", _(u"Espèces")),
                                                  ("cb", _(u"Carte bancaire")),
                                                  ("virement", _(u"Virement bancaire")),
125
                                                  ("soge", _(u"Société Générale"))]
126
127
128
129
                                        )
    pay_nom = forms.CharField(label=_(u"Nom¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    pay_prenom = forms.CharField(label=_(u"Prénom¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    pay_banque = forms.CharField(label=_(u"Banque¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
130
131
    def clean(self):
        """des valeurs par défaut"""
132
        out = super(ReadhesionForm, self).clean()
133
134
        # Si on débite l'adhésion sur note sans faire de crédit, on n'autorise pas de on_note
        if out.get("type_de_paiement") == "none" and out.get("on_note", 0) != 0:
135
            raise forms.ValidationError(_(u"Pour une réadhésion sans crédit, il est impossible de donner un montant supplémentaire."))
136
        if out.has_key("on_note") and type(out["on_note"]) == float:
137
            out["on_note"] = int(round(100 * out["on_note"]))
138
139
140
141
142
143
144
        else:
            out["on_note"] = 0
        if out.has_key("section") and (out["section"] == ""):
            del out["section"]
        return out


145
class InscriptionForm(CompteRelatedForm):
146
147
148
149
150
151
152
153
154
155
156
    """Formulaire pour inscrire un nouveau compte.
       À l'initialisation, on peut fournir ``full_acl`` (keyword argument) pour passer en readonly les champs
       qui nécessite certains droits. Si non précisé, on considèrera que l'utilisateur n'a aucun droit.
       (Donc tous les champs sensibles seront readonly).
       """
    #: Champs qui apparaîtront en premier
    PRIORITY_FIELDS = ["normalien", "wei", "override_adh"]
    
    #: Association champ -> droit nécessaire pour le modifier
    ACL_NEEDED = {"override_adh" : u"adhesions_admin"}
    
157
158
159
    wei = forms.BooleanField(label=_(u"Inscription au WEI"), required=False)
    override_adh = FrenchFloatField(label=_(u"Montant de l'adhésion"), widget=forms.TextInput(attrs={"autocomplete": "off"}))
    annee = forms.IntegerField(label=_(u"Année d'inscription (année courante si non précisée)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
160
    # partie paiement
161
162
163
164
165
166
167
168
169
170
171
172
    on_note = FrenchFloatField(label=_(u"Montant supplémentaire à mettre sur la note"), required=False, initial=0, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    type_de_paiement = forms.ChoiceField(label=_(u"Type de paiement"),
                                         choices=[("cheque", _(u"Chèque")),
                                                  ("especes", _(u"Espèces")),
                                                  ("cb", _(u"Carte bancaire")),
                                                  ("virement", _(u"Virement bancaire")),
                                                  ("soge", _(u"Société Générale")),
                                                  ("none", _(u"Pas de crédit"))]
                                        )
    pay_nom = forms.CharField(label=_(u"Nom¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    pay_prenom = forms.CharField(label=_(u"Prénom¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    pay_banque = forms.CharField(label=_(u"Banque¹ (pour le paiement)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
173
174
175
176
177
178
179
180
181
182
    
    def __init__(self, *args, **kwargs):
        acls = kwargs.get("full_rights", [])
        if acls:
            del kwargs["full_rights"]
        super(InscriptionForm, self).__init__(*args, **kwargs)
        # On bloque les champs que l'utilisateur n'a pas le droit de modifier
        for (fieldname, acl) in InscriptionForm.ACL_NEEDED.iteritems():
            if not acl in acls:
                self.fields[fieldname].widget.attrs["readonly"] = True
183
184
185
        # Certains champs doivent recalculer le montant de l'adhésion en cas de modification
        for fieldname in ["normalien", "wei"]:
            self.fields[fieldname].widget.attrs["onChange"] = "javascript:update_montant_adhesion();return(false);"
186
    
187
188
    def clean(self):
        """des valeurs par défaut"""
189
        out = super(InscriptionForm, self).clean()
190
        if out.has_key("on_note") and type(out["on_note"]) == float:
191
            out["on_note"] = int(round(100 * out["on_note"]))
192
193
194
195
196
197
198
199
        else:
            out["on_note"] = 0
        if out.has_key("report_period") and (out["report_period"] == None):
            del out["report_period"]
        if out.has_key("annee") and (out["annee"] == None):
            del out["annee"]
        return out

200
class AliasForm(BootstrapForm):
201
    """Formulaire pour ajouter un alias"""
202
    alias = forms.CharField(label=_(u"Nouvel alias"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
Vincent Le gallic's avatar
Vincent Le gallic committed
203

204
class PasswordForm(BootstrapForm):
205
    """Formulaire pour changer un mot de passe"""
206
207
    password = forms.CharField(label=_(u"Nouveau mot de passe"), widget=forms.PasswordInput)
    password_confirm = forms.CharField(label=_(u"Confirmation du mot de passe"), widget=forms.PasswordInput, required=True)
Vincent Le gallic's avatar
Vincent Le gallic committed
208
    def clean(self):
209
        """Vérifie que le mot de passe et sa confirmation concordent et enlève le deuxième."""
210
        out = super(PasswordForm, self).clean()
Vincent Le gallic's avatar
Vincent Le gallic committed
211
212
        if self.errors:
            return out
213
        if (out["password"] != out["password_confirm"]):
214
            raise forms.ValidationError(_(u"Le mot de passe et sa confirmation ne concordent pas."))
Vincent Le gallic's avatar
Vincent Le gallic committed
215
216
        else:
            del out["password_confirm"]
Vincent Le gallic's avatar
Vincent Le gallic committed
217
218
            return out

219
class SearchForm(CompteRelatedForm):
220
    """Formulaire pour faire une recherche avancée"""
221
    # On peut rechercher sur tous les champs d'un compte, plus les alias et les anciens pseudos
222
223
    alias = forms.CharField(label=_(u"Alias"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    historique = forms.CharField(label=_(u"Ancien pseudo (toujours actif)"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
224
225
226
    def __init__(self, *args, **kwargs):
        super(CompteRelatedForm, self).__init__(*args, **kwargs)
        # La section n'est facultative qu'à la préinscription
227
        for field in self.fields:
228
            self.fields[field].required = False
229

230
class SearchHistoriquePseudoForm(BootstrapForm):
231
    """Formulaire pour faire une recherche par ancien pseudo"""
232
233
    historique = forms.CharField(label=_(u"Ancien pseudo"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    exactfilter = forms.ChoiceField(label=_(u"Correspondance sur :"),
234
                                    widget=forms.RadioSelect,
235
                                    choices=[("b", _(u"début du mot")), ("", _(u"n'importe où dans le mot")), ("x", _(u"correspondance exacte"))],
236
237
238
239
240
241
242
                                    required=False)

# Les formats de timestamps acceptés
#  Les dates
### Les %s sont là parce qu'on a besoin de placer les groupes à deux endroits
### dans la regexp, et ça nécessite qu'ils aient deux noms différents
year_match = ur'(?P<y%s>[0-9]{2}|[0-9]{4})'
243
ym1, ym2 = year_match % (1), year_match % (2)
244
month_match = ur'(?P<m%s>[0-9]{1,2})'
245
mm1, mm2 = month_match % (1), month_match % (2)
246
day_match = ur'(?P<d%s>[0-9]{1,2})'
247
248
dm1, dm2 = day_match % (1), day_match % (2)
date_match = ur'^(?:' + ym1 + '-' + mm1 + '-' + dm1 + '|' + dm2 + '/' + mm2 + '(?:/' + ym2 + ')?)$'
249
250
251
252
253
254
255
256

date_matcher = re.compile(date_match)

#  Les heures (il n'est pas nécessaire de les spécifier (défaut à 0 pour chaque champ))
hours_match = ur'(?:(?P<H>[0-9]{1,2}) ?(?:h|heures?)?\.?)?'
minutes_match = ur'(?:(?P<M>[0-9]{1,2}) ?(?:m|min|minutes?)?\.?)?'
seconds_match = ur'(?:(?P<S>[0-9]{1,2}) ?(?:s|sec|secondes?)?\.?)?'
separator_match = u"(?::| )?"
257
time_match = u'^' + separator_match.join([hours_match, minutes_match, seconds_match]) + u'$'
258
259
260
261
262

time_matcher = re.compile(time_match)

def to_string_ignoring_None(obj):
    """Convertit un objet en chaîne de caractères, mais avec None -> '' """
263
    if (obj == None):
264
265
266
267
268
269
        return ""
    else:
        return unicode(obj)

def to_int_ignoring_null(obj):
    """Convertit un objet en entier mais avec None et '' -> 0"""
270
    if obj in [None, '']:
271
272
273
274
275
276
277
278
279
        return 0
    else:
        return int(obj)

class MyDateField(forms.CharField):
    """Un champ personnalisé de détection de date.
       Renvoie un objet datetime.date"""
    description = u"Une date (assez souple sur le format d'entrée)"
    
280
    def to_python(self, raw_value):
Vincent Le gallic's avatar
Vincent Le gallic committed
281
        """Conversion de la valeur texte en objet python."""
282
        raw_value = super(MyDateField, self).to_python(raw_value)
Vincent Le gallic's avatar
Vincent Le gallic committed
283
        if raw_value == u'':
284
            raise forms.ValidationError(_(u"Ce champ est obligatoire"))
285
286
287
288
        result = date_matcher.match(raw_value)
        if result:
            data = result.groupdict()
            # On commence par fusionner ce qui n'a été séparé que par les règles de re.compile
289
290
291
            for field in ["y", "m", "d"]:
                f1, f2 = field + "1", field + "2"
                data[field] = to_string_ignoring_None(data[f1]) + to_string_ignoring_None(data[f2])
292
293
294
295
296
                del data[f1], data[f2]
            # On convertit tout ce beau monde en entier
            for f in data.keys():
                data[f] = to_int_ignoring_null(data[f])
            # Si on n'a pas d'année, on met l'année en cours (plus un si la date se retrouve dans le passé)
297
            if (data["y"] == 0):
298
                today = time.localtime()[:3]
299
300
                if today[1:] > (data["m"], data["d"]):
                    data["y"] = today[0] + 1
301
302
303
                else:
                    data["y"] = today[0]
            # Si la date a été donnée à deux chiffres, il faut la passer à 4
304
305
306
            if data["y"] < 1000:
                if data["y"] > settings.YEAR_1900s_OVER:
                    data["y"] += 1900
307
                else:
308
                    data["y"] += 2000
309
310
            # On le renvoie sous forme de datetime.date
            try:
311
                return datetime.date(data["y"], data["m"], data["d"])
312
            except Exception as exc:
313
                raise forms.ValidationError(_(u'"%s" ne peut pas être transformé en date : "%s"') % (raw_value, exc))
314
315
            return data
        else:
Vincent Le gallic's avatar
Vincent Le gallic committed
316
            raise forms.ValidationError(u'"%s" ne peut pas être transformé en date (essaye le format JJ/MM/AAAA)' % (raw_value))
317
318
319
320
321
322

class MyTimeField(forms.CharField):
    """Un champ personnalisé de détection d'heure.
       Renvoie un objet datetime.time"""
    description = u"Une heure (assez souple sur le format d'entrée)"
    
323
    def to_python(self, raw_value):
Vincent Le gallic's avatar
Vincent Le gallic committed
324
        """Conversion de la valeur texte en objet python."""
325
        raw_value = super(MyTimeField, self).to_python(raw_value)
326
327
328
329
330
331
332
333
        result = time_matcher.match(raw_value)
        if result:
            data = result.groupdict()
            # On convertit tout ce beau monde en entier
            for f in data.keys():
                data[f] = to_int_ignoring_null(data[f])
            # On le renvoie sous forme de datetime.time
            try:
334
                return datetime.time(data["H"], data["M"], data["S"])
335
            except Exception as exc:
336
                raise forms.ValidationError(u'"%s" ne peut pas être transformé en heure : "%s"' % (raw_value, exc))
337
        else:
Vincent Le gallic's avatar
Vincent Le gallic committed
338
            raise forms.ValidationError(u'"%s" ne peut pas être transformé en heure (essaye le format HH:MM:SS)' % (raw_value))
339

340
class ActiviteForm(BootstrapForm):
341
    """Formulaire pour créer ou modifer une activité"""
342
    id = forms.IntegerField(required=False, widget=forms.HiddenInput)
343
344
345
346
347
348
349
350
351
352
    titre = forms.CharField(label=_(u"Titre"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    signature = forms.CharField(label=_(u"Signature"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    description = forms.CharField(label=_(u"Description"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    debut_date = MyDateField(label=_(u"Date de début"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    debut_time = MyTimeField(label=_(u"Heure de début"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    fin_date = MyDateField(label=_(u"Date de fin"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    fin_time = MyTimeField(label=_(u"Heure de fin"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    lieu = forms.CharField(label=_(u"Lieu"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    liste = forms.BooleanField(label=_(u"Liste d'invités"), required=False)
    listeimprimee = forms.BooleanField(label=_(u"Liste imprimée"), required=False)
353
354
355
    def clean(self):
        """Récupère les données et fusionne les dates et les heures
           pour finalement donner une chaîne %Y-%m-%d %H:%M:%S"""
356
        out = super(ActiviteForm, self).clean()
357
        # à ce stade, out ne contient pas forcément tous les champs si certains ont été fournis vides
358
        if not set(["debut_date", "debut_time", "fin_date", "fin_time"]).issubset(out.keys()):
359
            return out
360
361
        dd, dt, fd, ft = out["debut_date"], out["debut_time"], out["fin_date"], out["fin_time"]
        debut, fin = datetime.datetime(dd.year, dd.month, dd.day, dt.hour, dt.minute, dt.second), datetime.datetime(fd.year, fd.month, fd.day, ft.hour, ft.minute, ft.second)
362
        if debut>fin:
363
            raise forms.ValidationError(_(u"La méthode DeLorean_TimeTravel() n'est pas encore implémentée dans la Note Kfet 2015, merci de réessayer plus tard ou bien de te résoudre à faire commencer ton activité avant qu'elle ne soit finie."))
364
        else:
365
366
            del out["debut_date"], out["debut_time"], out["fin_date"], out["fin_time"]
            out["debut"], out["fin"] = debut.strftime("%Y-%m-%d %H:%M:%S"), fin.strftime("%Y-%m-%d %H:%M:%S")
367
368
369
            return out
    
    def __init__(self, *args, **kwargs):
370
371
372
373
374
        """Pour initialiser le formulaire, on doit bidouiller un peu pour avoir
           debut_date, debut_time, fin_date et fin_time dans initial.
           
           Gère aussi les subtilités du champ listeimprimee.
           """
375
376
        if 'initial' in kwargs.keys():
            champs = kwargs['initial'].keys()
377
            for champ_date in ["debut", "fin"]:
378
                if champ_date in champs:
379
                    date = time.strptime(kwargs['initial'][champ_date],"%Y-%m-%d %H:%M:%S")
380
                    # On décompose le timestamp en date/heure
381
                    kwargs['initial'][champ_date + "_date"], kwargs['initial'][champ_date + '_time'] = time.strftime("%d/%m/%Y %H:%M:%S", date).split(" ")
382
                    del kwargs['initial'][champ_date]
383
384
385
386
387
388
        # Il faut aussi faire en sorte que le champ "liste imprimée" ne soit pas toujours disponible
        if 'listeimprimee' in kwargs.keys():
            keeplisteimprimee = kwargs['listeimprimee']
            del kwargs['listeimprimee']
        else:
            keeplisteimprimee = True
389
        BootstrapForm.__init__(self, *args, **kwargs)
390
391
        if not keeplisteimprimee:
            del self.fields['listeimprimee']
392

393
class BoutonForm(BootstrapForm):
394
    """Formulaire pour créer ou modifier un bouton"""
395
396
    label = forms.CharField(label=_(u"Label"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    montant = FrenchFloatField(label=_(u"Montant"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
397
398
    destinataire = forms.ChoiceField()
    categorie = forms.ChoiceField()
399
400
401
    affiche = forms.BooleanField(label=_(u"Afficher"), required=False, initial=True)
    description = forms.CharField(label=_(u"Description"), widget=forms.TextInput(attrs={"autocomplete" : "off"}), required=False)
    consigne = forms.BooleanField(label=_(u"Consigné"), required=False, initial=False)
402
403
404
405
    def __init__(self, *args, **kwargs):
        # Pour initialiser le formulaire, on veut que le solde soit passé en euros
        if 'initial' in kwargs.keys():
            if 'montant' in kwargs['initial'].keys():
406
                kwargs['initial']['montant'] = kwargs['initial']['montant'] / 100.0
407
        BootstrapForm.__init__(self, *args, **kwargs)
408
    def clean(self):
Vincent Le gallic's avatar
Vincent Le gallic committed
409
410
        """Vérifie que le bouton n'est pas absurde :
           montant >= 0, destinataire et montant ``int``."""
411
        out = super(BoutonForm, self).clean()
412
        if out.has_key("montant") and out["montant"] < 0:
413
            raise forms.ValidationError(_(u"Le montant d'un bouton doit être positif"))
414
415
416
        try:
            out['destinataire'] = int(out['destinataire'])
        except:
417
            raise forms.ValidationError(_(u"Je sais pas comme tu t'es débrouillé pour pas me filer un entier dans le champ destinataire, et je veux pas le savoir."))
418
        try:
419
            out['montant'] = int(round(100 * out['montant']))
420
        except:
421
            raise forms.ValidationError(_(u"Précise un montant correct."))
Vincent Le gallic's avatar
Vincent Le gallic committed
422
423
        return out

424
class PhotoForm(forms.Form):
425
    """Formulaire d'envoi de photo"""
426
    photo = forms.FileField(label=_(u"Fichier photo"))
427
428
    def clean(self):
        """On n'autorise pas les photos trop grosses."""
429
        out = super(PhotoForm, self).clean()
430
431
432
433
        if out.has_key("photo"):
            photo = out["photo"]
            if photo != None and photo.size > settings.MAX_PHOTO_SIZE:
                raise forms.ValidationError(u"Photo trop volumineuse (%s octets), maximum %s" % (photo.size, settings.MAX_PHOTO_SIZE))
434
        return out
435

436
class MoneyForm(BootstrapForm):
437
    """Classe de base pour les formulaires qui parlent d'argent."""
438
439
    montant = FrenchFloatField(label=_(u"Montant"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    commentaire = forms.CharField(label=_(u"Commentaire"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
440
    def clean(self):
Vincent Le gallic's avatar
Vincent Le gallic committed
441
        """Gère les conversions en centimes"""
442
        out = super(MoneyForm, self).clean()
443
        if out.has_key("montant") and type(out["montant"]) == float:
444
            out["montant"] = int(round(100 * out["montant"]))
445
446
        else:
            out["montant"] = 0
447
        return out
448

449
450
451
class CreditRetraitForm(MoneyForm):
    """Formulaire pour effectuer un crédit ou un retrait."""
    idbde = forms.IntegerField(widget=forms.HiddenInput)
452
453
454
455
456
457
458
459
460
461
    type = forms.ChoiceField(label=_(u"Type de paiement"),
                             choices=[("", _(u"<Choisis un mode de paiement>")),
                                      ("especes", _(u"Espèces")),
                                      ("cb", _(u"Carte bancaire")),
                                      ("cheque", _(u"Chèque")),
                                      ("virement", _(u"Virement bancaire")),]
                             )
    nom = forms.CharField(label=_(u"Nom"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    prenom = forms.CharField(label=_(u"Prénom"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    banque = forms.CharField(label=_(u"Banque"), required=False)
462
    def clean(self):
Vincent Le gallic's avatar
Vincent Le gallic committed
463
464
        """Gère le cas où le formulaire a été envoyé sans idbde (l'utilisateur n'a pas cliqué sur une note)
           en levant une erreur spécifique qui sera rattrappée lors de la gestion AJAJ."""
465
        out = super(CreditRetraitForm, self).clean()
466
467
        if out.get("idbde") is None:
            raise CreditRetraitWithoutIdbde
468
        return out
469
470

class TransfertForm(MoneyForm):
Vincent Le gallic's avatar
Vincent Le gallic committed
471
472
    """Formulaire pour effectuer un transfert d'argent.
       Également utilisé pour les dons."""
473
    commentaire = forms.CharField(label=_(u"Motif"), required=False, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
474

475

476
class DeleteCompteForm(BootstrapForm):
477
    """Formulaire de confirmation de suppression de compte."""
478
    anonymiser = forms.BooleanField(label=_(u"Anonymiser le compte (nom, prénom, mail, adresse, …)"), required=False)
479
480
481


DEPTS = (
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
    ('', _(u'<Choisir un département>')),
    ('A0', _(u'Informatique (A0)')),
    ('A1', _(u'Mathématiques (A1)')),
    ('A2', _(u'Physique (A2)')),
    ('A\'2', _(u'Physique Appliquée (A\'2)')),
    ('A"2', _(u'Chimie (A"2)')),
    ('A3', _(u'Biologie (A3)')),
    ('B1234', _(u'SAPHIRE (B1234)')),
    ('B1', _(u'Mécanique (B1)')),
    ('B2', _(u'Génie Civil (B2)')),
    ('B3', _(u'Génie Mécanique (B3)')),
    ('B4', _(u'EEA (B4)')),
    ('C', _(u'Design (C)')),
    ('D2', _(u'Eco-Gestion (D2)')),
    ('D3', _(u'Sciences sociales (D3)')),
    ('E', _(u'Anglais (E)')),
    ('EXT', _(u'Autre (EXT)')),
499
500
501
)

MODES_PAIEMENTS = (
502
503
504
    ('note', _(u'Note')),
    ('soge', _(u'Société Générale')),
    ('virement', _(u'Virement Bancaire (sous conditions*)')),
505
506
507
508
509
510
)

ROLES = (
    ('libre', 'Electron libre'),
    ('chef_equipe', 'Chef d\'équipe (3A+)'),
    ('chef_bus', 'Chef de bus (2A sobre)'),
Hamza Dely's avatar
Hamza Dely committed
511
    ('staff', 'Staff WEI'),
512
513
514
    ('inconnu', 'Je ne sais pas'),
)

515
516
BUS = (
    ('Je ne sais pas', 'Je ne sais pas'),
517
518
519
520
521
    ('[Car]vengers'  , '[Car]vengers'),
    ('Les Pirates du [Car]ibéen', 'Les Pirates du [Car]ibéen'),
    ('[Car] Toutatis !', '[Car] Toutatis !'),
    ('Chewbac[car]', 'Chewbac[car]'),
    ('Ex[car]libur', 'Ex[car]libur'),
522
    ('Zinedine Zi[Van]', 'Zinedine Zi[van]'),
523
    ('[Car]field', '[Car]field'),
524
    ('Staff', 'Staff'),
pollion's avatar
pollion committed
525
526
 )

527

528
class WEImonInscriptionForm(BootstrapForm):
529
530
531
    """
        Questionnaire WEI pour les 2A+
    """
532
533
534
535
536
537
538
539
540
541
    tel = forms.CharField(max_length=10, required=True, label=_(u"Téléphone"))
    urgence_nom = forms.CharField(max_length=255, required=True, label=_(u"Nom de la personne à contacter en cas d'urgence"))
    urgence_tel = forms.CharField(max_length=10, required=True, label=_(u"Téléphone de la personne à contacter en cas d'urgence"))
    annee = forms.IntegerField(min_value=1, required=True, label=_(u"Années à l'ENS (année du WEI à venir incluse)"))
    dept = forms.ChoiceField(choices=DEPTS, required=True, initial='', label=_(u"Département d'enseignement"))
    paiement = forms.ChoiceField(choices=MODES_PAIEMENTS, required=True, initial='note', label=_(u"Mode de paiement"))
    normalien = forms.BooleanField(required=False, initial=False, label=_(u"Normalien, Prof, Directeur de département..."))
    conge = forms.BooleanField(required=False, initial=False, label=_(u"Si normalien : CIR, CST, Joker ..."))
    pbsante = forms.CharField(widget=forms.Textarea, required=False, label=_(u"Informations pour le staff WEI (allergies/intolérances, végétarien, problèmes de santé, ...)"))
    bus = forms.ChoiceField(choices=BUS, initial=_(u'Je ne sais pas'), required=True, label=_(u"Bus demandé"))
Antoine Bernard's avatar
Antoine Bernard committed
542
    role = forms.MultipleChoiceField(choices=ROLES, initial=[_(u'inconnu'),], required=True, label=_(u"Je voudrais faire mon WEI en tant que"), widget=forms.CheckboxSelectMultiple)
543
544
545
546
547
548
549
550

    def _is_tel_number(self, data):
        """
            Méthode permettant de vérifier qu'il s'agit bien d'un numéro
            de téléphone valide.
        """
        raw_tel = data
        AUTH_PREFIXES = ['01', '02', '03', '04', '05', '06', '07', ]
551
552
553
554
        DELIMITERS = [" ", ".", "-", "_"]

        # Retrait des délimiteurs
        for delimiter in DELIMITERS:
555
            raw_tel = raw_tel.replace(delimiter, "")
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

        # On commence par vérifier que le numéro a la bonne taille
        if len(raw_tel) != 10:
            raise forms.ValidationError("Ton numéro de téléphone ne fait pas 10 chiffres")

        # Ensuite on vérifie le préfixe
        if not raw_tel[0:2] in AUTH_PREFIXES:
                raise forms.ValidationError("Ton numéro de téléphone est invalide")

        # Ensuite on vérifie qu'il s'agit bien d'un entier
        try:
            cleaned_tel = int(raw_tel)
        except ValueError:
            raise forms.ValidationError("Ton numéro de téléphone est invalide")

        return raw_tel

    def clean_tel(self):
        """
            Méthode effectuant les vérifications sur la validité du champ tel
            entré par l'utilisateur.
        """
        return self._is_tel_number(self.cleaned_data["tel"])

    def clean_urgence_tel(self):
        """
            Méthode effectuant les vérifications sur la validité du champ urgence_tel
            entré par l'utilisateur.
        """
        return self._is_tel_number(self.cleaned_data["urgence_tel"])

    def clean_role(self):
        """
            Méthode procédant à la validation du champ role, et le transformant en
            chaine de caractères afin de pouvoir être stocké dans la base de données.
        """

        return ";".join(self.cleaned_data["role"])

595
596
597
598
599
600
601
602
603
604
605
606
    def clean_conge(self):
        """
            Méthode désactivant le champ conge si normalien n'est pas coché.
        """
        val_norm = self.cleaned_data["normalien"]
        val_conge = self.cleaned_data["conge"]

        if val_norm == True:
            return val_conge
        else:
            return False

607
608
609
610
611
612
613
    def clean(self):
        """
            Vérifie que si le rôle 'staff' est demandé, alors le pseudo-bus
            staff est assigné de force.
        """
        cleaned_data = super(WEImonInscriptionForm, self).clean()

614
615
616
        if 'role' not in cleaned_data:
            raise forms.ValidationError('Tu n\'as pas précisé quel rôle tu voulais')

617
618
619
620
621
        if 'staff' in cleaned_data['role']:
            cleaned_data['bus'] = 'Staff'

        return cleaned_data

622

623
class WEIVieuxForm(BootstrapForm):
624
625
626
    """
        Questionnaire WEI pour les 2A+
    """
627
    pseudo = forms.CharField(max_length=255, required=True, label=_("Nom de note"))
628
629
630
631
    tel = forms.CharField(max_length=10, required=True, label=_(u"Téléphone"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    mail = forms.EmailField(max_length=254, required=True, label=_(u"Email"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    urgence_nom = forms.CharField(max_length=255, required=True, label=_(u"Nom de la personne à contacter en cas d'urgence"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    urgence_tel = forms.CharField(max_length=10, required=True, label=_(u"Téléphone de la personne à contacter en cas d'urgence"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
632
633
634
635
636
    annee = forms.IntegerField(min_value=0, required=True, label=_(u"Années à l'ENS (année du WEI à venir incluse)"))
    dept = forms.ChoiceField(choices=DEPTS, required=True, initial='', label=_(u"Département d'enseignement"))
    paiement = forms.ChoiceField(choices=MODES_PAIEMENTS, required=True, label=_(u"Mode de paiement"))
    normalien = forms.BooleanField(required=False, initial=False, label=_(u"Normalien, Prof, Directeur de département..."))
    conge = forms.BooleanField(required=False, initial=False, label=_(u"Si normalien : CIR, CST ..."))
637
    pbsante = forms.CharField(widget=forms.Textarea(attrs={"autocomplete" : "off"}), required=False, label=_(u"Informations pour le staff WEI (allergies/intolérances, végétarien, problèmes de santé, ...)"))
638
639
    bus = forms.ChoiceField(choices=BUS, initial=_(u'Je ne sais pas'), required=True, label=_(u"Bus demandé"))
    role = forms.MultipleChoiceField(choices=ROLES, initial=[_(u'inconnu'),], required=True, label=_(u"Je voudrais faire mon WEI en tant que"), widget=forms.CheckboxSelectMultiple)
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685

    def _is_tel_number(self, data):
        """
            Méthode permettant de vérifier qu'il s'agit bien d'un numéro
            de téléphone valide.
        """
        raw_tel = data
        AUTH_PREFIXES = ['01', '02', '03', '04', '05', '06', '07', ]

        # On commence par vérifier que le numéro a la bonne taille
        if len(raw_tel) != 10:
            raise forms.ValidationError("Ton numéro de téléphone ne fait pas 10 chiffres")

        # Ensuite on vérifie le préfixe
        if not raw_tel[0:2] in AUTH_PREFIXES:
                raise forms.ValidationError("Ton numéro de téléphone est invalide")

        # Ensuite on vérifie qu'il s'agit bien d'un entier
        try:
            cleaned_tel = int(raw_tel)
        except ValueError:
            raise forms.ValidationError("Ton numéro de téléphone est invalide")

        return raw_tel

    def clean_tel(self):
        """
            Méthode effectuant les vérifications sur la validité du champ tel
            entré par l'utilisateur.
        """
        return self._is_tel_number(self.cleaned_data["tel"])

    def clean_urgence_tel(self):
        """
            Méthode effectuant les vérifications sur la validité du champ urgence_tel
            entré par l'utilisateur.
        """
        return self._is_tel_number(self.cleaned_data["urgence_tel"])

    def clean_role(self):
        """
            Méthode procédant à la validation du champ role, et le transformant en
            chaine de caractères afin de pouvoir être stocké dans la base de données.
        """

        return ";".join(self.cleaned_data["role"])
686

687
688
689
690
691
692
693
    def clean(self):
        """
            Vérifie que si le rôle 'staff' est demandé, alors le pseudo-bus
            staff est assigné de force.
        """
        cleaned_data = super(WEIVieuxForm, self).clean()

694
695
696
        if 'role' not in cleaned_data:
            raise forms.ValidationError('Tu n\'as pas précisé quel rôle tu voulais')

697
698
699
700
701
702
        if 'staff' in cleaned_data['role']:
            cleaned_data['bus'] = 'Staff'

        return cleaned_data


703
class WEIVieuxChangeForm(WEIVieuxForm):
704
    bus = forms.ChoiceField(choices=BUS, initial=_(u'Je ne sais pas'), required=True, label=_(u"Bus demandé"))
705
706
707

Q_RADIO = [(i,i) for i in range(1,6)]

708
Q_MOTS = (
Maxime Bombar's avatar
Maxime Bombar committed
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
    ('0', _(u'Incognito')),
    ('1', _(u'Cape ou pas Cape')),
    ('2', _(u'Infatigable')),
    ('3', _(u'Tipiak')),
    ('4', _(u'Raspoutine')),
    ('5', _(u'Baie Des Cochons')),
    ('6', _(u'Licorne')),
    ('7', _(u'Soubassophone')),
    ('8', _(u' C\'est pas faux')),
    ('9', _(u'Tise')),
    ('10', _(u'Pas réflechir')),
    ('11', _(u'souillards')),
    ('12', _(u'canapé')),
    ('13', _(u'poulpe')),
    ('14', _(u'procrastination')),
    ('15', _(u'troll')),
    ('16', _(u'Garfield')),
    ('17', _(u'ricard')),
    ('18', _(u'Problèmes')),
    ('19', _(u'apéro')),
    ('20', _(u'colo')),
    ('21', _(u'banquet')),
731
732
)

733
class WEI1AForm(BootstrapForm):
734
735
736
    """
        Formulaire d'inscription au WEI pour 1A
    """
Antoine Bernard's avatar
Antoine Bernard committed
737
    nom = forms.CharField(max_length=255, label=_(u"Nom"))
Antoine Bernard's avatar
Antoine Bernard committed
738
    prenom = forms.CharField(max_length=255, label=_(u"Prénom"))
739
    genre = forms.ChoiceField(label=_(u"Genre"), choices=[('', ''),
740
                                                        ('M', _(u'Masculin')),
741
742
                                                        ('F', _(u'Féminin')),
                                                        ('N', _(u'Non-binaire')),])
Vincent Le gallic's avatar
Vincent Le gallic committed
743
    adresse = forms.CharField(max_length=510, widget=forms.Textarea, label=_(u"Adresse"))
Antoine Bernard's avatar
Antoine Bernard committed
744
    mail = forms.EmailField(label=_(u"Adresse e-mail"))
745
    ml_evenements = forms.BooleanField(label=_(u"Inscription à la liste de diffusion pour être au courant des évènements du campus (1 mail/semaine)"), required=False)
746
    normalien = forms.BooleanField(label=_(u"Rémunéré(e) ?"), required=False)
747
748
749
    tel = forms.RegexField(max_length=15, regex='^\+?[0-9]{,15}$', label=_(u"Téléphone"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    urgence_nom = forms.CharField(max_length=255, label=_(u"Personne à contacter en cas d'urgence"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    urgence_tel = forms.RegexField(max_length=15, regex='^\+?[0-9]{,15}', label=_(u"Numéro à contacter en cas d'urgence"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
750
751
752
753
    dept = forms.ChoiceField(choices=DEPTS, label=_(u"Département d'enseignement envisagé"))
    note = forms.CharField(max_length=510, label=_(u"Nom de note"))
    infos = forms.CharField(max_length=510, widget=forms.Textarea, label=_(u"Infos importantes (Allergies, intolérances, -18ans, végétarien, problèmes de santé ...)"), required=False)
    soge = forms.BooleanField(required=False, label=_(u"Paiement du WEI avec la Société Générale ?"))
754
    #: Champs appartenant au questionnaire
755
    QUESTIONS  = ["q_soirees", "q_alcools", "q_encadrement", "q_groupe", "q_sociable", "q_chants", "q_boire", "q_assos", "q_suiveur", "q_activites", "q_personnes", "q_conquetes", "q_mots", "petit_mot"]
756
757
    GENERALE  = ["q_soirees", "q_alcools", "q_encadrement", "q_groupe", "q_sociable", "q_chants",]
    WEI  = ["q_boire", "q_assos", "q_suiveur", "q_activites", "q_personnes", "q_conquetes",]
758
    MOTS = ["q_mots", "petit_mot"] # ouh, pour petit_mot, c'est un kludge de présentation. kludge-ception !
759

Lev-Arcady Sellem's avatar
Lev-Arcady Sellem committed
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
    q_soirees = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"J'aime bien aller en soirée"), help_text={'label_1' :_(u"Pas du tout"), 'label_5' : _(u"Énormément")})
    q_alcools = forms.ChoiceField(choices=Q_RADIO, label=_(u"En soirée, je bois de l'alcool"), help_text={'label_1' :_(u"Pas du tout"), 'label_5' : _(u"Beaucoup")}, widget=forms.RadioSelect())
    q_encadrement = forms.ChoiceField(choices=Q_RADIO, label=_(u"J'aime bien me sentir encadré"), help_text={'label_1' :_(u"Libre comme l'air"), 'label_5' : _(u"Je préfère me sentir bien entouré en sécurité")}, widget=forms.RadioSelect())
    q_groupe = forms.ChoiceField(choices=Q_RADIO, label=_(u"J’aime bien être en groupe"), help_text={'label_1' :_(u"La solitude vaut mieux que la mauvaise compagnie"), 'label_5' : _(u"Plus on est, plus on rit")}, widget=forms.RadioSelect())
    q_sociable = forms.ChoiceField(choices=Q_RADIO, label=_(u"Je vais facilement vers les autres"), help_text={'label_1' :_(u"Si on ne m'incite pas, je n'y vais pas"), 'label_5' : _(u"Je suis le plus sociable que je connaisse")}, widget=forms.RadioSelect())
    q_chants = forms.ChoiceField(choices=Q_RADIO, label=_(u"Les chants"), help_text={'label_1' :_(u"J'ai la migraine"), 'label_5' : _(u"Je suis toujours celui qui crie le plus fort")}, widget=forms.RadioSelect())

    q_boire = forms.ChoiceField(choices=Q_RADIO, label=_(u"Boire"), help_text={'label_1' :_(u"Non"), 'label_5' : _(u"Oui")}, widget=forms.RadioSelect())
    q_assos = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"Découvrir la vie associative du campus"), help_text={'label_1' :_(u"Non"), 'label_5' : _(u"Oui")})
    q_activites = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"Pour faire des activités"), help_text={'label_1' :_(u"Non"), 'label_5' : _(u"Oui")})
    q_conquetes = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"Pour flirter"), help_text={'label_1' :_(u"Non"), 'label_5' : _(u"Oui")})
    q_personnes = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"Pour rencontrer de nouvelles personnes"), help_text={'label_1' :_(u"Non"), 'label_5' : _(u"Oui")})
    q_suiveur = forms.ChoiceField(choices=Q_RADIO, widget=forms.RadioSelect(), label=_(u"Enfin, je vais au WEI"), help_text={'label_1' :_(u"Parce que tout le monde y va…"), 'label_5' : _(u"J'en rêve depuis des mois !")})

    q_mots = forms.MultipleChoiceField(choices=Q_MOTS, widget=widgets.CheckboxSelectMultiple(), label=_(u"Parmi ces mots, ceux qui te représentent le plus sont"))
775
    
776
777
    petit_mot = forms.CharField(max_length=510, widget=forms.Textarea, label=_(u"Un dernier petit mot, juste pour l'orga WEI ? (facultatif)"), required=False)

778
779
780
781
782
783
784
785
786
787
788
789
    INTRO_QUESTIONNAIRE = _(u"""
Cher(e) première année, te voici devant un questionnaire qui n’est pas là pour te juger,
te dissuader ni t’imposer une ambiance, mais pour faire en sorte que tu passes le meilleur
week-end d’intégration possible. En effet, nous essayons d’adapter les ambiances en fonction
des personnalités de chacun d’entre vous.
La sincérité de tes réponses est donc de la plus grande importance.
De plus, les réponses à ce questionnaire ne seront en aucun cas divulguées.""")

    OUTRO_QUESTIONNAIRE = _(u"""
Merci beaucoup d’avoir pris le temps de répondre.
Si tu as des inquiétudes ou des questions au sujet du week-end d’intégration,
n’hésite pas à nous en faire part.
Maxime Bombar's avatar
Maxime Bombar committed
790
Si tu souhaites le faire de manière anonyme tu peux envoyer un mail à <b>weiensc2017@gmail.com</b>.
791
792
Durant toute la durée du WEI n’hésite pas à venir discuter avec tes chefs d’équipes et/ou
le BDE si tu as des problèmes ou des questions.""")
793

794
795
796
797
798
799
800
801
    def clean_infos(self):
        data = self.cleaned_data['infos']

        if data is None:
            data = ''

        return data

802
803
        return ';'.join(data)

804
805
    def clean_q_mots(self):
        data = self.cleaned_data['q_mots']
806
807
        if len(data) != 3:
            raise forms.ValidationError(_(u"Choisis *3* mots !"))
808
809

        return ';'.join(data)
810

811

812
813
814
815
class WEIAdminForm(BootstrapForm):
    """
        Formulaire pour la modification des paramètres du WEI
    """
816
817
818
819
820
821
822
823
    wei_name = forms.CharField(max_length=1024, label=_(u"Nom du WEI"), required=True)
    wei_begin = forms.DateField(label=_(u"Date de début"), required=True)
    wei_end = forms.DateField(label=_(u"Date de fin"), required=True)
    wei_1a_available = forms.BooleanField(label=_(u"Inscriptions 1A ouvertes"), required=False)
    wei_vieux_available = forms.BooleanField(label=_(u"Inscriptions 2A+ ouvertes"), required=False)
    wei_contact = forms.EmailField(max_length=254, label=_(u"Adresse de contact"), required=True)
    prix_wei_normalien = forms.FloatField(label=_(u"Prix WEI normalien"), required=True)
    prix_wei_non_normalien = forms.FloatField(label=_(u"Prix WEI non normalien"), required=True)
824
825
826
827
828
829
830
831
832
833
834
835

    def clean_wei_begin(self):
        data = self.cleaned_data["wei_begin"]
        data = str(data)

        return data

    def clean_wei_end(self):
        data = self.cleaned_data["wei_end"]
        data = str(data)

        return data
836

837
838
839
840
841
842
843
844
845
846
847
848
    def clean_prix_wei_normalien(self):
        data = self.cleaned_data["prix_wei_normalien"]
        data = int(data*100)

        return data

    def clean_prix_wei_non_normalien(self):
        data = self.cleaned_data["prix_wei_non_normalien"]
        data = int(data*100)

        return data

849
class GenericDateTreasury(BootstrapForm):
850
    '''Un forms avec date et heure pour les requêtes SQL'''
851
852
    debut_date = MyDateField(label=_(u"Date de début"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    fin_date = MyDateField(label=_(u"Date de fin"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
853

854
class AjoutRemise(BootstrapForm):
855
856
    """ Un forms avant pour corriger avant d'ajouter un transaction
        à une remise. """
857
858
859
860
    nom = forms.CharField(max_length=255, required=True, label=_(u"Nom de l'émetteur"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    prenom = forms.CharField(max_length=255, required=True, label=_(u"Prénom de l'émetteur"))
    banque = forms.CharField(max_length=255, required=True, label=_(u"Banque émettrice du chéquier"))
    montant = FrenchFloatField(min_value=0, required=True, label=_(u"Montant du chèque"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
861
    #idbde_beneficiaire = forms.IntegerField(required=False, widget=forms.HiddenInput)
862
    idremise = forms.ChoiceField(label =_(u"Remise"))
863

864
865
866
867
868
869
870
871
872
873
874
875
    def __init__(self, *args, **kwargs):
        # Pour initialiser le formulaire, on veut que le solde soit passé en euros
        if 'initial' in kwargs.keys():
            if 'montant' in kwargs['initial'].keys():
                kwargs['initial']['montant'] = kwargs['initial']['montant'] / 100.0
        forms.Form.__init__(self, *args, **kwargs)

    def clean(self) :
        """Vérifie que le chèque n'est pas absurde :
           montant >= 0, et montant ``int``."""
        out = super(AjoutRemise, self).clean()
        if out.has_key("montant") and out["montant"] < 0:
876
            raise forms.ValidationError(_(u"Le montant d'un chèque doit être positif ou nul."))
877
878
879
        try:
            out['montant'] = int(round(100 * out['montant']))
        except:
880
            raise forms.ValidationError(_(u"Précise un montant correct."))
881

882
883
884
885
        """Convertit l'idremise en ``int``"""
        if out.has_key("idremise"):
            out['idremise'] = int(out['idremise'])

886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
_latex_escape = {
	'&' : r'\&',
	'%':  r'\%',
	'$':  r'\$',
	'#':  r'\#',
	'_':  r'\_',
	'{':  r'\{',
	'}':  r'\}',
	'[':  r'\[',
	']':  r'\]',
	'~':  r'\textasciitilde',
	'\\': r'\textbackslash',
	}

def escape_latex(s):
901
    return "".join(_latex_escape.get(c, c) for c in s)
902

903
class FactureForm(BootstrapForm):
904
    """ Formulaire de création de facture"""
905
    nom = forms.CharField(max_length=255, required=True, label=_(u"Nom du client ou Raison sociale"), widget=forms.TextInput(attrs={'placeholder' : _(u"Mr. Dupont")}))
906
907
    adresse = forms.CharField(max_length=255,
                              required=True,
908
909
                              label=_(u"Adresse du client ou Domiciliation"),
                              widget=forms.Textarea(attrs={'placeholder' : _(u"Chambre A123B, Etage 1  CROUS de Créteil                   68 rue Camille Desmoulins 94230 CACHAN"),
910
911
912
913
                                                           'rows' : 5,
                                                           'style' : 'resize:none;'}))
    objet = forms.CharField(max_length=255,
                            required=True,
914
915
                            label=_(u"Objet"),
                            widget=forms.TextInput(attrs={'placeholder' : _(u"Paiement Pot Design")}))
916
    description = forms.CharField(max_length=510,
917
918
                                  label=_(u"Description"),
                                  widget=forms.Textarea(attrs={'placeholder' : _(u'Cette facture concerne le paiement des boissons et de la nourriture de la soirée du 31 février 2015.'),
919
                                                               'style' : 'resize:none;'}))
920
    id_facture = forms.IntegerField(label=_(u"Facture n°"), widget=forms.TextInput(attrs={"autocomplete" : "off"}))
921
922
923
924
925

    def clean(self):
        """ Formate les champs adresse et description
            pour le rendu dans le LaTeX."""
        out = super(FactureForm, self).clean()
926
927
	out["objet"] = escape_latex(out["objet"])
	out["nom"] = escape_latex(out["nom"])
928
929
930
931
932
933
        if out.has_key("adresse"):
            out["adresse"] = out["adresse"].strip().split('\n')
        if out.has_key("description"):
            out["description"] = out["description"].strip().split('\n')
        return out

934
class ProduitForm(BootstrapForm):
935
936
937
938
939
940
941
942
    """
        Formulaire pour un produit

        Un produit se compose :
        * designation = ``str``
        * quantite = <decimal>
        * prixunitare = <decimal>
    """
943
944
945
    designation = forms.CharField(max_length=255, label=_(u"Désignation"))
    quantite = forms.DecimalField(label=_(u"Quantité"), localize = True, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
    prixunitaire = forms.DecimalField(label=_(u"Prix unitaire"), localize = True, widget=forms.TextInput(attrs={"autocomplete" : "off"}))
946

947
    def __init__(self, *args, **kwargs):
948
949
        super(ProduitForm, self).__init__(*args, **kwargs)
        self.empty_permitted = False
950

951
952
953
954
955
    def clean(self):
        """Vérifie que le produit n'est pas absurde :
           quantite > 0 et prixunitaire >= 0."""
        out = super(ProduitForm, self).clean()
        if out.has_key("quantite") and out["quantite"] <= 0: