diff --git a/admin/controle_tresorier.py b/admin/controle_tresorier.py index 3cb609bb..ae2d3508 100755 --- a/admin/controle_tresorier.py +++ b/admin/controle_tresorier.py @@ -8,12 +8,16 @@ u"""Ce script permet au tr les câbleurs n'ont pas encore rendus. Utilisations possibles : - * %(prog)s {paiement|carte|list} [--debug ] - * %(prog)s mail [--debug ] + * %(prog)s OPTIONS {paiement|carte|list} + * %(prog)s OPTIONS mail -L'unique option est : - --debug envoyer tous les mails à l' indiquée, plutôt +Les options sont: + -d, --debug envoyer tous les mails à l' indiquée, plutôt qu'aux vrais destinataires + -h, --help affiche ce message + -t, --tri trier suivant ce champ. Les champs possibles sont: + id, nom, cableur ou date. Le défaut est ``nom'' + -i, --inverse trier par ordre inverse Les commandes sont : * paiement contrôle interactif des nouvelles (ré-)adhésions @@ -23,6 +27,7 @@ Les commandes sont : login est dans la , 'bureau' désignant le mail récapitulatif envoyé à bureau ; si la liste est vide tous les mails nécessaires seront envoyés + * help affiche ce message Le modèle du mail envoyé aux câbleurs est lu sur l'entrée standard (typiquement via une redirection). Les trois premières lignes doivent être : @@ -35,7 +40,7 @@ sera remplac Le mail récapitulatif envoyé à bureau est immuable.""" -import sys, os, re +import sys, os, re, getopt sys.path.append('/usr/scripts/gestion') # Fonctions d'affichage @@ -62,20 +67,14 @@ if u'Tresorier' not in cableur.droits(): from socket import gethostname debug = False +# Le champ sur lequel on veut trier (id, nom, cableur, date) +trier_par = "nom" +tri_inverse = False + if gethostname().split(".")[0] == 'egon': debug = 'glondu@crans.org' ann_scol = 2004 -if __name__ == '__main__': - if len(sys.argv) > 3 and sys.argv[-2] == '--debug': - debug = sys.argv[-1] - sys.argv.pop() - sys.argv.pop() - -if debug: - cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug) - - def _controle_interactif_adherents(liste, quoi): """ Contrôle interactif des adhérents de la liste (quoi = p ou c). @@ -86,13 +85,13 @@ def _controle_interactif_adherents(liste, quoi): restant = len(liste) if restant == 0: return 0, 0 - + cprint(u'\nContrôle %s des adhérents' % explicite, 'cyan') cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).") cprint(u"Une autre réponse entraîne l'interruption du processus.") cprint(u"Le format est [nb_restant] Nom, Prénom (aid).") cprint(u"") - + nb = 0 for a in liste: ok = prompt(u'[%3d] %s, %s (%s) ?' @@ -121,7 +120,7 @@ def _controle_interactif_clubs(liste): restant = len(liste) if restant == 0: return 0, 0 - + cprint(u'\nContrôle de la charte des clubs', 'cyan') cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n'.") cprint(u"Une autre réponse entraîne l'interruption du processus.") @@ -146,7 +145,7 @@ def _controle_interactif_clubs(liste): break return nb, len(liste)-nb - + def controle_interactif(quoi): """ @@ -155,14 +154,14 @@ def controle_interactif(quoi): if quoi not in 'pc': raise ValueError todo_list = db.search('%s=%d&controle!=*%s*' % ({'p': 'paiement', 'c': 'carteEtudiant'}[quoi], ann_scol, quoi)) - + # Tri de la liste des adhérents selon nom, prénom # Ça peut se faire plus facilement en Python 2.4 avec l'argument key todo_list['adherent'].sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom()))) # Traitement des adhérents oka, noka = _controle_interactif_adherents(todo_list['adherent'], quoi) - + if quoi == 'p': # Tri de la liste des clubs todo_list['club'].sort(lambda x, y: cmp(x.nom(), y.nom())) @@ -187,11 +186,19 @@ def formater_pour_cableur(liste): lignes = [] total = 0 liste.sort(lambda x, y: cmp(x[1].nom(), y[1].nom())) - + for date, a in liste: lignes.append([a.id(), a.Nom(), date]) total += 1 + if trier_par == 'id': + lignes.sort(key = lambda ligne: int(ligne[0])) + else: + champ = {'nom' : 1, 'cableur' : 1, 'date' : 2}[trier_par] + lignes.sort(key = lambda ligne: ligne[champ]) + + if tri_inverse: lignes.reverse() + return tableau(lignes, titre = [u'id', u'Nom', u'Date Heure'], largeur = [6, 40, 18], @@ -205,7 +212,7 @@ def formater_pour_bureau(dico): """ lignes = [] total = 0 - + liste = dico.keys() liste.sort() for cableur in liste: @@ -213,6 +220,14 @@ def formater_pour_bureau(dico): lignes.append([a.id(), a.Nom(), cableur, date]) total += 1 + if trier_par == 'id': + lignes.sort(key = lambda ligne: int(ligne[0])) + else: + champ = {'nom' : 1, 'cableur' : 2, 'date' : 3}[trier_par] + lignes.sort(key = lambda ligne: ligne[champ]) + + if tri_inverse: lignes.reverse() + return tableau(lignes, titre = [u'id', u'Nom', u'Câbleur', u'Date'], largeur = [6, 40, 18, 18], @@ -229,12 +244,12 @@ def qui(historique, quoi): cableur = ('_inconnu_', '_inconnu_') champ = re.compile(quoi) - + for ligne in historique: if champ.search(ligne) or 'inscription' in ligne: matched = regexp.search(ligne) if matched: cableur = matched.group(1), matched.group(2) - + return cableur @@ -244,12 +259,12 @@ def chercher_cableurs(liste, quoi): désigne le champ qui sera recherché dans l'historique. """ resultat = {} - + for a in liste: date, cableur = qui(a.historique(), quoi) if not resultat.has_key(cableur): resultat[cableur] = [] resultat[cableur].append((date, a)) - + return resultat @@ -258,17 +273,17 @@ from email_tools import send_email, parse_mail_template # Mise en application du mémorable cours de Fred sur les objets :-) class ControleMailer: - + def __init__(self): # Recherche des câbleurs possédant des cotisations/chartes todo_list = db.search('paiement=%d&controle!=*p*' % ann_scol) self._paiements = chercher_cableurs(todo_list['adherent'], r'(paiement|controle.*\+k)') self._chartes = chercher_cableurs(todo_list['club'], 'paiement') - + # Recherche des câbleurs possédant des cartes d'étudiant todo_list = db.search('carteEtudiant=%d&controle!=*c*' % ann_scol) self._cartes = chercher_cableurs(todo_list['adherent'], 'carteEtudiant') - + # Récupère tous les câbleurs qui doivent quelque chose cableurs = {} for a in self._paiements.keys(): @@ -285,36 +300,36 @@ class ControleMailer: else: self._sender = u'%s <%s@crans.org>' % (cableur.Nom(), cableur.canonical_alias() or cableur.mail()) - + # Se connecte au serveur SMTP par défaut from smtplib import SMTP self._server = SMTP() self._server.connect() - + def __del__(self): # Termine la connexion au serveur SMTP self._server.quit() - + def recapitulatif(self): """ Renvoie le récapitulatif pour le bureau. """ msg = u'' - + if self._paiements: msg += u"Fiches d'adhésion et cotisations et/ou caution des adhérents :\n" msg += formater_pour_bureau(self._paiements) + '\n\n' - + if self._chartes: msg += u"Chartes signées des clubs :\n" msg += formater_pour_bureau(self._chartes) + '\n\n' - + if self._cartes: msg += u"Carte d'étudiant des adhérents :\n" msg += formater_pour_bureau(self._cartes) + '\n\n' - + return msg.strip() - + def mail_bureau(self): """ Envoie le mail récapitulatif à bureau (s'il y a qqch à envoyer). @@ -331,7 +346,7 @@ class ControleMailer: return coul(u'Mail envoyé à bureau avec succès !', 'vert') else: return coul(u'Tout est à jour, aucun mail envoyé.', 'vert') - + def mail_cableurs(self, subject, body, liste=None): """ Envoie un mail aux câbleurs concernés qui figurent dans la liste. @@ -342,22 +357,22 @@ class ControleMailer: nb = 0 if liste == None: liste = self._cableurs - + for c in liste: msg = u'' - + if self._paiements.has_key(c): msg += u"Fiches d'adhésion, cotisations et/ou caution des adhérents :\n" msg += formater_pour_cableur(self._paiements[c]) + '\n\n' - + if self._chartes.has_key(c): msg += u"Chartes signées des clubs :\n" msg += formater_pour_cableur(self._chartes[c]) + '\n\n' - + if self._cartes.has_key(c): msg += u"Carte d'étudiant des adhérents :\n" msg += formater_pour_cableur(self._cartes[c]) + '\n\n' - + if msg: msg = msg.strip() send_email(self._sender, @@ -367,7 +382,7 @@ class ControleMailer: server = self._server, debug = debug) nb += 1 - + return coul(u'%d mail(s) envoyé(s) aux câbleurs avec succès !' % nb, 'vert') @@ -380,28 +395,53 @@ def __usage(message=None): if __name__ == '__main__' : - - if len(sys.argv) <= 1: + + try: + options, arg = getopt.getopt(sys.argv[1:], 'ht:d:i', [ 'help', 'debug=', 'tri=', 'inverse' ]) + except getopt.error, msg: + __usage(unicode(msg)) + + for opt, val in options: + if opt in [ '-h', '--help' ]: + __usage() + + elif opt in [ '-d', '--debug' ]: + debug = val + cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug) + + elif opt in [ '-t', '--tri' ]: + if val in [ 'id', 'nom', 'cableur', 'date' ]: + trier_par = val + else: + __usage(u'Champ de tri invalie %s' % val) + + elif opt in [ '-i', '--inverse' ]: + tri_inverse = True + + else: + __usage("option inconnue « %s »'" % opt) + + if len(arg) == 0 or arg[0] == 'help': __usage() - - elif sys.argv[1] == 'paiement': - if len(sys.argv) != 2: + + elif arg[0] == 'paiement': + if len(arg) != 1: __usage(u'Mauvaise utilisation de paiement') controle_interactif('p') - - elif sys.argv[1] == 'carte': - if len(sys.argv) != 2: + + elif arg[0] == 'carte': + if len(arg) != 1: __usage(u'Mauvaise utilisation de carte') controle_interactif('c') - - elif sys.argv[1] == 'list': - if len(sys.argv) != 2: + + elif arg[0] == 'list': + if len(arg) != 1: __usage(u'Mauvaise utilisation de list') cprint(ControleMailer().recapitulatif(), newline=False) - - elif sys.argv[1] == 'mail': + + elif arg[0] == 'mail': mailer = ControleMailer() - cableurs = sys.argv[2:] + cableurs = arg[1:] if cableurs: bureau = False if 'bureau' in cableurs: @@ -417,15 +457,15 @@ if __name__ == '__main__' : body % u'' except TypeError: cprint(u"Le format du modèle n'est pas correct, arrêt.") - sys.exit(1) + sys.exit(1) cprint(u'Modèle OK, on envoie les mails...') cprint(mailer.mail_cableurs(subject, body, cableurs)) if bureau: cprint(mailer.mail_bureau()) - + else: - __usage(u'Commande inconnue : %s' % sys.argv[1]) - + __usage(u'Commande inconnue : %s' % arg[0]) + sys.exit(0)