
Ignore-this: 3e3d76242fcd7250d97409abb5b53fdb darcs-hash:20090328124206-bd074-d5a2a44d0daf538ece093e91ce6deb5407128e24.gz
328 lines
12 KiB
Python
328 lines
12 KiB
Python
#!/usr/bin/python
|
|
# -*- mode: python; coding: utf-8 -*-
|
|
#
|
|
# stats_cableurs.py
|
|
# -----------------
|
|
#
|
|
# Copyright (C) 2008, 2009 François Bobot <bobot@crans.org>,
|
|
# Jeremie Dimino <jeremie@dimino.org>,
|
|
# Michel Blockelet <blockelet@crans.org>,
|
|
# Antoine Durand-Gasselin <adg@crans.org>
|
|
#
|
|
# 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)
|