[admin/controle_tresorier] plus d'options pour controle_tresorier

options pour changer le critère de tri.

darcs-hash:20081210181938-af139-cebdbfb780ecd7448025504a42046080da4a5e85.gz
This commit is contained in:
Jeremie Dimino 2008-12-10 19:19:38 +01:00
parent bc9a6118cc
commit 4aba28c1a6

View file

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