premier jet pour l'intgration des factures la base de gestion du crans

darcs-hash:20060610211036-4ec08-dc1e583c484f17ad06dee3f2b33fd135782bf416.gz
This commit is contained in:
chove 2006-06-10 23:10:36 +02:00
parent d3da8dc087
commit 589e9bf4d0

View file

@ -258,7 +258,8 @@ class CransLdap:
'machineFixe': auto_search_machines_champs,
'machineWifi': auto_search_machines_champs,
'machineCrans': auto_search_machines_champs,
'borneWifi': auto_search_machines_champs }
'borneWifi': auto_search_machines_champs,
'facture' : [] }
# Champs de recherche pour la recherche manuelle (en plus de la recherche auto)
non_auto_search_machines_champs = \
@ -278,7 +279,8 @@ class CransLdap:
'machineCrans': non_auto_search_machines_champs + ['prise'],
'borneWifi': non_auto_search_machines_champs + \
['prise', 'puissance', 'canal', 'hotspot', 'positionBorne', 'nvram'],
'machineWifi': non_auto_search_machines_champs + ['ipsec'] }
'machineWifi': non_auto_search_machines_champs + ['ipsec'],
'facture': ['fid']}
# tous les champs de recherche
search_champs = {}
@ -291,7 +293,8 @@ class CransLdap:
'machineFixe': 2,
'machineWifi': 2,
'machineCrans': 2,
'borneWifi': 2 }
'borneWifi': 2,
'facture': 2}
def __init__(self, readonly=False):
self.connect(readonly)
@ -550,6 +553,9 @@ class CransLdap:
# On récupère la bonne classe
nom_classe = (entry[1].get('objectClass') or ['none'])[0]
nom_classe = nom_classe[0].upper() + nom_classe[1:]
classe = eval(nom_classe)
# On crée l'objet
return classe(entry, mode, self.conn)
try:
classe = eval(nom_classe)
# On crée l'objet
@ -1012,6 +1018,9 @@ class BaseClasseCrans(CransLdap):
# Construction de l'historique
if not self._init_data:
if self.idn=='fid':
modif = 'création'
else:
modif = 'inscription'
else:
### ON NE TOUCHE PAS A SELF.MODIFS, IL EST UTILISÉ PLUS LOIN !!!!!!!
@ -1127,7 +1136,11 @@ class BaseClasseCrans(CransLdap):
r = r[0].split(',')[0]
if r[:4] != '%s=' % self.idn: continue
vidns.append(int(r[4:]))
# On prend le premier libre
if self.idn=='fid':
# Pour une facture on prend un nouveau numéro
vidn = max(vidns)+1
else:
# Sinon on prend le premier libre
while vidn in vidns:
vidn += 1
@ -1350,6 +1363,18 @@ class BaseProprietaire(BaseClasseCrans):
else:
return []
def factures(self):
""" Retourne les factures (instances) appartenant à la classe """
# Le champ id n'est pas initialisé lorsque le proprio est en cours
# de création
if self.id():
res = []
for r in self.conn.search_s('%s=%s,%s' % (self.idn, self.id(), self.base_dn), 1, Facture.filtre_idn):
res.append(self.make(r, self._modifiable))
return res
else:
return []
def solde(self, operation=None, comment=None):
""" Retourne ou modifie le solde d'un propriétaire
operation doit être un nombre positif ou négatif
@ -2643,7 +2668,6 @@ class Machine(BaseClasseCrans):
ret += coul(u'Clef IPsec de la machine : %s\n' % self.ipsec(), 'cyan')
self.services_to_restart('conf_wifi_ng')
# Reconfiguration firewalls et dhcps
if reconf_ip:
self.services_to_restart('macip', reconf_ip)
@ -2667,7 +2691,7 @@ class Machine(BaseClasseCrans):
# Reconfiguration clients wifi ?
if isinstance(self, MachineWifi) or isinstance(self, BorneWifi) \
and ('ipHostNumber' in self.modifs or 'host' in self.modifs or 'macAddress' in self.modifs or 'nvram' in self.modifs or 'hotspot' in self.modifs):
and ('ipHostNumber' in self.modifs or 'host' in self.modifs or 'macAddress' in self.modifs):
self.services_to_restart('conf_wifi_ng')
# Regénération blackliste nécessaire ?
@ -2976,6 +3000,314 @@ class BorneWifi(Machine):
self._set('nvram', current)
return new
class Facture(BaseClasseCrans):
""" Classe de définition d'une facture """
objectClass = 'facture'
idn = 'fid'
filtre_idn = 'objectClass=facture'
def __init__(self, parent_or_tuple, mode='', conn=None):
"""
parent_or_tuple est :
* soit une instance d'une classe pouvant posséder une facture
(Adherent, Club), la nouvelle facture lui sera alors associée.
* soit directement le tuple définissant une facture (tel que
retourné par les fonctions de recherche ldap)
Pour l'édition d'une facture, mode devra être égal à 'w'
Attention, si mode='w' mais si l'objet est déja locké il n'y a
pas d'erreur, vérifier l'obtention du lock grâce à la valeur de
_modifiable (si ='w' c'est bon)
conn est une instance de la classe de connexion à la base LDAP
"""
# Initialisation de la connexion
self.conn = conn
if not self.conn:
self.connect()
self.modifs = {}
t = parent_or_tuple.__class__
if t == tuple:
# Initialisation avec données fournies
self.dn = parent_or_tuple[0]
if mode == 'w':
try:
self.lock(self.idn, self.id())
self._modifiable = 'w'
except EnvironmentError , c:
self._modifiable = 0
else:
self._modifiable = 0
# Utile pour construire l'instruction LDAP de modif
self._init_data = parent_or_tuple[1].copy()
self._data = parent_or_tuple[1]
# Propriéraire inconnu mais ce n'est pas grave
self.__proprietaire = None
elif t in [Adherent, Club] and mode != 'w':
# Facture vide
self.__proprietaire = parent_or_tuple
self.dn = parent_or_tuple.dn
self._data = {'objectClass': [self.objectClass], 'modePaiement':['paypal']}
self._init_data = {}
self._modifiable = 'w'
else:
raise TypeError(u'Arguments invalides')
def numero(self):
""" Retourne le numéro de facture """
fid = self._data.get('fid',[None])[0]
if fid == None:
raise NotImplementedError, u'Il faut enregistrer une facture pour connaitre son numero'
return fid
def proprietaire(self):
"""
retroune le propriétaire de la facture (classe Adherent ou Club)
"""
# si la facture est en mode w mais pas le proprio, on tente de prendre
# le proprio en w
if self.__proprietaire and self.__proprietaire._modifiable != self._modifiable:
self.__proprietaire = None
# récupère le proprio si ce n'est pas encore fait
if not self.__proprietaire:
res = self.conn.search_s(','.join(self.dn.split(',')[1:]), 0)
if 'adherent' in res[0][1]['objectClass']:
self.__proprietaire = Adherent(res[0], self._modifiable, self.conn)
elif 'club' in res[0][1]['objectClass']:
self.__proprietaire = Club(res[0], self._modifiable, self.conn)
else:
raise ValueError, u'Propriétaire inconnu'
return self.__proprietaire
def modePaiement(self, new=None):
"""
Définit ou retourne le mode de paiement.
Le mode de paiement doit être une chaine de caractère
"""
# modification du mode de paiement
if new != None:
if self.recuPaiement():
raise ValueError, u'Facture déja payée'
if not self._modifiable:
raise NotImplementedError, "La facture n'est pas modifiable"
if new not in ['liquide','cheque','paypal']:
raise ValueError, u'Mode de paiement non accepté'
self._set('modePaiement', [new])
return decode(self._data.get('modePaiement', [None])[0])
def recuPaiement(self, new=None):
"""
Définit ou retourne qui a recu le paiement
"""
# on vérifie que la facture n'est pas déja payéee
if new and self._data.get('recuPaiement', []):
raise ValueError, u'Facture déja payée'
# modification de la valeur
if new != None:
# on vérifie que la facture est modifiable
if not self._modifiable and new:
raise NotImplementedError, "La facture n'est pas modifiable"
# on crédite les articles, si c'est pas possible, la metode
# levera une exeption
self._crediter()
# ajout des frais à la liste d'articles
self.ajoute(self._frais())
# modifie la base ldap
self._set("recuPaiement",[new])
# renvoie la valeur trouvée dans la base
return self._data.get("recuPaiement",[None])[0]
def _del_recu_paiement(self):
""" Pour test """
self._set("recuPaiement",[])
def _crediter(self):
"""
Credite les articles à son propriétaire
"""
# si la facture n'existe pas encore, on la sauve pour générer un numéro
if not self._data.has_key('fid'):
self.save()
# on vérifie que le propriétaire est modifiable
if not self.proprietaire()._modifiable:
raise SystemError, u"Impossible de créditer les articles, le proprietaire n'est pas modifiable"
# on crédite les articles
for art in self._articles():
print art
# solde impression
if art["code"] == "SOLDE":
print 'coucou'
proprio = self.proprietaire()
proprio.solde(operation=art['nombre']*art["pu"], comment="Facture n°%s : %s" % (self.numero(),art['designation']))
proprio.save()
def _frais(self):
"""
Retourne une liste d'articles correspondants aux divers frais
"""
arts = []
# aucun frais pour une facture payée, ils sont intégrés aux articles
if self.recuPaiement():
return []
# frais de paiement par paypal
if self.modePaiement() == 'paypal':
# 25 centimes pour le paiement paypal
s = 0.25
# et on ajoute 3.5% du montant
for art in self._articles():
s += 0.035 * art['nombre'] * art['pu']
# ajoute à la liste d'articles de frais
arts.append( {'code':'FRAIS','designation':'Frais de tansaction PayPal','nombre':1,'pu':round(s,2)} )
return arts
def _articles(self, arts = None):
""" Retourne ou modifie la liste des articles de la base """
# modifie la liste des articles
if arts != None:
self._set('article',['%s~~%s~~%s~~%s' % (art['code'],art['designation'],str(art['nombre']),str(art['pu'])) for art in arts])
# charge la liste des articles
arts = []
for art in self._data.get("article",[]):
art = art.split('~~')
art = { 'code' : art[0],
'designation' : art[1],
'nombre' : float(art[2]),
'pu' : float(art[3]) }
arts.append(art)
return arts
def ajoute(self, ajoute):
""" Ajoute un/des article(s) à la facture
ajoute est un article ou une liste d'articles
"""
# on ne eut pas modifier une facture payée
if self.recuPaiement():
raise ValueError, u'On ne peut pas modifier une facture payée'
# charge la liste des articles
arts = self._articles()
# ajoute les articles
if type(ajoute)==dict:
ajoute = [ajoute]
if type(ajoute)==list:
for art in ajoute:
if '~~' in ' '.join([str(x) for x in art.values()]):
raise ValueError, u'Ne pas mettre de ~~ dans les champs'
arts.append(art)
# enregistre la nouvelle liste
self._articles(arts)
def supprime(self, supprime):
""" Supprime un/des article(s) à la facture
arts est un article ou une liste d'articles
"""
# on ne eut pas modifier une facture payée
if self.recuPaiement():
raise ValueError, u'On ne peut pas modifier une facture payée'
# charge la liste des articles
arts = self._articles()
# on supprime les anciens articles
if type(supprime)==dict:
supprime = [supprime]
if type(supprime)==list:
for art in supprime:
arts.remove(art)
# enregistre la nouvelle liste
self._articles(arts)
def articles(self):
"""
Retourne la liste des articles.
ajoute et supprime sont :
un article ou
une liste d'articles
Un article est un dictionnaire de la forme :
{ 'code' : string,
'designation' : string,
'nombre' : int/float,
'pu' : int/float }
"""
return self._articles() + self._frais()
def total(self):
"""
Calcule le total de la facture, frais compris
"""
s = 0
for art in self.articles():
s += art['nombre'] * art['pu']
return s
def urlPaypal(self):
"""
Retourne l'url paypal pour le paiement de cette facture
"""
url = "https://www.paypal.com/cgi-bin/webscr?cmd=_cart"
url += "&upload=1"
url += "&business=paypal@crans.org"
url += "&currency_code=EUR"
url += "&no_shipping=1"
#url += "&address_override=1"
url += "&no_note=1"
url += "&return=http://factures.crans.org/return"
url += "&cancel_return=http://factures.crans.org/cancel"
url += "&invoice=12345" # num de facture
url += "&item_name_1=coucou"
url += "&amount_1=12"
url += "&quantity_1=2"
return url
def save(self):
"""
Enregistre la facture dans la base LDAP
Retourne une chaîne indiquant les opération effectuées.
"""
# Enregistrement
self._save()
# Remise à zéro
self.modifs = {}
# Message de sortie
return coul(u"Facture n°%s enregistrée avec succès." % self.numero(), 'vert')
def delete(self, comment=''):
""" Suppression de la facture """
self.__proprietaire = None
self._delete(self.dn, comment)
class _FakeProprio(CransLdap):
""" Définitions de base d'un propriétaire virtuel """