2012-07-22 17:44:44 +00:00
#! /usr/bin/env python
2012-07-21 14:36:17 +00:00
#
# ------------------------------
#
# La grosse fleme de faire les comptes à chaque fois
# Maintenant c'est toi qui les fait pour moi :D
#
# ------------------------------
# ------------------------------
# Imports
# ------------------------------
2012-07-22 17:44:44 +00:00
import csv
import os
import optparse
2020-08-02 16:31:15 +00:00
from pathlib import Path
2012-07-21 14:36:17 +00:00
2012-07-22 17:44:44 +00:00
def extrait_from_file ( file_name ) :
2013-04-22 14:59:40 +00:00
"""
Extrait les informations à partir d ' un fichier
: param file_name : nom du fichier avec les comptes
2020-08-03 08:37:17 +00:00
: return : liste [ [ nom , montant , parts ] , . . . ]
2013-04-22 14:59:40 +00:00
"""
2012-07-22 17:44:44 +00:00
file = open ( file_name , " r " )
try :
reader = csv . reader ( file , delimiter = " , " )
2013-05-12 19:24:52 +00:00
r_comptes = list ( reader )
header = r_comptes . pop ( 0 ) # On récupère le premier élément (les headers)
comptes = [ ]
for c in r_comptes : # On parcourt les lignes pour typer les éléments correctement
compte = { }
for ( i , h ) in enumerate ( header ) :
if " nom " in h . lower ( ) :
compte [ " nom " ] = c [ i ]
if " montant " in h . lower ( ) :
compte [ " montant " ] = eval ( c [ i ] )
2020-08-03 08:37:17 +00:00
if " part " in h . lower ( ) :
compte [ " parts " ] = int ( c [ i ] )
2013-05-12 19:24:52 +00:00
comptes + = [ compte ]
return comptes
2012-07-22 17:44:44 +00:00
finally :
file . close ( )
2013-09-03 08:04:55 +00:00
def forfait ( compte , output = print ) :
2013-04-22 14:59:40 +00:00
"""
2020-08-03 08:37:17 +00:00
Gère le nombre de parts et affiche quelques stats
2013-04-22 14:59:40 +00:00
2020-08-03 08:37:17 +00:00
: param compte : comptes de ce que chacun a payé [ [ nom , montant , parts ] , . . . ]
2013-04-22 14:59:40 +00:00
: return : Comptes des crédits de chacun envers la communauté
"""
2013-05-12 19:24:52 +00:00
cout_total = sum ( [ c [ " montant " ] for c in compte ] )
2020-08-03 08:37:17 +00:00
output ( " Cout total: {cout_tot} " . format ( cout_tot = cout_total ) )
2012-08-14 16:30:46 +00:00
2020-08-03 08:37:17 +00:00
nbr_jour = sum ( [ c [ " parts " ] for c in compte ] )
output ( " Nombre de parts {njour} " . format ( njour = nbr_jour ) )
2012-08-14 16:30:46 +00:00
cout_jour = cout_total / nbr_jour
2020-08-03 08:37:17 +00:00
output ( " Cout de la part: {cout} " . format ( cout = round ( cout_jour , 2 ) ) )
2012-08-14 16:30:46 +00:00
2013-09-03 08:04:55 +00:00
output ( " \n " )
2012-08-14 16:30:46 +00:00
new_compte = [ ]
for pers in compte :
2020-08-03 08:37:17 +00:00
new_compte + = [ [ pers [ " nom " ] , ( pers [ " montant " ] - pers [ " parts " ] * cout_jour ) ] ]
2013-09-01 17:59:45 +00:00
2012-08-14 16:30:46 +00:00
return new_compte
2012-07-21 15:31:30 +00:00
def normalise ( compte ) :
""" Centre en 0 les comptes """
2013-05-12 19:24:52 +00:00
moyenne = sum ( [ c [ " montant " ] for c in compte ] ) / len ( compte )
2012-07-21 15:31:30 +00:00
compte_normalise = compte
2012-07-22 17:44:44 +00:00
2012-07-21 15:31:30 +00:00
for ( i , n ) in enumerate ( compte ) :
2013-05-12 19:24:52 +00:00
compte_normalise [ i ] [ " montant " ] = compte [ i ] [ " montant " ] - moyenne
2012-07-22 17:44:44 +00:00
2012-07-21 15:31:30 +00:00
return compte_normalise
2013-09-03 08:04:55 +00:00
def affiche_final ( donRec , output = print ) :
2013-04-22 14:59:40 +00:00
"""
Affiche qui donne quoi à qui à partir de la liste
: param donRec : liste avec qui doit quoi à qui [ [ qui , àqui , quoi ] . . . ]
"""
2012-07-21 16:04:15 +00:00
for g in donRec :
2013-09-03 08:04:55 +00:00
output ( " {don} donne {montant} à {rec} " . format ( don = g [ 0 ] , rec = g [ 1 ] , montant = round ( g [ 2 ] , 2 ) ) )
2012-07-21 16:04:15 +00:00
2020-08-02 16:31:15 +00:00
def join_comptes ( compte1 , compte2 ) :
"""
>> > c1 = [ [ ' pop ' , 3 ] , [ ' bab ' , - 2 ] ]
>> > c2 = [ [ ' pop ' , 1 ] , [ ' nin ' , - 3 ] ]
>> > join_comptes ( c1 , c2 )
[ ( ' nin ' , - 3 ) , ( ' pop ' , 4 ) , ( ' bab ' , - 2 ) ]
"""
c_dict1 = { k : v for k , v in compte1 }
c_dict2 = { k : v for k , v in compte2 }
joined = { k : c_dict1 . get ( k , 0 ) + c_dict2 . get ( k , 0 ) for k in set ( c_dict1 ) | set ( c_dict2 ) }
return [ ( k , v ) for k , v in joined . items ( ) ]
2012-07-21 15:31:30 +00:00
2020-08-03 08:52:14 +00:00
def tribut ( account , seuil = 0 ) :
""" Tells who owns what to who (recursive algorithm)
: param seuil : seuil à partir duquel on ne doit plus rien .
: return : liste des valeurs associées aux débits des comptes après le remboursement
"""
account . sort ( key = lambda s : s [ 1 ] )
m = account [ 0 ]
M = account [ - 1 ]
res = [ ' doneur ' , ' receveur ' , 0 ]
# Si celui qui doit le plus doit moins que le crédit que celui qui a le plus grand crédit
# Il va donc tout lui donner
if abs ( m [ 1 ] ) < = abs ( M [ 1 ] ) :
M2 = M [ 1 ] + m [ 1 ]
# print("{em} donne {em_n} à {eM} donc {em} devient {eM2}".format(em = m[0], em_n = abs(m[1]), eM = M[0] , eM2 = M2))
res = [ m [ 0 ] , M [ 0 ] , abs ( m [ 1 ] ) ]
# On enleve le minimum
account . remove ( m )
# ON change la valeur du max
account [ - 1 ] = [ M [ 0 ] , M2 ]
# Sinon il donne juste de quoi compenser
else :
m2 = m [ 1 ] + M [ 1 ]
# print("{em} donne {eM_n} à {eM} et devient {em2}".format(em = m[0] , em2 = m2 , eM = M[0], eM_n = M[1]))
res = [ m [ 0 ] , M [ 0 ] , abs ( M [ 1 ] ) ]
# On eleve le max
account . remove ( M )
# On change la valeur du min
account [ 0 ] = [ m [ 0 ] , m2 ]
# Gestion du Seuil
account = [ i for i in account if abs ( i [ 1 ] ) > = seuil ]
if ( len ( account ) > 1 ) :
#print(account)
return [ res ] + tribut ( account , seuil = seuil )
else :
return [ res ]
2012-07-21 14:36:17 +00:00
if __name__ == ' __main__ ' :
2012-07-22 17:44:44 +00:00
# Pour analyser les options qu'on lui demande
parser = optparse . OptionParser ( )
# options proposée
2020-08-03 08:37:17 +00:00
parser . add_option ( " -f " , " --file " , action = " store " , type = " string " , dest = " file_name " , help = " Analyse les comptes à partir du fichier donné en argument ou des fichiers du repertoire " )
#parser.add_option("-p","--path",action="store", type = "string", dest="pathname", help="Analyse les comptes à partir de tous les fichiers csv du repertoir (multicompte)")
2013-04-22 15:24:59 +00:00
parser . add_option ( " -e " , " --seuil " , action = " store " , type = " int " , dest = " seuil " , default = 0 , help = " Seuil à partir duquel on concidère qu ' il n ' est plus nécessaire de payer. " )
2012-07-22 17:44:44 +00:00
# Digestion
( options , args ) = parser . parse_args ( )
if options . file_name :
2020-08-03 08:37:17 +00:00
path = Path ( options . file_name )
2020-08-02 16:31:15 +00:00
assert path . exists ( )
2020-08-03 08:37:17 +00:00
if path . is_dir ( ) :
2020-08-03 08:52:14 +00:00
cred_dept = [ ]
2020-08-03 08:37:17 +00:00
for f in path . glob ( ' *.csv ' ) :
print ( f " Compte: { f . name } " )
compte = extrait_from_file ( f )
compte_normalise = forfait ( compte )
2020-08-03 08:52:14 +00:00
cred_dept = join_comptes ( cred_dept , compte_normalise )
2020-08-03 08:37:17 +00:00
else :
compte = extrait_from_file ( options . file_name )
cred_dept = forfait ( compte )
2020-08-03 08:52:14 +00:00
final = tribut ( cred_dept , options . seuil )
2020-08-02 16:31:15 +00:00
affiche_final ( final )
2012-07-21 14:36:17 +00:00
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del