#!/usr/bin/python # -*- mode: python; coding: utf-8 -*- # # stats_cableurs.py # ----------------- # # Copyright (C) 2008, 2009 François Bobot , # Jeremie Dimino , # Michel Blockelet , # Antoine Durand-Gasselin # # This file 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 file 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., 59 Temple Street #330, Boston, MA 02111-1307, USA. import sys, re, datetime, time sys.path.append("/usr/scripts/gestion/") from ldap_crans import CransLdap from affich_tools import cprint db = CransLdap() __DAYS_IN_PREVIOUS_MONTH = [datetime.timedelta(days) for days in [ 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ] ] def parse_ligne_histo(ligne): u"""Parse une ligne d'historique et renvoie (['dd', 'mm', 'yyyy'], ['date', 'heure', 'who', 'what'])""" champ = ligne.replace(',', '').replace(': ', '').split(' ') sdate = champ[0].split('/') date = datetime.date(int(sdate[2]), int(sdate[1]), int(sdate[0])) return date, champ def parse_historique(truc): u"""Parse l'historique""" return [ parse_ligne_histo(ligne) for ligne in truc.historique() ] def dec_date(date): u"""retranche un mois à la date.""" return (date - __DAYS_IN_PREVIOUS_MONTH[date.month -1]) class StatsCableursBase: u"""Classe prototype pour afficher des stats de câbleurs.""" colonnes = [('score', u'Son score')] nbmois = 4 stats = {} def __init__(self, mois = -4): if mois > 0: # si on demande depuis 09 (septembre) , on remonte # jusqu'à septembre self.nbmois = (datetime.date.today().month + 12 - mois) % 12 else: # si on demande les stats sur 4 mois, on remonte sur 4 # mois self.nbmois = - mois # On récupère les statistiques self.get_stats() # On les affiche self.print_stats() def get_stats(self): u"""Génération dummy de statistiques""" self.stats = {} def print_stats(self): u"""Affiche pour chaque cableur les valeurs de ses différentes colonnes définies dans self.colonnes.""" stats = self.stats cableurs = stats.keys() ### Si quelqu'un trouve une manière plus élégante de faire… try: cableurs.sort(lambda x, y : cmp(stats[x]['score'], stats[y]['score']), reverse=True) except TypeError: cableurs.sort(lambda x, y : cmp(stats[x][0], stats[y][0]), reverse=True) long_max = reduce(lambda m, c : max(m, len(c)), cableurs, len('cableur')) # Titres des colonnes ligne = "%-*s" % (long_max, u'Câbleur') for typ, nom in self.colonnes: ligne += " | %s" % nom cprint(ligne) # Ligne pour délimiter ligne = ''.center(long_max, '-') for typ, nom in self.colonnes: ligne += "-+-%s" % ''.center(len(nom), '-') cprint(ligne) # Statiqtiques par câbleur for cableur in cableurs: acts = stats[cableur] ligne = "%-*s" % (long_max, cableur) for typ, nom in self.colonnes: ligne += " | %*d" % (len(nom), acts[typ]) cprint(ligne) def sort_events(self, events): u"""Split une liste d'évènements selon les mois""" sorted_events = [] since = datetime.date.replace(datetime.date.today(), day = 1) backwards = self.nbmois while backwards > 0: sorted_events.append([ ev for ev in events if ev[0] >= since ]) events = [ ev for ev in events if ev[0] < since ] backwards -= 1 since = dec_date(since) sorted_events.append(events) return sorted_events class StatsCableursMachines(StatsCableursBase): u"""Cette classe s'occupe de recenser l'activité des différents câbleurs sur les machines, ce qui représente le travail typique du câbleur en milieu d'année""" def ajoute_actions(self, machine, hist): u"""Ajoute dans hist la liste des actions effectués par chacuns des câbleurs sur la machine pendant les mois.""" for date, champ in parse_historique(machine): # on ne va pas non plus compter les actions qu'on fait sur # ses propres machines. if machine.proprietaire().compte() != champ[2]: # Il se peut qu'une personne sans les droits câbleur ait # effectué une action. try: hist[champ[2]].append( (date, champ[3]) ) except KeyError: hist[champ[2]] = [ (date, champ[3]) ] def get_stats(self): u"""Récupère les statistiques des différents câbleurs sur les différentes machines""" # La liste des câbleurs en tant qu'entité ldap, histoire de bien # faire apparaître ceux qui n'ont rien fait ldap_cableurs = db.search("droits=cableur")['adherent'] # On récupère la liste des machines all_machines = db.search('mid=*') machines = all_machines['machineFixe'] + all_machines['machineWifi'] # hists permet de répartir toutes les actions sur les différents # câbleurs. hists = {} for i in ldap_cableurs: hists[i.compte()] = [] # on récupère l'historique des machines que l'on met dans hists for becane in machines: self.ajoute_actions(becane, hists) split_hist = {} for cableur in hists.keys(): split_hist[cableur] = self.sort_events(hists[cableur]) self.stats[cableur] = [ len(i) for i in split_hist[cableur] ] score = sum (self.stats[cableur][:-1]) self.stats[cableur].insert(0, score) month = datetime.date.today() for i in range(self.nbmois): self.colonnes.append( (i + 1, "%d/%02d" % (month.month, month.year - 2000))) month = dec_date(month) self.colonnes[0] = (0, "%d last" % self.nbmois) self.colonnes.append( (self.nbmois +1, "< " + self.colonnes[-1][1]) ) if __name__ == "__main__": StatsCableursMachines() ## class StatsCableursAdherents: ## u"""Cette classe s'occupe de recenser les actions que les câbleurs ## font sur les adhérents (en fait les {,re}adhésions).""" ## ## colonnes = [('inscription', u'inscription'), ## ('reinscription', u'réinscription'), ## ('total', u'score total')] ## ## date_debut_ann_scol = time.mktime((ann_scol, 8, 1, 0, 0, 0, 0, 0, 0)) ## paiement_ann_scol = "paiement+%d" % ann_scol ## ## def donne_cableur(mois, adherent): ## u""" Cherche le cableur qui a inscrit ou réinscrit un adhérent. """ ## cableur = None ## ## # Est-ce qu'on recherche une inscription ou une reinscription? ## if adherent.dateInscription() < self.date_debut_ann_scol: ## action = 'reinscription' ## action_filtre = self.paiement_ann_scol ## else: ## action = 'inscription' ## action_filtre = 'inscription' ## ## for hist in adherent.historique(): ## # On decoupe pour avoir un truc utilisable ## champ = hist.replace(',', '').replace(': ', '').split(' ') ## # On inspecte la date ## date = champ[0].split('/') ## if int(date[1]) in mois and int(date[2]) == ann_scol: ## # Maintenant on regarde si l'action recherchee est ici ## if action_filtre in champ[3:]: ## return action, champ[2] ## ## return action, None ## ## def calcul_score(mois): ## u""" Calcul le score de tous les cableurs ayant inscrit ou ## réinscrit quelqu'un pour l'année en cours. """ ## ## liste = db.search("paiement=2008")['adherent'] ## ## score = {} ## for adherent in liste: ## action, cableur = donne_cableur(mois, adherent) ## if cableur: ## if not score.has_key(cableur): ## score[cableur] = { 'inscription': 0, ## 'reinscription': 0 } ## score[cableur][action] += 1 ## ## # On calcul le score total pour chaque cableur ## for s in score.values(): ## s['total'] = 2 * s['inscription'] + s['reinscription'] ## ## return score ## ## def classement(score={}): ## u""" Retourne la liste des câbleurs classé par score total décroisant. """ ## cableurs = score.keys() ## cableurs.sort(lambda x, y : cmp(score[x]['total'], score[y]['total']), reverse=True) ## return cableurs ## ## ## ## if __name__ == "__main__": ## nb_affiche = 10 ## mois = range(8, 11) ## if len(sys.argv) > 1: ## if sys.argv[1] == '-e': ## mois = range(8, 13) ## if len(sys.argv) > 2: ## try: ## nb_affiche = int(sys.argv[2]) ## except ValueError: ## nb_affiche = 10 ## else: ## try: ## nb_affiche = int(sys.argv[1]) ## except ValueError: ## nb_affiche = 10 ## ## if sys.argv[1] == '--efficiency': ## ActionsCableurs([(1, 2009), (2, 2009), (3, 2009)]) ## sys.exit(0) ## ## score = calcul_score(mois) ## classement = classe(score) ## ## if nb_affiche > 0: ## classement = classement[0:nb_affiche] ## ## # On cherche les noms des câbleurs parceque c'est quand même mieux ## nom_reel = {} ## for cableur in classement: ## nom_reel[cableur] = db.search('uid=%s' % cableur)['adherent'][0].Nom() ## ## # Calcul des statistiques ## total_inscription = 0 ## total_reinscription = 0 ## total = 0 ## for s in score.values(): ## total_inscription += s['inscription'] ## total_reinscription += s['reinscription'] ## total += s['total'] ## cprint(u"""Statistiques globales: ## - inscriptions: %(inscription)d ## - réinscription: %(reinscription)d ## - total: %(total)d ## ## """ % { 'inscription': total_inscription, ## 'reinscription': total_reinscription, ## 'total': total }, newline=False) ## ## # Calcul la longueur du nom le plus long ## long_max = reduce(lambda m, c : max(m, len(c)), nom_reel.values(), len('cableur')) ## ## ## # Titres des colonnes ## ligne = "%-*s" % (long_max, u'câbleur') ## for typ, nom in colonnes: ## ligne += " | %s" % nom ## cprint(ligne) ## # Ligne pour délimiter ## ligne = ''.center(long_max, '-') ## for typ, nom in colonnes: ## ligne += "-+-%s" % ''.center(len(nom), '-') ## cprint(ligne) ## # Statiqtiques par câbleur ## for cableur in classement: ## score_cableur = score[cableur] ## ligne = "%-*s" % (long_max, nom_reel[cableur]) ## for typ, nom in colonnes: ## ligne += " | %*d" % (len(nom), score_cableur[typ]) ## cprint(ligne)